From 4b7627b05f47fe5cca1ce38a890d09fabe7625f4 Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Thu, 10 Oct 2024 11:56:42 -0700 Subject: [PATCH 01/25] Start running CI on Dart 3 --- .github/workflows/dart_ci.yml | 39 ++++++++++++++++++++++++-------- tool/delete_dart_2_only_files.sh | 17 ++++++++++++++ 2 files changed, 47 insertions(+), 9 deletions(-) create mode 100644 tool/delete_dart_2_only_files.sh diff --git a/.github/workflows/dart_ci.yml b/.github/workflows/dart_ci.yml index 69b79307d..77191ba94 100644 --- a/.github/workflows/dart_ci.yml +++ b/.github/workflows/dart_ci.yml @@ -22,17 +22,24 @@ jobs: strategy: fail-fast: false matrix: - # Can't run on `dev` (Dart 3) until we're fully null-safe. - sdk: [ 2.19.6 ] + sdk: [ 2.19.6, 3.4.4, main ] steps: - uses: actions/checkout@v4 - - uses: dart-lang/setup-dart@v1 + - id: setup-dart + uses: dart-lang/setup-dart@v1 with: sdk: ${{ matrix.sdk }} - name: Print Dart SDK version run: dart --version + - name: Delete Dart-2-only files when running on Dart 3 + run: | + DART_VERSION="${{ steps.setup-dart.outputs.dart-version }}" + if [[ "$DART_VERSION" =~ ^3 ]]; then + ./tool/delete_dart_2_only_files.sh + fi + - id: install name: Install dependencies run: dart pub get @@ -102,21 +109,28 @@ jobs: strategy: fail-fast: false matrix: - # Can't run on `dev` (Dart 3) until we're fully null-safe. - sdk: [ 2.19.6 ] + sdk: [ 2.19.6, 3.4.4, main ] analyzer: # We only have one version currently, but we'll leave this CI step in place # for the next time we need to support multiple analyzer versions. - ^5.1.0 steps: - uses: actions/checkout@v4 - - uses: dart-lang/setup-dart@v1 + - id: setup-dart + uses: dart-lang/setup-dart@v1 with: sdk: ${{ matrix.sdk }} - name: Print Dart SDK version run: dart --version + - name: Delete Dart-2-only files when running on Dart 3 + run: | + DART_VERSION="${{ steps.setup-dart.outputs.dart-version }}" + if [[ "$DART_VERSION" =~ ^3 ]]; then + ./tool/delete_dart_2_only_files.sh + fi + - name: Update analyzer constraint to ${{ matrix.analyzer }} and validate `dart pub get` can resolve id: resolve run: | @@ -142,17 +156,24 @@ jobs: strategy: fail-fast: false matrix: - # Can't run on `stable` (Dart 3) until we're fully null-safe. - sdk: [ 2.19.6 ] + sdk: [ 2.19.6, 3.4.4, main ] steps: - uses: actions/checkout@v4 - - uses: dart-lang/setup-dart@v1 + - id: setup-dart + uses: dart-lang/setup-dart@v1 with: sdk: ${{ matrix.sdk }} - name: Print Dart SDK version run: dart --version + - name: Delete Dart-2-only files when running on Dart 3 + run: | + DART_VERSION="${{ steps.setup-dart.outputs.dart-version }}" + if [[ "$DART_VERSION" =~ ^3 ]]; then + (cd ../.. && ./tool/delete_dart_2_only_files.sh) + fi + - id: link name: Override over_react dependency with local path run: cd ../.. && dart pub get && dart tool/travis_link_plugin_deps.dart diff --git a/tool/delete_dart_2_only_files.sh b/tool/delete_dart_2_only_files.sh new file mode 100644 index 000000000..e64228544 --- /dev/null +++ b/tool/delete_dart_2_only_files.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +# +# This script deletes files that can only be run in Dart 2 (ones not using null-safety), +# and need to be deleted for analysis and compilation to work in Dart 3. +# + +set -e + +rm -rf test/over_react/component_declaration/non_null_safe_builder_integration_tests +rm test/over_react/component_declaration/flux_component_test/component2/unsound_flux_component_test.dart +rm test/over_react/component_declaration/flux_component_test/unsound_flux_component_test.dart +rm test/over_react_component_declaration_non_null_safe_test.dart + +rm -rf tools/analyzer_plugin/test/unit/util/non_null_safe +rm -rf tools/analyzer_plugin/test/integration/assists/non_null_safe +rm -rf tools/analyzer_plugin/test/integration/diagnostics/non_null_safe \ No newline at end of file From b57ea3581e79763221a65aa8bbfafec40a4dabab Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Thu, 10 Oct 2024 11:57:44 -0700 Subject: [PATCH 02/25] Fix permissions --- tool/delete_dart_2_only_files.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tool/delete_dart_2_only_files.sh diff --git a/tool/delete_dart_2_only_files.sh b/tool/delete_dart_2_only_files.sh old mode 100644 new mode 100755 From b9788c2d40246303dcb5a0d60438cfa3f067994f Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Thu, 10 Oct 2024 12:01:16 -0700 Subject: [PATCH 03/25] Fix formatting check --- .github/workflows/dart_ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dart_ci.yml b/.github/workflows/dart_ci.yml index 77191ba94..29886f23b 100644 --- a/.github/workflows/dart_ci.yml +++ b/.github/workflows/dart_ci.yml @@ -51,7 +51,7 @@ jobs: - name: Verify formatting run: dart run dart_dev format --check # Only run on one sdk version in case there are conflicts - if: always() && matrix.sdk != '2.19.6' && steps.install.outcome == 'success' + if: always() && matrix.sdk == '2.19.6' && steps.install.outcome == 'success' # Analyze before generated files are created to verify that component boilerplate analysis is "clean" without the need for building - name: Analyze example source (pre-build) From 36fc6467e03f09338a7809e91fdf6195b85b5661 Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Thu, 10 Oct 2024 13:11:26 -0700 Subject: [PATCH 04/25] Fix warnings in Dart 3 (except for in generated files) --- analysis_options.yaml | 2 + .../disposable_manager_proxy.dart | 4 -- lib/src/util/css_value_util.dart | 2 +- lib/src/util/prop_conversion.dart | 1 - .../component_base_test.dart | 3 +- .../over_react/util/cast_ui_factory_test.dart | 4 +- test/test_util/test_util.dart | 12 +++++ .../builder/parsing/members_test.dart | 51 +++++++++---------- 8 files changed, 43 insertions(+), 36 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 9344e1913..e5cd3e88c 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -15,6 +15,8 @@ analyzer: unused_import: warning unnecessary_import: warning unnecessary_null_comparison: warning + # To work around warning "'can_be_null_after_null_aware' isn't a recognized error code" in Dart 3 + included_file_warning: info # Workaround for https://github.com/dart-lang/sdk/issues/51087 # TODO remove once we're no longer running CI on Dart 2.18 diff --git a/lib/src/component_declaration/disposable_manager_proxy.dart b/lib/src/component_declaration/disposable_manager_proxy.dart index 819d6130e..526456815 100644 --- a/lib/src/component_declaration/disposable_manager_proxy.dart +++ b/lib/src/component_declaration/disposable_manager_proxy.dart @@ -63,7 +63,6 @@ mixin DisposableManagerProxy on react.Component implements DisposableManagerV7 { _getDisposableProxy().listenToStream(stream, onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError); - @override Disposable manageAndReturnDisposable(Disposable disposable) => _getDisposableProxy().manageAndReturnTypedDisposable(disposable); @@ -71,13 +70,11 @@ mixin DisposableManagerProxy on react.Component implements DisposableManagerV7 { Completer manageCompleter(Completer completer) => _getDisposableProxy().manageCompleter(completer); - @override void manageDisposable(Disposable disposable) => _getDisposableProxy().manageDisposable(disposable); /// DEPRECATED. Use [getManagedDisposer] instead. @Deprecated('w_common 2.0.0') - @override void manageDisposer(Disposer disposer) => _getDisposableProxy().getManagedDisposer(disposer); @@ -87,7 +84,6 @@ mixin DisposableManagerProxy on react.Component implements DisposableManagerV7 { /// DEPRECATED. Use [listenToStream] instead. @Deprecated('w_common 2.0.0') - @override void manageStreamSubscription(StreamSubscription subscription) => _getDisposableProxy().getManagedDisposer(subscription.cancel); diff --git a/lib/src/util/css_value_util.dart b/lib/src/util/css_value_util.dart index e1ff146e8..303f2f958 100644 --- a/lib/src/util/css_value_util.dart +++ b/lib/src/util/css_value_util.dart @@ -132,7 +132,7 @@ class CssValue implements Comparable { /// Returns whether this value's [number] and [unit] are equal to that of [other]. @override - bool operator ==(dynamic other) { + bool operator ==(Object other) { return identical(this, other) || (other is CssValue && number == other.number && unit == other.unit); } diff --git a/lib/src/util/prop_conversion.dart b/lib/src/util/prop_conversion.dart index 0c8054a57..1499ea2f3 100644 --- a/lib/src/util/prop_conversion.dart +++ b/lib/src/util/prop_conversion.dart @@ -1,4 +1,3 @@ -import 'package:js/js.dart'; import 'package:js/js_util.dart'; import 'package:meta/meta.dart'; import 'package:over_react/over_react.dart' show Context, Ref; diff --git a/test/over_react/component_declaration/component_base_test.dart b/test/over_react/component_declaration/component_base_test.dart index f02b4eef1..34855283a 100644 --- a/test/over_react/component_declaration/component_base_test.dart +++ b/test/over_react/component_declaration/component_base_test.dart @@ -534,8 +534,7 @@ main() { test('a Map of the wrong type throws a type error', () { final style = {'color': 'blue'}; expect(() => getTypedView({styleKey: style}).style, - // ignore: deprecated_member_use - throwsA(anyOf(isA(), isA()))); + throwsA(isATypeCastError())); }); test('null: returns null', () { diff --git a/test/over_react/util/cast_ui_factory_test.dart b/test/over_react/util/cast_ui_factory_test.dart index e3f1be72c..614ca25e8 100644 --- a/test/over_react/util/cast_ui_factory_test.dart +++ b/test/over_react/util/cast_ui_factory_test.dart @@ -18,6 +18,8 @@ library cast_ui_factory_test; import 'package:over_react/over_react.dart'; import 'package:test/test.dart'; +import '../../test_util/test_util.dart'; + part 'cast_ui_factory_test.over_react.g.dart'; main() { @@ -44,7 +46,7 @@ main() { }); test('throws an error if provided something other than a UiFactory', () { - expect(() => castUiFactory('test'), throwsA(isA())); + expect(() => castUiFactory('test'), throwsA(isATypeCastError())); }); }); } diff --git a/test/test_util/test_util.dart b/test/test_util/test_util.dart index 48b525ca0..661015157 100644 --- a/test/test_util/test_util.dart +++ b/test/test_util/test_util.dart @@ -17,6 +17,7 @@ library test_util; import 'dart:js_util'; import 'package:over_react/over_react.dart'; +import 'package:test/test.dart'; export 'package:over_react_test/over_react_test.dart' hide testJsComponentFactory; @@ -37,3 +38,14 @@ bool isDDC() { assert(assertsEnabled = true); return assertsEnabled; } + +/// A matcher that matches an error thrown when a runtime cast fails. +/// +/// This will be either +/// - a `CastError` in Dart 2 (removed in Dart 3) +/// - a [TypeError] in Dart 3 +Matcher isATypeCastError() => anyOf( + isA(), + // Use toString since CastError isn't available in Dart 3 + isA().having((o) => o.toString(), 'toString() value', contains('CastError')), + ); diff --git a/test/vm_tests/builder/parsing/members_test.dart b/test/vm_tests/builder/parsing/members_test.dart index dd3f705fd..24357463e 100644 --- a/test/vm_tests/builder/parsing/members_test.dart +++ b/test/vm_tests/builder/parsing/members_test.dart @@ -195,34 +195,31 @@ main() { }; // Loop over the deprecated lifecycle methods - legacyLifecycleMethodsMap.keys.forEach((lifecycle) => { - // Loop through every version of the boilerplate - for (final version in BoilerplateVersions.values) - { - test('$lifecycle with ${versionDescriptions[version]}', () { - // Grab the boilerplate with the deprecated lifecycle method - final componentString = getBoilerplateString( - deprecatedLifecycleMethod: lifecycle, version: version); - final members = - BoilerplateMemberHelper.parseAndReturnMembers(componentString); - final component = members.whereType().first; - final componentVersion = resolveVersion(members).version; - final file = SourceFile.fromString(componentString); - final collector = ErrorCollector.callback(file, onError: validateCallback); - - component.validate(componentVersion, collector); - - // Warnings should only be logged if the component is a Component2 - if (component.isComponent2(componentVersion)) { - expect(validateResults, [ - contains(legacyLifecycleMethodsMap[lifecycle]), - ]); - } else { - expect(validateResults, []); - } - }) - } + for (final lifecycle in legacyLifecycleMethodsMap.keys) { + // Loop through every version of the boilerplate + for (final version in BoilerplateVersions.values) { + test('$lifecycle with ${versionDescriptions[version]}', () { + // Grab the boilerplate with the deprecated lifecycle method + final componentString = getBoilerplateString(deprecatedLifecycleMethod: lifecycle, version: version); + final members = BoilerplateMemberHelper.parseAndReturnMembers(componentString); + final component = members.whereType().first; + final componentVersion = resolveVersion(members).version; + final file = SourceFile.fromString(componentString); + final collector = ErrorCollector.callback(file, onError: validateCallback); + + component.validate(componentVersion, collector); + + // Warnings should only be logged if the component is a Component2 + if (component.isComponent2(componentVersion)) { + expect(validateResults, [ + contains(legacyLifecycleMethodsMap[lifecycle]), + ]); + } else { + expect(validateResults, []); + } }); + } + } }); }); }); From 78a30042be50a61346fbe264d9fe1621f842a55b Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Thu, 10 Oct 2024 13:19:17 -0700 Subject: [PATCH 05/25] Remove test cases that produce warnings in Dart 3 --- .../null_safe_accessor_integration_test.dart | 24 ------------- .../null_safe_accessor_integration_test.dart | 22 ------------ ...ccessor_integration_test.over_react.g.dart | 36 ------------------- .../null_safe_accessor_integration_test.dart | 24 ------------- .../null_safe_accessor_integration_test.dart | 24 ------------- ...ccessor_integration_test.over_react.g.dart | 36 ------------------- 6 files changed, 166 deletions(-) diff --git a/test/over_react/component_declaration/builder_integration_tests/backwards_compatible/null_safe_accessor_integration_test.dart b/test/over_react/component_declaration/builder_integration_tests/backwards_compatible/null_safe_accessor_integration_test.dart index 9d885d654..ef60306af 100644 --- a/test/over_react/component_declaration/builder_integration_tests/backwards_compatible/null_safe_accessor_integration_test.dart +++ b/test/over_react/component_declaration/builder_integration_tests/backwards_compatible/null_safe_accessor_integration_test.dart @@ -96,13 +96,6 @@ void main() { testValue: 'test value', ); }); - test('nullable dynamic with extraneous ? syntax', () { - testPropWriteAndRead( - readProp: (p) => p.nullableDynamicWithQuestion, - writeProp: (p, value) => p.nullableDynamicWithQuestion = value, - testValue: 'test value', - ); - }); test('nullable typedef, without ? syntax', () { testPropWriteAndRead( readProp: (p) => p.nullableTypedefWithoutQuestion, @@ -171,9 +164,6 @@ void main() { test('nullable dynamic', () { expectReadPropReturnsNull((props) => props.nullableDynamic); }); - test('nullable dynamic with extraneous ? syntax', () { - expectReadPropReturnsNull((props) => props.nullableDynamicWithQuestion); - }); test('nullable typedef, without ? syntax', () { expectReadPropReturnsNull((props) => props.nullableTypedefWithoutQuestion); }); @@ -290,13 +280,6 @@ void main() { testValue: 'test value', ); }); - test('nullable dynamic with extraneous ? syntax', () { - testStateWriteAndRead( - readState: (p) => p.nullableDynamicWithQuestion, - writeState: (p, value) => p.nullableDynamicWithQuestion = value, - testValue: 'test value', - ); - }); test('nullable typedef, without ? syntax', () { testStateWriteAndRead( readState: (p) => p.nullableTypedefWithoutQuestion, @@ -365,9 +348,6 @@ void main() { test('nullable dynamic', () { expectReadStateReturnsNull((state) => state.nullableDynamic); }); - test('nullable dynamic with extraneous ? syntax', () { - expectReadStateReturnsNull((state) => state.nullableDynamicWithQuestion); - }); test('nullable typedef, without ? syntax', () { expectReadStateReturnsNull((state) => state.nullableTypedefWithoutQuestion); }); @@ -396,8 +376,6 @@ class _$NullSafeTestProps extends UiProps { String? nullable; dynamic nullableDynamic; - // ignore: unnecessary_question_mark - dynamic? nullableDynamicWithQuestion; NullableTypedef nullableTypedefWithoutQuestion; } @@ -412,8 +390,6 @@ class _$NullSafeTestState extends UiState { String? nullable; dynamic nullableDynamic; - // ignore: unnecessary_question_mark - dynamic? nullableDynamicWithQuestion; NullableTypedef nullableTypedefWithoutQuestion; } diff --git a/test/over_react/component_declaration/builder_integration_tests/component2/null_safe_accessor_integration_test.dart b/test/over_react/component_declaration/builder_integration_tests/component2/null_safe_accessor_integration_test.dart index bf78a2deb..5a0e9a13d 100644 --- a/test/over_react/component_declaration/builder_integration_tests/component2/null_safe_accessor_integration_test.dart +++ b/test/over_react/component_declaration/builder_integration_tests/component2/null_safe_accessor_integration_test.dart @@ -97,13 +97,6 @@ void main() { testValue: 'test value', ); }); - test('nullable dynamic with extraneous ? syntax', () { - testPropWriteAndRead( - readProp: (p) => p.nullableDynamicWithQuestion, - writeProp: (p, value) => p.nullableDynamicWithQuestion = value, - testValue: 'test value', - ); - }); test('nullable typedef, without ? syntax', () { testPropWriteAndRead( readProp: (p) => p.nullableTypedefWithoutQuestion, @@ -172,9 +165,6 @@ void main() { test('nullable dynamic', () { expectReadPropReturnsNull((props) => props.nullableDynamic); }); - test('nullable dynamic with extraneous ? syntax', () { - expectReadPropReturnsNull((props) => props.nullableDynamicWithQuestion); - }); test('nullable typedef, without ? syntax', () { expectReadPropReturnsNull((props) => props.nullableTypedefWithoutQuestion); }); @@ -291,13 +281,6 @@ void main() { testValue: 'test value', ); }); - test('nullable dynamic with extraneous ? syntax', () { - testStateWriteAndRead( - readState: (p) => p.nullableDynamicWithQuestion, - writeState: (p, value) => p.nullableDynamicWithQuestion = value, - testValue: 'test value', - ); - }); test('nullable typedef, without ? syntax', () { testStateWriteAndRead( readState: (p) => p.nullableTypedefWithoutQuestion, @@ -366,9 +349,6 @@ void main() { test('nullable dynamic', () { expectReadStateReturnsNull((state) => state.nullableDynamic); }); - test('nullable dynamic with extraneous ? syntax', () { - expectReadStateReturnsNull((state) => state.nullableDynamicWithQuestion); - }); test('nullable typedef, without ? syntax', () { expectReadStateReturnsNull((state) => state.nullableTypedefWithoutQuestion); }); @@ -397,7 +377,6 @@ class _$NullSafeTestProps extends UiProps { String? nullable; dynamic nullableDynamic; - dynamic? nullableDynamicWithQuestion; NullableTypedef nullableTypedefWithoutQuestion; } @@ -412,7 +391,6 @@ class _$NullSafeTestState extends UiState { String? nullable; dynamic nullableDynamic; - dynamic? nullableDynamicWithQuestion; NullableTypedef nullableTypedefWithoutQuestion; } diff --git a/test/over_react/component_declaration/builder_integration_tests/component2/null_safe_accessor_integration_test.over_react.g.dart b/test/over_react/component_declaration/builder_integration_tests/component2/null_safe_accessor_integration_test.over_react.g.dart index c5d843ac8..3a0eddcbc 100644 --- a/test/over_react/component_declaration/builder_integration_tests/component2/null_safe_accessor_integration_test.over_react.g.dart +++ b/test/over_react/component_declaration/builder_integration_tests/component2/null_safe_accessor_integration_test.over_react.g.dart @@ -111,17 +111,6 @@ abstract class _$NullSafeTestPropsAccessorsMixin set nullableDynamic(dynamic value) => props[_$key__nullableDynamic___$NullSafeTestProps] = value; - /// - @override - dynamic? get nullableDynamicWithQuestion => - (props[_$key__nullableDynamicWithQuestion___$NullSafeTestProps] ?? null) - as dynamic?; - - /// - @override - set nullableDynamicWithQuestion(dynamic? value) => - props[_$key__nullableDynamicWithQuestion___$NullSafeTestProps] = value; - /// @override NullableTypedef get nullableTypedefWithoutQuestion => @@ -166,9 +155,6 @@ abstract class _$NullSafeTestPropsAccessorsMixin PropDescriptor(_$key__nullable___$NullSafeTestProps); static const PropDescriptor _$prop__nullableDynamic___$NullSafeTestProps = PropDescriptor(_$key__nullableDynamic___$NullSafeTestProps); - static const PropDescriptor - _$prop__nullableDynamicWithQuestion___$NullSafeTestProps = - PropDescriptor(_$key__nullableDynamicWithQuestion___$NullSafeTestProps); static const PropDescriptor _$prop__nullableTypedefWithoutQuestion___$NullSafeTestProps = PropDescriptor( @@ -191,8 +177,6 @@ abstract class _$NullSafeTestPropsAccessorsMixin 'NullSafeTestProps.nullable'; static const String _$key__nullableDynamic___$NullSafeTestProps = 'NullSafeTestProps.nullableDynamic'; - static const String _$key__nullableDynamicWithQuestion___$NullSafeTestProps = - 'NullSafeTestProps.nullableDynamicWithQuestion'; static const String _$key__nullableTypedefWithoutQuestion___$NullSafeTestProps = 'NullSafeTestProps.nullableTypedefWithoutQuestion'; @@ -206,7 +190,6 @@ abstract class _$NullSafeTestPropsAccessorsMixin _$prop__requiredWithAccessorAndCustomKey___$NullSafeTestProps, _$prop__nullable___$NullSafeTestProps, _$prop__nullableDynamic___$NullSafeTestProps, - _$prop__nullableDynamicWithQuestion___$NullSafeTestProps, _$prop__nullableTypedefWithoutQuestion___$NullSafeTestProps ]; static const List $propKeys = [ @@ -218,7 +201,6 @@ abstract class _$NullSafeTestPropsAccessorsMixin _$key__requiredWithAccessorAndCustomKey___$NullSafeTestProps, _$key__nullable___$NullSafeTestProps, _$key__nullableDynamic___$NullSafeTestProps, - _$key__nullableDynamicWithQuestion___$NullSafeTestProps, _$key__nullableTypedefWithoutQuestion___$NullSafeTestProps ]; } @@ -388,17 +370,6 @@ abstract class _$NullSafeTestStateAccessorsMixin set nullableDynamic(dynamic value) => state[_$key__nullableDynamic___$NullSafeTestState] = value; - /// - @override - dynamic? get nullableDynamicWithQuestion => - (state[_$key__nullableDynamicWithQuestion___$NullSafeTestState] ?? null) - as dynamic?; - - /// - @override - set nullableDynamicWithQuestion(dynamic? value) => - state[_$key__nullableDynamicWithQuestion___$NullSafeTestState] = value; - /// @override NullableTypedef get nullableTypedefWithoutQuestion => @@ -439,9 +410,6 @@ abstract class _$NullSafeTestStateAccessorsMixin StateDescriptor(_$key__nullable___$NullSafeTestState); static const StateDescriptor _$prop__nullableDynamic___$NullSafeTestState = StateDescriptor(_$key__nullableDynamic___$NullSafeTestState); - static const StateDescriptor - _$prop__nullableDynamicWithQuestion___$NullSafeTestState = - StateDescriptor(_$key__nullableDynamicWithQuestion___$NullSafeTestState); static const StateDescriptor _$prop__nullableTypedefWithoutQuestion___$NullSafeTestState = StateDescriptor( @@ -461,8 +429,6 @@ abstract class _$NullSafeTestStateAccessorsMixin 'NullSafeTestState.nullable'; static const String _$key__nullableDynamic___$NullSafeTestState = 'NullSafeTestState.nullableDynamic'; - static const String _$key__nullableDynamicWithQuestion___$NullSafeTestState = - 'NullSafeTestState.nullableDynamicWithQuestion'; static const String _$key__nullableTypedefWithoutQuestion___$NullSafeTestState = 'NullSafeTestState.nullableTypedefWithoutQuestion'; @@ -475,7 +441,6 @@ abstract class _$NullSafeTestStateAccessorsMixin _$prop__requiredDynamic___$NullSafeTestState, _$prop__nullable___$NullSafeTestState, _$prop__nullableDynamic___$NullSafeTestState, - _$prop__nullableDynamicWithQuestion___$NullSafeTestState, _$prop__nullableTypedefWithoutQuestion___$NullSafeTestState ]; static const List $stateKeys = [ @@ -486,7 +451,6 @@ abstract class _$NullSafeTestStateAccessorsMixin _$key__requiredDynamic___$NullSafeTestState, _$key__nullable___$NullSafeTestState, _$key__nullableDynamic___$NullSafeTestState, - _$key__nullableDynamicWithQuestion___$NullSafeTestState, _$key__nullableTypedefWithoutQuestion___$NullSafeTestState ]; } diff --git a/test/over_react/component_declaration/builder_integration_tests/new_boilerplate/null_safe_accessor_integration_test.dart b/test/over_react/component_declaration/builder_integration_tests/new_boilerplate/null_safe_accessor_integration_test.dart index 67813be50..af1639758 100644 --- a/test/over_react/component_declaration/builder_integration_tests/new_boilerplate/null_safe_accessor_integration_test.dart +++ b/test/over_react/component_declaration/builder_integration_tests/new_boilerplate/null_safe_accessor_integration_test.dart @@ -96,13 +96,6 @@ void main() { testValue: 'test value', ); }); - test('nullable dynamic with extraneous ? syntax', () { - testPropWriteAndRead( - readProp: (p) => p.nullableDynamicWithQuestion, - writeProp: (p, value) => p.nullableDynamicWithQuestion = value, - testValue: 'test value', - ); - }); test('nullable typedef, without ? syntax', () { testPropWriteAndRead( readProp: (p) => p.nullableTypedefWithoutQuestion, @@ -171,9 +164,6 @@ void main() { test('nullable dynamic', () { expectReadPropReturnsNull((props) => props.nullableDynamic); }); - test('nullable dynamic with extraneous ? syntax', () { - expectReadPropReturnsNull((props) => props.nullableDynamicWithQuestion); - }); test('nullable typedef, without ? syntax', () { expectReadPropReturnsNull((props) => props.nullableTypedefWithoutQuestion); }); @@ -290,13 +280,6 @@ void main() { testValue: 'test value', ); }); - test('nullable dynamic with extraneous ? syntax', () { - testStateWriteAndRead( - readState: (p) => p.nullableDynamicWithQuestion, - writeState: (p, value) => p.nullableDynamicWithQuestion = value, - testValue: 'test value', - ); - }); test('nullable typedef, without ? syntax', () { testStateWriteAndRead( readState: (p) => p.nullableTypedefWithoutQuestion, @@ -365,9 +348,6 @@ void main() { test('nullable dynamic', () { expectReadStateReturnsNull((state) => state.nullableDynamic); }); - test('nullable dynamic with extraneous ? syntax', () { - expectReadStateReturnsNull((state) => state.nullableDynamicWithQuestion); - }); test('nullable typedef, without ? syntax', () { expectReadStateReturnsNull((state) => state.nullableTypedefWithoutQuestion); }); @@ -393,8 +373,6 @@ mixin NullSafeTestProps on UiProps { String? nullable; dynamic nullableDynamic; - // ignore: unnecessary_question_mark - dynamic? nullableDynamicWithQuestion; NullableTypedef nullableTypedefWithoutQuestion; } @@ -408,8 +386,6 @@ mixin NullSafeTestState on UiState { String? nullable; dynamic nullableDynamic; - // ignore: unnecessary_question_mark - dynamic? nullableDynamicWithQuestion; NullableTypedef nullableTypedefWithoutQuestion; } diff --git a/test/over_react/component_declaration/builder_integration_tests/null_safe_accessor_integration_test.dart b/test/over_react/component_declaration/builder_integration_tests/null_safe_accessor_integration_test.dart index 91caf6071..8bcca1f84 100644 --- a/test/over_react/component_declaration/builder_integration_tests/null_safe_accessor_integration_test.dart +++ b/test/over_react/component_declaration/builder_integration_tests/null_safe_accessor_integration_test.dart @@ -98,13 +98,6 @@ void main() { testValue: 'test value', ); }); - test('nullable dynamic with extraneous ? syntax', () { - testPropWriteAndRead( - readProp: (p) => p.nullableDynamicWithQuestion, - writeProp: (p, value) => p.nullableDynamicWithQuestion = value, - testValue: 'test value', - ); - }); test('nullable typedef, without ? syntax', () { testPropWriteAndRead( readProp: (p) => p.nullableTypedefWithoutQuestion, @@ -173,9 +166,6 @@ void main() { test('nullable dynamic', () { expectReadPropReturnsNull((props) => props.nullableDynamic); }); - test('nullable dynamic with extraneous ? syntax', () { - expectReadPropReturnsNull((props) => props.nullableDynamicWithQuestion); - }); test('nullable typedef, without ? syntax', () { expectReadPropReturnsNull((props) => props.nullableTypedefWithoutQuestion); }); @@ -292,13 +282,6 @@ void main() { testValue: 'test value', ); }); - test('nullable dynamic with extraneous ? syntax', () { - testStateWriteAndRead( - readState: (p) => p.nullableDynamicWithQuestion, - writeState: (p, value) => p.nullableDynamicWithQuestion = value, - testValue: 'test value', - ); - }); test('nullable typedef, without ? syntax', () { testStateWriteAndRead( readState: (p) => p.nullableTypedefWithoutQuestion, @@ -367,9 +350,6 @@ void main() { test('nullable dynamic', () { expectReadStateReturnsNull((state) => state.nullableDynamic); }); - test('nullable dynamic with extraneous ? syntax', () { - expectReadStateReturnsNull((state) => state.nullableDynamicWithQuestion); - }); test('nullable typedef, without ? syntax', () { expectReadStateReturnsNull((state) => state.nullableTypedefWithoutQuestion); }); @@ -398,8 +378,6 @@ class _$NullSafeTestProps extends UiProps { String? nullable; dynamic nullableDynamic; - // ignore: unnecessary_question_mark - dynamic? nullableDynamicWithQuestion; NullableTypedef nullableTypedefWithoutQuestion; } @@ -414,8 +392,6 @@ class _$NullSafeTestState extends UiState { String? nullable; dynamic nullableDynamic; - // ignore: unnecessary_question_mark - dynamic? nullableDynamicWithQuestion; NullableTypedef nullableTypedefWithoutQuestion; } diff --git a/test/over_react/component_declaration/builder_integration_tests/null_safe_accessor_integration_test.over_react.g.dart b/test/over_react/component_declaration/builder_integration_tests/null_safe_accessor_integration_test.over_react.g.dart index 8c994e01c..bb27e880c 100644 --- a/test/over_react/component_declaration/builder_integration_tests/null_safe_accessor_integration_test.over_react.g.dart +++ b/test/over_react/component_declaration/builder_integration_tests/null_safe_accessor_integration_test.over_react.g.dart @@ -111,17 +111,6 @@ abstract class _$NullSafeTestPropsAccessorsMixin set nullableDynamic(dynamic value) => props[_$key__nullableDynamic___$NullSafeTestProps] = value; - /// - @override - dynamic? get nullableDynamicWithQuestion => - (props[_$key__nullableDynamicWithQuestion___$NullSafeTestProps] ?? null) - as dynamic?; - - /// - @override - set nullableDynamicWithQuestion(dynamic? value) => - props[_$key__nullableDynamicWithQuestion___$NullSafeTestProps] = value; - /// @override NullableTypedef get nullableTypedefWithoutQuestion => @@ -166,9 +155,6 @@ abstract class _$NullSafeTestPropsAccessorsMixin PropDescriptor(_$key__nullable___$NullSafeTestProps); static const PropDescriptor _$prop__nullableDynamic___$NullSafeTestProps = PropDescriptor(_$key__nullableDynamic___$NullSafeTestProps); - static const PropDescriptor - _$prop__nullableDynamicWithQuestion___$NullSafeTestProps = - PropDescriptor(_$key__nullableDynamicWithQuestion___$NullSafeTestProps); static const PropDescriptor _$prop__nullableTypedefWithoutQuestion___$NullSafeTestProps = PropDescriptor( @@ -191,8 +177,6 @@ abstract class _$NullSafeTestPropsAccessorsMixin 'NullSafeTestProps.nullable'; static const String _$key__nullableDynamic___$NullSafeTestProps = 'NullSafeTestProps.nullableDynamic'; - static const String _$key__nullableDynamicWithQuestion___$NullSafeTestProps = - 'NullSafeTestProps.nullableDynamicWithQuestion'; static const String _$key__nullableTypedefWithoutQuestion___$NullSafeTestProps = 'NullSafeTestProps.nullableTypedefWithoutQuestion'; @@ -206,7 +190,6 @@ abstract class _$NullSafeTestPropsAccessorsMixin _$prop__requiredWithAccessorAndCustomKey___$NullSafeTestProps, _$prop__nullable___$NullSafeTestProps, _$prop__nullableDynamic___$NullSafeTestProps, - _$prop__nullableDynamicWithQuestion___$NullSafeTestProps, _$prop__nullableTypedefWithoutQuestion___$NullSafeTestProps ]; static const List $propKeys = [ @@ -218,7 +201,6 @@ abstract class _$NullSafeTestPropsAccessorsMixin _$key__requiredWithAccessorAndCustomKey___$NullSafeTestProps, _$key__nullable___$NullSafeTestProps, _$key__nullableDynamic___$NullSafeTestProps, - _$key__nullableDynamicWithQuestion___$NullSafeTestProps, _$key__nullableTypedefWithoutQuestion___$NullSafeTestProps ]; } @@ -355,17 +337,6 @@ abstract class _$NullSafeTestStateAccessorsMixin set nullableDynamic(dynamic value) => state[_$key__nullableDynamic___$NullSafeTestState] = value; - /// - @override - dynamic? get nullableDynamicWithQuestion => - (state[_$key__nullableDynamicWithQuestion___$NullSafeTestState] ?? null) - as dynamic?; - - /// - @override - set nullableDynamicWithQuestion(dynamic? value) => - state[_$key__nullableDynamicWithQuestion___$NullSafeTestState] = value; - /// @override NullableTypedef get nullableTypedefWithoutQuestion => @@ -406,9 +377,6 @@ abstract class _$NullSafeTestStateAccessorsMixin StateDescriptor(_$key__nullable___$NullSafeTestState); static const StateDescriptor _$prop__nullableDynamic___$NullSafeTestState = StateDescriptor(_$key__nullableDynamic___$NullSafeTestState); - static const StateDescriptor - _$prop__nullableDynamicWithQuestion___$NullSafeTestState = - StateDescriptor(_$key__nullableDynamicWithQuestion___$NullSafeTestState); static const StateDescriptor _$prop__nullableTypedefWithoutQuestion___$NullSafeTestState = StateDescriptor( @@ -428,8 +396,6 @@ abstract class _$NullSafeTestStateAccessorsMixin 'NullSafeTestState.nullable'; static const String _$key__nullableDynamic___$NullSafeTestState = 'NullSafeTestState.nullableDynamic'; - static const String _$key__nullableDynamicWithQuestion___$NullSafeTestState = - 'NullSafeTestState.nullableDynamicWithQuestion'; static const String _$key__nullableTypedefWithoutQuestion___$NullSafeTestState = 'NullSafeTestState.nullableTypedefWithoutQuestion'; @@ -442,7 +408,6 @@ abstract class _$NullSafeTestStateAccessorsMixin _$prop__requiredDynamic___$NullSafeTestState, _$prop__nullable___$NullSafeTestState, _$prop__nullableDynamic___$NullSafeTestState, - _$prop__nullableDynamicWithQuestion___$NullSafeTestState, _$prop__nullableTypedefWithoutQuestion___$NullSafeTestState ]; static const List $stateKeys = [ @@ -453,7 +418,6 @@ abstract class _$NullSafeTestStateAccessorsMixin _$key__requiredDynamic___$NullSafeTestState, _$key__nullable___$NullSafeTestState, _$key__nullableDynamic___$NullSafeTestState, - _$key__nullableDynamicWithQuestion___$NullSafeTestState, _$key__nullableTypedefWithoutQuestion___$NullSafeTestState ]; } From c1ad5da5a3af21d6dfa4c22f4c0ff014f98e7142 Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Thu, 10 Oct 2024 13:24:15 -0700 Subject: [PATCH 06/25] Remove unused dependencies --- pubspec.yaml | 2 -- test/over_react/component_declaration/component_base_test.dart | 1 - .../flux_component_test/component2/flux_component_test.dart | 1 - test/over_react/util/rem_util_test.dart | 1 - 4 files changed, 5 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index 07c4b28ed..e82dd9a33 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,14 +31,12 @@ dev_dependencies: build_runner: ^2.0.0 build_test: ^2.0.0 build_web_compilers: ^3.0.0 - built_value_generator: ^8.0.0 dart_dev: ^4.0.1 dependency_validator: ^3.0.0 glob: ^2.0.1 io: ^1.0.0 react_testing_library: ^3.0.1 over_react_test: ^3.0.0 - pedantic: ^1.11.1 test: ^1.20.0 workiva_analysis_options: ^1.4.0 yaml: ^3.1.0 diff --git a/test/over_react/component_declaration/component_base_test.dart b/test/over_react/component_declaration/component_base_test.dart index 34855283a..235389b65 100644 --- a/test/over_react/component_declaration/component_base_test.dart +++ b/test/over_react/component_declaration/component_base_test.dart @@ -24,7 +24,6 @@ import 'package:over_react/over_react.dart' show Dom, DummyComponent, DummyCompo import 'package:over_react/over_react.dart' as over_react; import 'package:over_react/src/component_declaration/component_base.dart'; import 'package:over_react/src/component_declaration/component_type_checking.dart'; -import 'package:pedantic/pedantic.dart'; import 'package:react/react_client.dart'; import 'package:test/test.dart'; import 'package:w_common/disposable.dart'; diff --git a/test/over_react/component_declaration/flux_component_test/component2/flux_component_test.dart b/test/over_react/component_declaration/flux_component_test/component2/flux_component_test.dart index 50401ebc8..cb9c5407f 100644 --- a/test/over_react/component_declaration/flux_component_test/component2/flux_component_test.dart +++ b/test/over_react/component_declaration/flux_component_test/component2/flux_component_test.dart @@ -20,7 +20,6 @@ import 'dart:async'; import 'dart:html'; import 'package:logging/logging.dart'; -import 'package:pedantic/pedantic.dart'; import 'package:test/test.dart'; import 'package:w_flux/w_flux.dart'; import 'package:over_react/over_react.dart'; diff --git a/test/over_react/util/rem_util_test.dart b/test/over_react/util/rem_util_test.dart index 6216984ff..121eb37ab 100644 --- a/test/over_react/util/rem_util_test.dart +++ b/test/over_react/util/rem_util_test.dart @@ -21,7 +21,6 @@ import 'dart:html'; import 'package:over_react/src/util/css_value_util.dart'; import 'package:over_react/src/util/rem_util.dart'; import 'package:over_react/src/util/test_mode.dart'; -import 'package:pedantic/pedantic.dart'; import 'package:test/test.dart'; import '../../test_util/test_util.dart'; From 50abd3fd6c2e43c4ec656241c8979cba09918be2 Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Thu, 10 Oct 2024 13:25:49 -0700 Subject: [PATCH 07/25] Widen build_web_compilers range to fix DDC compilation on Dart 3 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index e82dd9a33..897b8453c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,7 +30,7 @@ dev_dependencies: build_resolvers: ^2.0.0 build_runner: ^2.0.0 build_test: ^2.0.0 - build_web_compilers: ^3.0.0 + build_web_compilers: '>=3.2.6 <5.0.0' dart_dev: ^4.0.1 dependency_validator: ^3.0.0 glob: ^2.0.1 From ff88b627d7e52ed4d148e7283264d8c9fc9dda11 Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Thu, 10 Oct 2024 13:27:54 -0700 Subject: [PATCH 08/25] Fix Dart-2-specific import --- lib/src/util/prop_conversion.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/src/util/prop_conversion.dart b/lib/src/util/prop_conversion.dart index 1499ea2f3..effe74e17 100644 --- a/lib/src/util/prop_conversion.dart +++ b/lib/src/util/prop_conversion.dart @@ -1,3 +1,6 @@ +// This is only an unnecessary import in Dart 3; in Dart 2, we need it for allowInterop. +// ignore: unnecessary_import +import 'package:js/js.dart'; import 'package:js/js_util.dart'; import 'package:meta/meta.dart'; import 'package:over_react/over_react.dart' show Context, Ref; From d754ed81103d6c295b7d9eb636461ba2fc9b9f16 Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Thu, 10 Oct 2024 13:45:00 -0700 Subject: [PATCH 09/25] Exclude non-null-safe builder test cases in Dart 3 --- .github/workflows/dart_ci.yml | 16 ++++++++++++++-- dart_test.yaml | 2 ++ .../conditionally_null_safe_builder_test.dart | 6 +++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/.github/workflows/dart_ci.yml b/.github/workflows/dart_ci.yml index 29886f23b..7068baddc 100644 --- a/.github/workflows/dart_ci.yml +++ b/.github/workflows/dart_ci.yml @@ -88,7 +88,13 @@ jobs: - name: Run tests (VM) # Can't use build_runner (which dart_dev uses if you depend on it) to run VM tests, since we get the error: # Unable to spawn isolate: /…/build_runner_testRU6M77/.packages: Error: Problem in packages configuration file: Unexpected character - run: dart test -P vm + run: | + DART_VERSION="${{ steps.setup-dart.outputs.dart-version }}" + TEST_ARGS="" + if [[ "$DART_VERSION" =~ ^3 ]]; then + TEST_ARGS="--exclude-tags=dart-2-only" + fi + dart test -P vm "TEST_ARGS" if: always() && steps.install.outcome == 'success' && steps.build.outcome == 'success' - name: Run tests (DDC) @@ -146,7 +152,13 @@ jobs: run: dart run build_runner build --build-filter='**.dart' --delete-conflicting-outputs - name: Run builder tests - run: dart test -p vm -- test/vm_tests/builder + run: | + DART_VERSION="${{ steps.setup-dart.outputs.dart-version }}" + TEST_ARGS="" + if [[ "$DART_VERSION" =~ ^3 ]]; then + TEST_ARGS="--exclude-tags=dart-2-only" + fi + dart test -p vm -- test/vm_tests/builder analyzer_plugin: runs-on: ubuntu-latest diff --git a/dart_test.yaml b/dart_test.yaml index 7f3b0c835..096df915a 100644 --- a/dart_test.yaml +++ b/dart_test.yaml @@ -48,3 +48,5 @@ tags: # Tests that represent a case of undesirable JS interop behavior that's # either unavoidable or exists as a tradeoff for improved behavior in other cases. js-interop-tradeoff: {} + # Tests for behavior that's only valid in Dart 2, and does not apply to Dart 3. + dart-2-only: {} diff --git a/test/vm_tests/builder/conditionally_null_safe_builder_test.dart b/test/vm_tests/builder/conditionally_null_safe_builder_test.dart index 6d719b306..e2d43bbd5 100644 --- a/test/vm_tests/builder/conditionally_null_safe_builder_test.dart +++ b/test/vm_tests/builder/conditionally_null_safe_builder_test.dart @@ -19,7 +19,7 @@ import 'package:test/test.dart'; main() { group('conditionally null safe builder', () { - group('on package-level Dart version that is not null safe', () { + group('on package-level Dart language version that is not null safe', () { setUpAll(() { const nonNullSafePackagePath = 'test_fixtures/test_packages/non_null_safe'; @@ -81,9 +81,9 @@ main() { 'Using nullSafety: false. {languageVersion: 2.11, source: libraryVersionComment}')); }); }); - }); + }, tags: 'dart-2-only'); - group('on package-level Dart version that is null safe', () { + group('on package-level Dart language version that is null safe', () { setUpAll(() { const nonNullSafePackagePath = 'test_fixtures/test_packages/null_safe'; Process.runSync('dart', ['pub', 'get'], From 105f01b7df16061aea5b2b46f4ee34de6f055292 Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Thu, 10 Oct 2024 13:57:24 -0700 Subject: [PATCH 10/25] Fix test args not being passed --- .github/workflows/dart_ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dart_ci.yml b/.github/workflows/dart_ci.yml index 7068baddc..f1896beed 100644 --- a/.github/workflows/dart_ci.yml +++ b/.github/workflows/dart_ci.yml @@ -94,7 +94,7 @@ jobs: if [[ "$DART_VERSION" =~ ^3 ]]; then TEST_ARGS="--exclude-tags=dart-2-only" fi - dart test -P vm "TEST_ARGS" + dart test -P vm "$TEST_ARGS" if: always() && steps.install.outcome == 'success' && steps.build.outcome == 'success' - name: Run tests (DDC) @@ -158,7 +158,7 @@ jobs: if [[ "$DART_VERSION" =~ ^3 ]]; then TEST_ARGS="--exclude-tags=dart-2-only" fi - dart test -p vm -- test/vm_tests/builder + dart test -p vm "$TEST_ARGS" -- test/vm_tests/builder analyzer_plugin: runs-on: ubuntu-latest From 32c5b36c7a8aa63fc841c828b030418a61ff232e Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Thu, 10 Oct 2024 14:02:04 -0700 Subject: [PATCH 11/25] Suppress analysis_options include warning in Dart 3 --- tools/analyzer_plugin/analysis_options.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/analyzer_plugin/analysis_options.yaml b/tools/analyzer_plugin/analysis_options.yaml index f11db5869..9ec565946 100644 --- a/tools/analyzer_plugin/analysis_options.yaml +++ b/tools/analyzer_plugin/analysis_options.yaml @@ -17,6 +17,8 @@ analyzer: unused_import: info import_of_legacy_library_into_null_safe: warning implementation_imports: warning + # To work around warning "'can_be_null_after_null_aware' isn't a recognized error code" in Dart 3 + included_file_warning: info # ignores from v1.recommended prefer_interpolation_to_compose_strings: ignore From 9f5399517a7493b054b7f725da59753dc8ae10ae Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Thu, 10 Oct 2024 14:09:44 -0700 Subject: [PATCH 12/25] Fix empty string being passed as test arg --- .github/workflows/dart_ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dart_ci.yml b/.github/workflows/dart_ci.yml index f1896beed..b44ef740d 100644 --- a/.github/workflows/dart_ci.yml +++ b/.github/workflows/dart_ci.yml @@ -94,7 +94,7 @@ jobs: if [[ "$DART_VERSION" =~ ^3 ]]; then TEST_ARGS="--exclude-tags=dart-2-only" fi - dart test -P vm "$TEST_ARGS" + dart test -P vm $TEST_ARGS if: always() && steps.install.outcome == 'success' && steps.build.outcome == 'success' - name: Run tests (DDC) @@ -158,7 +158,7 @@ jobs: if [[ "$DART_VERSION" =~ ^3 ]]; then TEST_ARGS="--exclude-tags=dart-2-only" fi - dart test -p vm "$TEST_ARGS" -- test/vm_tests/builder + dart test -p vm $TEST_ARGS -- test/vm_tests/builder analyzer_plugin: runs-on: ubuntu-latest From 5412fef66a55b08f01e88b43ec9b06afc326bf8a Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Thu, 10 Oct 2024 14:19:06 -0700 Subject: [PATCH 13/25] Remove Dart-2-only lint config causing warning in Dart 3 --- tools/analyzer_plugin/analysis_options.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/analyzer_plugin/analysis_options.yaml b/tools/analyzer_plugin/analysis_options.yaml index 9ec565946..76e1b662d 100644 --- a/tools/analyzer_plugin/analysis_options.yaml +++ b/tools/analyzer_plugin/analysis_options.yaml @@ -15,7 +15,6 @@ analyzer: missing_return: warning # Override workiva_analysis_options upgrade to warning unused_import: info - import_of_legacy_library_into_null_safe: warning implementation_imports: warning # To work around warning "'can_be_null_after_null_aware' isn't a recognized error code" in Dart 3 included_file_warning: info From 922d5359aa4ae09eff0a6a3748d7bd88e37d300d Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Thu, 10 Oct 2024 14:19:45 -0700 Subject: [PATCH 14/25] Work around presets ignoring excluded tag args --- .github/workflows/dart_ci.yml | 8 ++++---- dart_test.yaml | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/dart_ci.yml b/.github/workflows/dart_ci.yml index b44ef740d..0ad2b65d2 100644 --- a/.github/workflows/dart_ci.yml +++ b/.github/workflows/dart_ci.yml @@ -92,9 +92,9 @@ jobs: DART_VERSION="${{ steps.setup-dart.outputs.dart-version }}" TEST_ARGS="" if [[ "$DART_VERSION" =~ ^3 ]]; then - TEST_ARGS="--exclude-tags=dart-2-only" + TEST_ARGS="--preset=no-dart-2" fi - dart test -P vm $TEST_ARGS + dart test --preset vm $TEST_ARGS if: always() && steps.install.outcome == 'success' && steps.build.outcome == 'success' - name: Run tests (DDC) @@ -156,9 +156,9 @@ jobs: DART_VERSION="${{ steps.setup-dart.outputs.dart-version }}" TEST_ARGS="" if [[ "$DART_VERSION" =~ ^3 ]]; then - TEST_ARGS="--exclude-tags=dart-2-only" + TEST_ARGS="--preset=no-dart-2" fi - dart test -p vm $TEST_ARGS -- test/vm_tests/builder + dart test --preset vm $TEST_ARGS -- test/vm_tests/builder analyzer_plugin: runs-on: ubuntu-latest diff --git a/dart_test.yaml b/dart_test.yaml index 096df915a..30e487165 100644 --- a/dart_test.yaml +++ b/dart_test.yaml @@ -12,6 +12,9 @@ presets: paths: - test/vm_tests/ + no-dart-2: + exclude_tags: dart-2-only + dartdevc: exclude_tags: no-ddc paths: From 3a6933a027afacf7c776b84280c506a04cc9cd22 Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Thu, 10 Oct 2024 14:22:26 -0700 Subject: [PATCH 15/25] Suppress comment references info --- analysis_options.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/analysis_options.yaml b/analysis_options.yaml index e5cd3e88c..5b3a623f5 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -15,6 +15,7 @@ analyzer: unused_import: warning unnecessary_import: warning unnecessary_null_comparison: warning + comment_references: info # To work around warning "'can_be_null_after_null_aware' isn't a recognized error code" in Dart 3 included_file_warning: info From 25622a5980345d726a79227fe95cc5d70a2e4315 Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Thu, 10 Oct 2024 14:26:16 -0700 Subject: [PATCH 16/25] Use Dart stable (main used by mistake) --- .github/workflows/dart_ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dart_ci.yml b/.github/workflows/dart_ci.yml index 0ad2b65d2..172404e10 100644 --- a/.github/workflows/dart_ci.yml +++ b/.github/workflows/dart_ci.yml @@ -22,7 +22,7 @@ jobs: strategy: fail-fast: false matrix: - sdk: [ 2.19.6, 3.4.4, main ] + sdk: [ 2.19.6, 3.4.4, stable ] steps: - uses: actions/checkout@v4 - id: setup-dart @@ -115,7 +115,7 @@ jobs: strategy: fail-fast: false matrix: - sdk: [ 2.19.6, 3.4.4, main ] + sdk: [ 2.19.6, 3.4.4, stable ] analyzer: # We only have one version currently, but we'll leave this CI step in place # for the next time we need to support multiple analyzer versions. @@ -168,7 +168,7 @@ jobs: strategy: fail-fast: false matrix: - sdk: [ 2.19.6, 3.4.4, main ] + sdk: [ 2.19.6, 3.4.4, stable ] steps: - uses: actions/checkout@v4 - id: setup-dart From 0331324fca4cf8985f979073fe3db20cd9fd1be7 Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Thu, 10 Oct 2024 16:21:15 -0700 Subject: [PATCH 17/25] Add timeouts, helpful for when test process hangs at end of run --- .github/workflows/dart_ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/dart_ci.yml b/.github/workflows/dart_ci.yml index 172404e10..e89f899c2 100644 --- a/.github/workflows/dart_ci.yml +++ b/.github/workflows/dart_ci.yml @@ -100,10 +100,12 @@ jobs: - name: Run tests (DDC) run: dart test --precompiled ddc_precompiled -P dartdevc if: always() && steps.install.outcome == 'success' && steps.build.outcome == 'success' + timeout-minutes: 5 - name: Run tests (dart2js) run: dart run dart_dev test --build-args="-r" -P dart2js if: always() && steps.install.outcome == 'success' && steps.build.outcome == 'success' + timeout-minutes: 5 - uses: anchore/sbom-action@v0 with: @@ -210,3 +212,4 @@ jobs: - name: Run tests run: dart run dart_dev test if: always() && steps.install.outcome == 'success' + timeout-minutes: 8 From f6719b22d9cbc6ef8fbe8b180fce2592217227d3 Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Mon, 14 Oct 2024 17:42:29 -0700 Subject: [PATCH 18/25] Work around test hanging issue --- dart_test.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dart_test.yaml b/dart_test.yaml index 30e487165..218c9cc67 100644 --- a/dart_test.yaml +++ b/dart_test.yaml @@ -4,11 +4,12 @@ platforms: - chrome - vm -# Default concurrency of 4 for unit tests, integration preset will override -concurrency: 4 +# Work around process hanging after tests finish: https://github.com/dart-lang/build/issues/3765 +concurrency: 1 presets: vm: + concurrency: 4 paths: - test/vm_tests/ From 9d1cdd2b34a1b14d5b512efe96975f837f57e110 Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Tue, 15 Oct 2024 18:38:58 -0700 Subject: [PATCH 19/25] Fix Dart 3 CI trying to run unsound test file --- tool/delete_dart_2_only_files.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tool/delete_dart_2_only_files.sh b/tool/delete_dart_2_only_files.sh index e64228544..c1f9d88c8 100755 --- a/tool/delete_dart_2_only_files.sh +++ b/tool/delete_dart_2_only_files.sh @@ -12,6 +12,14 @@ rm test/over_react/component_declaration/flux_component_test/component2/unsound_ rm test/over_react/component_declaration/flux_component_test/unsound_flux_component_test.dart rm test/over_react_component_declaration_non_null_safe_test.dart +# Remove the reference to the test file. Use a temporary file since we can't +# redirect to/from the same file in the same command. See https://github.com/koalaman/shellcheck/wiki/SC2094 +mv dart_test.yaml dart_test.yaml.old +grep over_react_component_declaration_non_null_safe_test.dart \ + --fixed-strings \ + --invert-match \ + dart_test.yaml.old > dart_test.yaml + rm -rf tools/analyzer_plugin/test/unit/util/non_null_safe rm -rf tools/analyzer_plugin/test/integration/assists/non_null_safe rm -rf tools/analyzer_plugin/test/integration/diagnostics/non_null_safe \ No newline at end of file From 35e8c9ce15236885b3b446adf6e42a274eac63db Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Tue, 15 Oct 2024 19:20:37 -0700 Subject: [PATCH 20/25] Only run SBOM action once --- .github/workflows/dart_ci.yml | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/.github/workflows/dart_ci.yml b/.github/workflows/dart_ci.yml index e89f899c2..f75192a6c 100644 --- a/.github/workflows/dart_ci.yml +++ b/.github/workflows/dart_ci.yml @@ -17,6 +17,23 @@ permissions: pull-requests: write jobs: + # Run as a separate job outside the Dart SDK matrix below, + # since we can only emit a single SBOM. + create-sbom-release-asset: + name: Create SBOM Release Asset + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: dart-lang/setup-dart@v1 + with: + sdk: 2.19.6 # This version doesn't matter so long as it resolves. + - run: dart pub get + - name: Publish SBOM to Release Assets + uses: anchore/sbom-action@v0 + with: + path: ./ + format: cyclonedx-json + build: runs-on: ubuntu-latest strategy: @@ -107,11 +124,6 @@ jobs: if: always() && steps.install.outcome == 'success' && steps.build.outcome == 'success' timeout-minutes: 5 - - uses: anchore/sbom-action@v0 - with: - path: ./ - format: cyclonedx-json - validate_analyzer: runs-on: ubuntu-latest strategy: From bfa632a7738ba3b1d29dfd6472f4c2b5e86791e8 Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Tue, 15 Oct 2024 19:22:07 -0700 Subject: [PATCH 21/25] Dial back matrix to only run on latest Dart 3 version --- .github/workflows/dart_ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dart_ci.yml b/.github/workflows/dart_ci.yml index f75192a6c..ac9326ba5 100644 --- a/.github/workflows/dart_ci.yml +++ b/.github/workflows/dart_ci.yml @@ -39,7 +39,7 @@ jobs: strategy: fail-fast: false matrix: - sdk: [ 2.19.6, 3.4.4, stable ] + sdk: [ 2.19.6, stable ] steps: - uses: actions/checkout@v4 - id: setup-dart @@ -129,7 +129,7 @@ jobs: strategy: fail-fast: false matrix: - sdk: [ 2.19.6, 3.4.4, stable ] + sdk: [ 2.19.6, stable ] analyzer: # We only have one version currently, but we'll leave this CI step in place # for the next time we need to support multiple analyzer versions. @@ -182,7 +182,7 @@ jobs: strategy: fail-fast: false matrix: - sdk: [ 2.19.6, 3.4.4, stable ] + sdk: [ 2.19.6, stable ] steps: - uses: actions/checkout@v4 - id: setup-dart From bcbb6eaa8e8a8b6a069b53389289e950534af656 Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Tue, 15 Oct 2024 19:28:33 -0700 Subject: [PATCH 22/25] Fix typo --- .github/workflows/dart_ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dart_ci.yml b/.github/workflows/dart_ci.yml index ac9326ba5..b0f10510a 100644 --- a/.github/workflows/dart_ci.yml +++ b/.github/workflows/dart_ci.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: dart-lang/setup-dart@v1 + - uses: dart-lang/setup-dart@v1 with: sdk: 2.19.6 # This version doesn't matter so long as it resolves. - run: dart pub get From 375848e4f55ab93e3dcd50992c81794aec046a82 Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Tue, 15 Oct 2024 19:29:06 -0700 Subject: [PATCH 23/25] Clean up temporary file --- tool/delete_dart_2_only_files.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tool/delete_dart_2_only_files.sh b/tool/delete_dart_2_only_files.sh index c1f9d88c8..af7122bdd 100755 --- a/tool/delete_dart_2_only_files.sh +++ b/tool/delete_dart_2_only_files.sh @@ -19,6 +19,7 @@ grep over_react_component_declaration_non_null_safe_test.dart \ --fixed-strings \ --invert-match \ dart_test.yaml.old > dart_test.yaml +rm dart_test.yaml.old rm -rf tools/analyzer_plugin/test/unit/util/non_null_safe rm -rf tools/analyzer_plugin/test/integration/assists/non_null_safe From d64668cb6f96d647f04409df1946664ccd8c1725 Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Tue, 15 Oct 2024 19:34:10 -0700 Subject: [PATCH 24/25] Officially support Dart 3 in SDK constraint --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 897b8453c..0f3e4a77d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ version: 5.4.0 description: A library for building statically-typed React UI components using Dart. homepage: https://github.com/Workiva/over_react/ environment: - sdk: '>=2.19.0 <3.0.0' + sdk: '>=2.19.0 <4.0.0' dependencies: collection: ^1.15.0 From 8df1dc0b564c9cd7021b61e8c65d764996484a44 Mon Sep 17 00:00:00 2001 From: Greg Littlefield Date: Tue, 15 Oct 2024 20:01:58 -0700 Subject: [PATCH 25/25] Fix error message assertion in Dart 3 --- test/over_react/component/lazy_test.dart | 4 ++-- test/over_react/util/prop_conversion_test.dart | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/over_react/component/lazy_test.dart b/test/over_react/component/lazy_test.dart index 46954047f..21454cbd5 100644 --- a/test/over_react/component/lazy_test.dart +++ b/test/over_react/component/lazy_test.dart @@ -320,8 +320,8 @@ sharedNestedPropConversionTests(UiFactory builder, {bool isJsCompon // DDC error message matches( RegExp(r"Expected a value of type 'Map[^']*', but got one of type '(Native|Legacy)JavaScriptObject'")), - // dart2js error message - matches(RegExp(r"type '(Unknown|Plain)JavaScriptObject' is not a subtype of type 'Map[^']*'")), + // Dart 2 dart2js, Dart 3 DDC error message + matches(RegExp(r"type '(Unknown|Plain|Legacy)JavaScriptObject' is not a subtype of type 'Map[^']*'")), )), ]); if (!isJsComponent) { diff --git a/test/over_react/util/prop_conversion_test.dart b/test/over_react/util/prop_conversion_test.dart index 13ca46d72..b53a46a07 100644 --- a/test/over_react/util/prop_conversion_test.dart +++ b/test/over_react/util/prop_conversion_test.dart @@ -1083,9 +1083,9 @@ main() { // DDC error message matches(RegExp( r"Expected a value of type 'Map[^']*', but got one of type '(Native|Legacy)JavaScriptObject'")), - // dart2js error message + // Dart 2 dart2js, Dart 3 DDC error message matches(RegExp( - r"type '(Unknown|Plain)JavaScriptObject' is not a subtype of type 'Map[^']*'")), + r"type '(Unknown|Plain|Legacy)JavaScriptObject' is not a subtype of type 'Map[^']*'")), )), ]);