From 00fe8b0abb7dd230b7275d62a7bd22ab0c804cbd Mon Sep 17 00:00:00 2001 From: Minsu Lee Date: Wed, 27 Dec 2023 14:17:58 +0900 Subject: [PATCH] feat: support late observables (#973) Co-authored-by: Pavan Podila --- mobx_codegen/CHANGELOG.md | 4 +++ mobx_codegen/lib/src/store_class_visitor.dart | 1 + mobx_codegen/lib/src/template/observable.dart | 30 +++++++++++++++---- mobx_codegen/lib/version.dart | 2 +- mobx_codegen/pubspec.yaml | 2 +- .../data/valid_late_variables_output.dart | 6 +++- mobx_codegen/test/generator_usage_test.dart | 15 ++++++++++ mobx_codegen/test/generator_usage_test.g.dart | 21 +++++++++++++ mobx_codegen/test/nested_store.g.dart | 5 +++- .../test/store_with_custom_context.g.dart | 5 +++- 10 files changed, 81 insertions(+), 10 deletions(-) diff --git a/mobx_codegen/CHANGELOG.md b/mobx_codegen/CHANGELOG.md index e9ed87352..c26419861 100644 --- a/mobx_codegen/CHANGELOG.md +++ b/mobx_codegen/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.5.0 + +- Support `late` observables by [@amondnet](https://github.com/amondnet). fix [#919](https://github.com/mobxjs/mobx.dart/issues/919) + ## 2.4.1 - Adds `useDeepEquality` for creating observables by [@amondnet](https://github.com/amondnet) diff --git a/mobx_codegen/lib/src/store_class_visitor.dart b/mobx_codegen/lib/src/store_class_visitor.dart index 17564bf73..83abf574b 100644 --- a/mobx_codegen/lib/src/store_class_visitor.dart +++ b/mobx_codegen/lib/src/store_class_visitor.dart @@ -102,6 +102,7 @@ class StoreClassVisitor extends SimpleElementVisitor { name: element.name, isPrivate: element.isPrivate, isReadOnly: _isObservableReadOnly(element), + isLate: element.isLate, equals: _getEquals(element), ); diff --git a/mobx_codegen/lib/src/template/observable.dart b/mobx_codegen/lib/src/template/observable.dart index c536c69a8..68e8efd83 100644 --- a/mobx_codegen/lib/src/template/observable.dart +++ b/mobx_codegen/lib/src/template/observable.dart @@ -11,6 +11,7 @@ class ObservableTemplate { required this.name, this.isReadOnly = false, this.isPrivate = false, + this.isLate = false, this.equals, this.useDeepEquality, }); @@ -21,6 +22,7 @@ class ObservableTemplate { final String name; final bool isPrivate; final bool isReadOnly; + final bool isLate; final ExecutableElement? equals; final bool? useDeepEquality; @@ -53,16 +55,34 @@ class ObservableTemplate { }'''; } + String _buildSetters() { + if (isLate) { + return ''' + bool _${name}IsInitialized = false; + @override - String toString() => """ - late final $atomName = Atom(name: '${storeTemplate.parentTypeName}.$name', context: context); - -${_buildGetters()} + set $name($type value) { + $atomName.reportWrite(value, _${name}IsInitialized ? super.$name : null, () { + super.$name = value; + _${name}IsInitialized = true; + }${equals != null ? ', equals: ${equals!.name}' : ''}); + }'''; + } + return ''' @override set $name($type value) { $atomName.reportWrite(value, super.$name, () { super.$name = value; }${equals != null ? ', equals: ${equals!.name}' : ''}${useDeepEquality != null ? ', useDeepEquality: $useDeepEquality' : ''}); - }"""; + }'''; + } + + @override + String toString() => """ + late final $atomName = Atom(name: '${storeTemplate.parentTypeName}.$name', context: context); + +${_buildGetters()} + +${_buildSetters()}"""; } diff --git a/mobx_codegen/lib/version.dart b/mobx_codegen/lib/version.dart index d2bed9e49..bc245f3fc 100644 --- a/mobx_codegen/lib/version.dart +++ b/mobx_codegen/lib/version.dart @@ -1,4 +1,4 @@ // Generated via set_version.dart. !!!DO NOT MODIFY BY HAND!!! /// The current version as per `pubspec.yaml`. -const version = '2.4.1'; +const version = '2.5.0'; diff --git a/mobx_codegen/pubspec.yaml b/mobx_codegen/pubspec.yaml index b14e3cd8f..915094400 100644 --- a/mobx_codegen/pubspec.yaml +++ b/mobx_codegen/pubspec.yaml @@ -1,6 +1,6 @@ name: mobx_codegen description: Code generator for MobX that adds support for annotating your code with @observable, @computed, @action and also creating Store classes. -version: 2.4.1 +version: 2.5.0 homepage: https://github.com/mobxjs/mobx.dart issue_tracker: https://github.com/mobxjs/mobx.dart/issues diff --git a/mobx_codegen/test/data/valid_late_variables_output.dart b/mobx_codegen/test/data/valid_late_variables_output.dart index 3fdbde0b1..9e280d3c1 100644 --- a/mobx_codegen/test/data/valid_late_variables_output.dart +++ b/mobx_codegen/test/data/valid_late_variables_output.dart @@ -8,10 +8,14 @@ mixin _$TestStore on _TestStore, Store { return super.username; } + bool _usernameIsInitialized = false; + @override set username(String value) { - _$usernameAtom.reportWrite(value, super.username, () { + _$usernameAtom + .reportWrite(value, _usernameIsInitialized ? super.username : null, () { super.username = value; + _usernameIsInitialized = true; }); } } diff --git a/mobx_codegen/test/generator_usage_test.dart b/mobx_codegen/test/generator_usage_test.dart index 306b6be51..3a6bb2dd7 100644 --- a/mobx_codegen/test/generator_usage_test.dart +++ b/mobx_codegen/test/generator_usage_test.dart @@ -124,6 +124,9 @@ abstract class _TestStore with Store { // ignore: only_throw_errors throw 'TEST ERROR'; } + + @observable + late String lateField; } void main() { @@ -279,4 +282,16 @@ void main() { expect(values, equals(['', 'field1', 'field2'])); }); + + test('setting late fields with action works', () { + final store = TestStore('field1', field2: 'field2'); + + final fields = []; + autorun((_) { + fields.add(store.lateField); + }); + store.lateField = 'field'; + + expect(fields, equals(['field'])); + }); } diff --git a/mobx_codegen/test/generator_usage_test.g.dart b/mobx_codegen/test/generator_usage_test.g.dart index 09d94af67..dff31d232 100644 --- a/mobx_codegen/test/generator_usage_test.g.dart +++ b/mobx_codegen/test/generator_usage_test.g.dart @@ -178,6 +178,26 @@ mixin _$TestStore on _TestStore, Store { }); } + late final _$lateFieldAtom = + Atom(name: '_TestStore.lateField', context: context); + + @override + String get lateField { + _$lateFieldAtom.reportRead(); + return super.lateField; + } + + bool _lateFieldIsInitialized = false; + + @override + set lateField(String value) { + _$lateFieldAtom.reportWrite( + value, _lateFieldIsInitialized ? super.lateField : null, () { + super.lateField = value; + _lateFieldIsInitialized = true; + }); + } + @override ObservableFuture future() { final _$future = super.future(); @@ -262,6 +282,7 @@ batchItem2: ${batchItem2}, batchItem3: ${batchItem3}, batchItem4: ${batchItem4}, errorField: ${errorField}, +lateField: ${lateField}, fields: ${fields}, batchedItems: ${batchedItems} '''; diff --git a/mobx_codegen/test/nested_store.g.dart b/mobx_codegen/test/nested_store.g.dart index 6599ebde4..79d54e3e2 100644 --- a/mobx_codegen/test/nested_store.g.dart +++ b/mobx_codegen/test/nested_store.g.dart @@ -17,10 +17,13 @@ mixin _$NestedStore on _NestedStore, Store { return super.name; } + bool _nameIsInitialized = false; + @override set name(String value) { - _$nameAtom.reportWrite(value, super.name, () { + _$nameAtom.reportWrite(value, _nameIsInitialized ? super.name : null, () { super.name = value; + _nameIsInitialized = true; }); } diff --git a/mobx_codegen/test/store_with_custom_context.g.dart b/mobx_codegen/test/store_with_custom_context.g.dart index aaea811b4..17666201c 100644 --- a/mobx_codegen/test/store_with_custom_context.g.dart +++ b/mobx_codegen/test/store_with_custom_context.g.dart @@ -18,10 +18,13 @@ mixin _$CustomContextStore on _CustomContextStore, Store { return super.name; } + bool _nameIsInitialized = false; + @override set name(String value) { - _$nameAtom.reportWrite(value, super.name, () { + _$nameAtom.reportWrite(value, _nameIsInitialized ? super.name : null, () { super.name = value; + _nameIsInitialized = true; }); }