├── .gitignore ├── .travis.yaml ├── LICENSE ├── README.md ├── meta_types ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── example │ ├── example.dart │ └── example.g.dart ├── lib │ └── meta_types.dart └── pubspec.yaml ├── meta_types_generator ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── build.yaml ├── example │ └── example.dart ├── lib │ ├── builder.dart │ ├── generator_api.dart │ └── src │ │ ├── data_class.dart │ │ ├── data_class_template.dart │ │ ├── enum_class.dart │ │ ├── enum_class_template.dart │ │ ├── generator.dart │ │ ├── generator_util.dart │ │ ├── sealed_class.dart │ │ └── sealed_class_template.dart ├── pubspec.yaml └── test │ └── unit │ ├── data_class_test.dart │ ├── models │ ├── definitions │ │ ├── b_tree.dart │ │ ├── data_class.dart │ │ ├── data_class_final.dart │ │ ├── data_class_generic.dart │ │ ├── data_class_inheritence.dart │ │ ├── data_class_interfaces.dart │ │ ├── data_class_mixin.dart │ │ ├── data_class_nesting.dart │ │ ├── enum_class.dart │ │ ├── enum_class_mixin.dart │ │ ├── enum_double.dart │ │ ├── enum_int.dart │ │ ├── enum_string.dart │ │ ├── sealed_class.dart │ │ ├── sealed_class_generics.dart │ │ ├── sealed_class_mixin.dart │ │ └── sealed_class_nesting.dart │ ├── models.dart │ └── models.g.dart │ └── union_class_test.dart ├── meta_types_json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── example │ ├── example.dart │ └── example.g.dart ├── lib │ └── meta_types_json.dart └── pubspec.yaml ├── meta_types_json_generator ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── build.yaml ├── example │ └── example.dart ├── lib │ └── builder.dart └── pubspec.yaml ├── meta_types_redux ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── example │ ├── example.dart │ └── example.g.dart ├── lib │ └── meta_types_redux.dart └── pubspec.yaml ├── meta_types_redux_generator ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── build.yaml ├── example │ └── example.dart ├── lib │ └── builder.dart └── pubspec.yaml └── mono_repo.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | .dart_tool 2 | .packages 3 | .pub 4 | pubspec.lock -------------------------------------------------------------------------------- /.travis.yaml: -------------------------------------------------------------------------------- 1 | language: dart 2 | script: 3 | - cd meta_types 4 | - pub get 5 | - pub run build_runner build 6 | - cd ../meta_types_generator 7 | - pub get 8 | - pub run build_runner test 9 | - cd ../meta_types_json 10 | - pub get 11 | - pub run build_runner build 12 | - dart example/example.dart 13 | - cd ../meta_types_redux 14 | - pub get 15 | - pub run build_runner build 16 | - dart example/example.dart -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 David Marne 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dart_meta_types 2 | 3 | [![Pub](https://img.shields.io/pub/v/meta_types.svg)](https://pub.dartlang.org/packages/meta_types) 4 | 5 | a code gen solution for defining sealed classes, data classes, and enum classes for dart. 6 | [examples](meta_types/example/example.dart). 7 | 8 | ## puropse 9 | 10 | * attempt to keep dart up to par with data types supported by kotlin. 11 | * provide means for defining algebreic data types in dart. 12 | * define patterns and apis for generating 3rd party mixins to provide additional functionality to generated models. e.g. meta_types_json. 13 | * support explicitly defining dataclasses as abstract, interface, extendable, and/or final. The generator can enforces strict practices for these concepts which dart-lang itself does not enforce. 14 | * provide means for representing non-nullable and nullable types in your data model. 15 | * provide means for meta-programming with your models without using dart:mirrors. 16 | 17 | ## How to use meta_types 18 | 19 | * Define model definitions using annotations from the meta_types package. 20 | * Add meta_types_generator and build_runner to your dev_dependencies 21 | * generate code by running `pub run build_runner run` 22 | 23 | See meta_types/example for examples on how to write model definitions. 24 | 25 | ## One rule to follow 26 | 27 | When writing class definitions ALWAYS use other class definitions when referencing other meta types. When writing code ALWAYS use the generated classes. Using the class definitons gives the generator the ability to resolve type information for classes that have not yet been generated. 28 | 29 | For this reason, class definitions for public models should always be made public. 30 | 31 | Note, this is different from other dart code gen solutions such as json_serializable and built_value, because the model definition is NOT used in your code. The generated classes are used directly in your code. This lets the generator generate constructors and additional fields and functions that are not present in the model definition, e.g. the clone method for data classes. 32 | 33 | ## Types 34 | 35 | * All metatypes are hashable and comparable. 36 | * All meta_types extend from a base class that allow them to be used generically for metaprogramming. 37 | 38 | For example, you can write a function that has in input of type `DataClass` which can be called with any data class. That function can use the accessors on DataClass to iterate over all the fields in the dataclass. 39 | 40 | ### data classes 41 | 42 | Data classes are immutable classes that only contain data. Dataclasses can be interfaces, abstract, extendable, or final. All generated models extend `DataClass`. 43 | 44 | ### sealed classes 45 | 46 | Sealed classes are immutable classes that have multiple fields, but only a single field can be set. Sealed classes cannot be extended or used as interfaces. All generated models extend `SealedClass`. 47 | 48 | ### enum classes 49 | 50 | Enum classes are classes that represent enumerations, using any type to represent the enumeration values. Enum classes cannot be extended or used as interfaces. All generated models extend `EnumClass`. 51 | 52 | ## Example - Binary tree ADT using sealed and data classes 53 | 54 | ```dart 55 | 56 | // model definitions 57 | 58 | @SealedClass() 59 | abstract class $BinaryTree { 60 | T get leaf; 61 | $Branch get branch; 62 | } 63 | 64 | @DataClass() 65 | abstract class $Branch { 66 | T get value; 67 | $BinaryTree get left; 68 | $BinaryTree get right; 69 | } 70 | ``` 71 | 72 | ```dart 73 | // model usage 74 | 75 | void preorderTraversal(BinaryTree tree) => tree.when( 76 | leaf: (val) { 77 | print(val); 78 | }, 79 | branch: (b) { 80 | print(b.value); 81 | preorderTraversal(b.left); 82 | preorderTraversal(b.right); 83 | }, 84 | ); 85 | 86 | final tree = BinaryTree.branchFactory( 87 | Branch( 88 | value: 1, 89 | left: BinaryTree.branchFactory( 90 | Branch( 91 | value: 2, 92 | left: BinaryTree.leafFactory(3), 93 | right: BinaryTree.leafFactory(4), 94 | ), 95 | ), 96 | right: BinaryTree.leafFactory(5), 97 | ), 98 | ); 99 | 100 | // prints 1, 2, 3, 4, 5 101 | preorderTraversal(tree); 102 | ``` 103 | 104 | ### Example: data class features 105 | ```dart 106 | // model definition 107 | @DataClass() 108 | abstract class $ExampleDataClass { 109 | // fieldWithNoDefault is a field without a default value 110 | // the constructor will require a value be passed for this param 111 | int get fieldWithNoDefault; 112 | 113 | // fieldWithDefault uses a default value of 10 if 114 | // no other value is passed to the constructor 115 | int get fieldWithDefault => 10; 116 | 117 | // data class fields are not nullable, one must 118 | // use the Nullable class to represent nullable fields 119 | Nullable get nullable; 120 | 121 | // computed fields memoize the result of the getter function 122 | @computed 123 | int get computedField => fieldWithDefault + 5; 124 | } 125 | ``` 126 | 127 | ```dart 128 | // model usage 129 | 130 | final d = ExampleDataClass( 131 | fieldWithNoDefault: 0, 132 | nullable: Nullable.nil(), 133 | ); 134 | 135 | print(d.fieldWithNoDefault); // 0 136 | print(d.fieldWithDefault); // 10 137 | print(d.nullable.value); // null 138 | print(d.computedField); // 15 139 | 140 | ``` 141 | 142 | see more examples [here](meta_types/example/example.dart) 143 | -------------------------------------------------------------------------------- /meta_types/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.1.0 2 | 3 | * initial annotations for annotating union, enum, and data classes 4 | * initial classes defined which all meta_types extend -------------------------------------------------------------------------------- /meta_types/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 David Marne 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /meta_types/README.md: -------------------------------------------------------------------------------- 1 | # meta_types 2 | 3 | library used for defining union, enum, and data classes. 4 | 5 | See [examples](example/example.dart) for example usage. 6 | See [dart_meta_types/README.md](../README.md) for more information. -------------------------------------------------------------------------------- /meta_types/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: 3 | implicit-casts: false 4 | implicit-dynamic: false 5 | -------------------------------------------------------------------------------- /meta_types/example/example.dart: -------------------------------------------------------------------------------- 1 | import 'package:meta_types/meta_types.dart'; 2 | 3 | part 'example.g.dart'; 4 | 5 | // regular data class, 6 | @DataClass() 7 | abstract class $ExampleDataClass { 8 | // fieldWithNoDefault is a field without a default value 9 | // the constructor will require a value be passed for this param 10 | int get fieldWithNoDefault; 11 | 12 | // fieldWithDefault uses a default value of 10 if 13 | // no other value is passed to the constructor 14 | int get fieldWithDefault => 10; 15 | 16 | // data class fields are not nullable, one must 17 | // use the Nullable class to represent nullable fields 18 | Nullable get nullable; 19 | 20 | // computed fields memoize the result of the getter function 21 | @computed 22 | int get computedField => fieldWithDefault + 5; 23 | } 24 | 25 | // ImplementorDataClass will implement $InterfaceDataClass 26 | @DataClass() 27 | abstract class $ImplementorDataClass implements $InterfaceDataClass { 28 | int get foo; 29 | } 30 | 31 | // $InterfaceDataClass must only be implemented. It will not be constructable itself. 32 | // It cannot be used in extends clauses, only implements clauses. Interfaces cannot 33 | // have default values. 34 | @DataClass(isInterface: true) 35 | abstract class $InterfaceDataClass { 36 | String get bar; 37 | } 38 | 39 | // BaseDataClass will contain all fields from ParentDataClass and GrandparentDataClass 40 | @DataClass() 41 | abstract class $BaseDataClass extends $ParentDataClass { 42 | int get foo; 43 | } 44 | 45 | // ParentDataClass will not be constructable since isAbstract is true 46 | @DataClass(isAbstract: true) 47 | abstract class $ParentDataClass extends $GrandparentDataClass { 48 | int get bar; 49 | } 50 | 51 | @DataClass(isAbstract: true) 52 | abstract class $GrandparentDataClass { 53 | String get baz => 'baz'; 54 | } 55 | 56 | // ExampleSealedClass will require one and only 57 | // on of the following fields are set. A when function 58 | // is also generated for easy switching. e.g.: 59 | // sealedClassInstance.when( 60 | // (intval) => print('int val is $intval'), 61 | // (strval) => print('str val is $strval'), 62 | // ); 63 | @SealedClass() 64 | abstract class $ExampleSealedClass { 65 | int get integer; 66 | String get string; 67 | } 68 | 69 | // enum class with int will using incrementing integers as values 70 | // unless a nother value is specified 71 | 72 | @EnumClass(int) 73 | abstract class $ExampleEnumInteger { 74 | static int a; // 0 75 | static int b; // 1 76 | static int c = 1000; // 1000 77 | static int d; // 3 78 | } 79 | 80 | // enum class with strings will use field name as value 81 | // unless a nother value is specified 82 | 83 | @EnumClass(String) 84 | abstract class $ExampleEnumString { 85 | static String a; 86 | static String b; 87 | static String c = 'custom'; 88 | } 89 | 90 | // enum class with custom type. 91 | 92 | @EnumClass(Signal) 93 | abstract class $ProtocolState { 94 | static const Waiting waiting = Waiting(); 95 | static const Talking talking = Talking(); 96 | } 97 | 98 | abstract class Signal { 99 | ProtocolState get signal; 100 | } 101 | 102 | class Waiting implements Signal { 103 | const Waiting(); 104 | ProtocolState get signal => ProtocolState.talking; 105 | } 106 | 107 | class Talking implements Signal { 108 | const Talking(); 109 | ProtocolState get signal => ProtocolState.waiting; 110 | } 111 | 112 | // Binary tree is an example of an algebreic data type 113 | // It is the combination of two unions 114 | 115 | @SealedClass() 116 | abstract class $BinaryTree { 117 | T get leaf; 118 | $Branch get branch; 119 | } 120 | 121 | @DataClass() 122 | abstract class $Branch { 123 | T get val; 124 | $BinaryTree get left; 125 | $BinaryTree get right; 126 | } 127 | 128 | void preorderTraversal(BinaryTree tree) => tree.when( 129 | leaf: (val) { 130 | print(val); 131 | }, 132 | branch: (b) { 133 | print(b.val); 134 | preorderTraversal(b.left); 135 | preorderTraversal(b.right); 136 | }, 137 | ); 138 | -------------------------------------------------------------------------------- /meta_types/example/example.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'example.dart'; 4 | 5 | // ************************************************************************** 6 | // MetaTypesGenerator 7 | // ************************************************************************** 8 | 9 | abstract class _ExampleDataClassBase extends DataClass { 10 | int get fieldWithNoDefault; 11 | int get fieldWithDefault => 10; 12 | Nullable get nullable; 13 | @computed 14 | int get computedField => fieldWithDefault + 5; 15 | @override 16 | Iterable get computedFields => 17 | [new ComputedField("computedField")]; 18 | 19 | @override 20 | Iterable get nonDefaultedFields => [ 21 | new DataClassField("fieldWithNoDefault"), 22 | new DataClassField>("nullable") 23 | ]; 24 | 25 | @override 26 | Iterable get defaultedFields => 27 | [new DataClassField("fieldWithDefault")]; 28 | 29 | Iterable _fields; 30 | @override 31 | Iterable get fields => 32 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 33 | } 34 | 35 | class ExampleDataClass extends _ExampleDataClassBase { 36 | final int _fieldWithNoDefault; 37 | final Nullable _nullable; 38 | final int _fieldWithDefault; 39 | int _computedField; 40 | 41 | ExampleDataClass({ 42 | @required int fieldWithNoDefault, 43 | @required Nullable nullable, 44 | int fieldWithDefault, 45 | }) : _fieldWithNoDefault = fieldWithNoDefault, 46 | _fieldWithDefault = fieldWithDefault, 47 | _nullable = nullable, 48 | super() { 49 | assert(this.fieldWithNoDefault != null, 50 | "null value provided for field fieldWithNoDefault"); 51 | assert(this.fieldWithDefault != null, 52 | "null value provided for field fieldWithDefault"); 53 | assert(this.nullable != null, "null value provided for field nullable"); 54 | } 55 | 56 | ExampleDataClass clone({ 57 | int fieldWithNoDefault, 58 | int fieldWithDefault, 59 | Nullable nullable, 60 | }) => 61 | new ExampleDataClass( 62 | fieldWithNoDefault: fieldWithNoDefault ?? _fieldWithNoDefault, 63 | fieldWithDefault: fieldWithDefault ?? _fieldWithDefault, 64 | nullable: nullable ?? _nullable, 65 | ); 66 | 67 | @override 68 | int get fieldWithNoDefault => _fieldWithNoDefault; 69 | @override 70 | Nullable get nullable => _nullable; 71 | @override 72 | int get fieldWithDefault => _fieldWithDefault ?? super.fieldWithDefault; 73 | @override 74 | int get computedField => _computedField ??= super.computedField; 75 | 76 | @override 77 | bool operator ==(dynamic other) { 78 | if (identical(other, this)) return true; 79 | if (other is! ExampleDataClass) return false; 80 | return fieldWithNoDefault == other.fieldWithNoDefault && 81 | fieldWithDefault == other.fieldWithDefault && 82 | nullable == other.nullable; 83 | } 84 | 85 | @override 86 | int get hashCode { 87 | return $jf($jc( 88 | $jc($jc(0, fieldWithNoDefault.hashCode), fieldWithDefault.hashCode), 89 | nullable.hashCode)); 90 | } 91 | } 92 | 93 | abstract class _ImplementorDataClassBase extends DataClass 94 | implements InterfaceDataClass { 95 | int get foo; 96 | @override 97 | Iterable get computedFields => []; 98 | 99 | @override 100 | Iterable get nonDefaultedFields => 101 | [new DataClassField("foo"), new DataClassField("bar")]; 102 | 103 | @override 104 | Iterable get defaultedFields => []; 105 | 106 | Iterable _fields; 107 | @override 108 | Iterable get fields => 109 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 110 | } 111 | 112 | class ImplementorDataClass extends _ImplementorDataClassBase 113 | implements InterfaceDataClass { 114 | final int _foo; 115 | final String _bar; 116 | 117 | ImplementorDataClass({ 118 | @required int foo, 119 | @required String bar, 120 | }) : _foo = foo, 121 | _bar = bar, 122 | super() { 123 | assert(this.foo != null, "null value provided for field foo"); 124 | assert(this.bar != null, "null value provided for field bar"); 125 | } 126 | 127 | ImplementorDataClass clone({ 128 | int foo, 129 | String bar, 130 | }) => 131 | new ImplementorDataClass( 132 | foo: foo ?? _foo, 133 | bar: bar ?? _bar, 134 | ); 135 | 136 | @override 137 | ImplementorDataClass cloneInterfaceDataClass({ 138 | String bar, 139 | }) => 140 | clone( 141 | bar: bar ?? _bar, 142 | ); 143 | 144 | @override 145 | int get foo => _foo; 146 | @override 147 | String get bar => _bar; 148 | 149 | @override 150 | bool operator ==(dynamic other) { 151 | if (identical(other, this)) return true; 152 | if (other is! ImplementorDataClass) return false; 153 | return foo == other.foo && bar == other.bar; 154 | } 155 | 156 | @override 157 | int get hashCode { 158 | return $jf($jc($jc(0, foo.hashCode), bar.hashCode)); 159 | } 160 | } 161 | 162 | abstract class InterfaceDataClass { 163 | String get bar; 164 | InterfaceDataClass cloneInterfaceDataClass({ 165 | String bar, 166 | }); 167 | } 168 | 169 | abstract class _BaseDataClassBase extends ParentDataClass { 170 | _BaseDataClassBase({ 171 | @required int bar, 172 | String baz, 173 | }) : super( 174 | bar: bar, 175 | baz: baz, 176 | ); 177 | int get foo; 178 | @override 179 | Iterable get computedFields => []; 180 | 181 | @override 182 | Iterable get nonDefaultedFields => 183 | [new DataClassField("foo")]; 184 | 185 | @override 186 | Iterable get defaultedFields => []; 187 | 188 | Iterable _fields; 189 | @override 190 | Iterable get fields => 191 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 192 | } 193 | 194 | class BaseDataClass extends _BaseDataClassBase { 195 | final int _foo; 196 | 197 | BaseDataClass({ 198 | @required int foo, 199 | @required int bar, 200 | String baz, 201 | }) : _foo = foo, 202 | super( 203 | bar: bar, 204 | baz: baz, 205 | ) { 206 | assert(this.foo != null, "null value provided for field foo"); 207 | } 208 | 209 | BaseDataClass clone({ 210 | int foo, 211 | int bar, 212 | String baz, 213 | }) => 214 | new BaseDataClass( 215 | foo: foo ?? _foo, 216 | bar: bar ?? _bar, 217 | baz: baz ?? _baz, 218 | ); 219 | 220 | @override 221 | BaseDataClass cloneParentDataClass({ 222 | int bar, 223 | String baz, 224 | }) => 225 | clone( 226 | bar: bar ?? _bar, 227 | baz: baz ?? _baz, 228 | ); 229 | 230 | @override 231 | BaseDataClass cloneGrandparentDataClass({ 232 | String baz, 233 | }) => 234 | clone( 235 | baz: baz ?? _baz, 236 | ); 237 | 238 | @override 239 | int get foo => _foo; 240 | 241 | @override 242 | bool operator ==(dynamic other) { 243 | if (identical(other, this)) return true; 244 | if (other is! BaseDataClass) return false; 245 | return foo == other.foo; 246 | } 247 | 248 | @override 249 | int get hashCode { 250 | return $jf($jc(0, foo.hashCode)); 251 | } 252 | } 253 | 254 | abstract class _ParentDataClassBase extends GrandparentDataClass { 255 | _ParentDataClassBase({ 256 | String baz, 257 | }) : super( 258 | baz: baz, 259 | ); 260 | int get bar; 261 | @override 262 | Iterable get computedFields => []; 263 | 264 | @override 265 | Iterable get nonDefaultedFields => 266 | [new DataClassField("bar")]; 267 | 268 | @override 269 | Iterable get defaultedFields => []; 270 | 271 | Iterable _fields; 272 | @override 273 | Iterable get fields => 274 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 275 | } 276 | 277 | abstract class ParentDataClass extends _ParentDataClassBase { 278 | final int _bar; 279 | 280 | ParentDataClass({ 281 | @required int bar, 282 | String baz, 283 | }) : _bar = bar, 284 | super( 285 | baz: baz, 286 | ) { 287 | assert(this.bar != null, "null value provided for field bar"); 288 | } 289 | 290 | ParentDataClass cloneParentDataClass({ 291 | int bar, 292 | String baz, 293 | }); 294 | 295 | @override 296 | ParentDataClass cloneGrandparentDataClass({ 297 | String baz, 298 | }); 299 | 300 | @override 301 | int get bar => _bar; 302 | 303 | @override 304 | bool operator ==(dynamic other) { 305 | if (identical(other, this)) return true; 306 | if (other is! ParentDataClass) return false; 307 | return bar == other.bar; 308 | } 309 | 310 | @override 311 | int get hashCode { 312 | return $jf($jc(0, bar.hashCode)); 313 | } 314 | } 315 | 316 | abstract class _GrandparentDataClassBase extends DataClass { 317 | String get baz => 'baz'; 318 | @override 319 | Iterable get computedFields => []; 320 | 321 | @override 322 | Iterable get nonDefaultedFields => []; 323 | 324 | @override 325 | Iterable get defaultedFields => 326 | [new DataClassField("baz")]; 327 | 328 | Iterable _fields; 329 | @override 330 | Iterable get fields => 331 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 332 | } 333 | 334 | abstract class GrandparentDataClass extends _GrandparentDataClassBase { 335 | final String _baz; 336 | 337 | GrandparentDataClass({ 338 | String baz, 339 | }) : _baz = baz, 340 | super() { 341 | assert(this.baz != null, "null value provided for field baz"); 342 | } 343 | 344 | GrandparentDataClass cloneGrandparentDataClass({ 345 | String baz, 346 | }); 347 | 348 | @override 349 | String get baz => _baz ?? super.baz; 350 | 351 | @override 352 | bool operator ==(dynamic other) { 353 | if (identical(other, this)) return true; 354 | if (other is! GrandparentDataClass) return false; 355 | return baz == other.baz; 356 | } 357 | 358 | @override 359 | int get hashCode { 360 | return $jf($jc(0, baz.hashCode)); 361 | } 362 | } 363 | 364 | class ExampleSealedClass extends _ExampleSealedClassBase { 365 | final int _integer; 366 | final bool _integerSet; 367 | 368 | final String _string; 369 | final bool _stringSet; 370 | 371 | ExampleSealedClass.integerFactory(this._integer) 372 | : _stringSet = false, 373 | _string = null, 374 | _integerSet = true; 375 | 376 | ExampleSealedClass.stringFactory(this._string) 377 | : _integerSet = false, 378 | _integer = null, 379 | _stringSet = true; 380 | 381 | int get integer => _integer; 382 | bool get integerSet => _integerSet; 383 | 384 | String get string => _string; 385 | bool get stringSet => _stringSet; 386 | 387 | W when({ 388 | @required W integer(int integer), 389 | @required W string(String string), 390 | }) { 391 | if (_integerSet) return integer(this.integer); 392 | return string(this.string); 393 | } 394 | 395 | @override 396 | bool operator ==(dynamic other) { 397 | if (identical(other, this)) return true; 398 | if (other is! ExampleSealedClass) return false; 399 | return integer == other.integer && string == other.string; 400 | } 401 | 402 | @override 403 | int get hashCode { 404 | return $jf($jc($jc(0, integer.hashCode), string.hashCode)); 405 | } 406 | } 407 | 408 | abstract class _ExampleSealedClassBase extends SealedClass { 409 | int get integer; 410 | String get string; 411 | bool get integerSet; 412 | 413 | bool get stringSet; 414 | @override 415 | Iterable get computedFields => []; 416 | 417 | @override 418 | Iterable get unionFields => [ 419 | new SealedClassField("integer"), 420 | new SealedClassField("string") 421 | ]; 422 | W when({ 423 | @required W integer(int integer), 424 | @required W string(String string), 425 | }); 426 | } 427 | 428 | class ExampleEnumInteger extends _ExampleEnumIntegerBase { 429 | final int _value; 430 | 431 | static final values = Set.from( 432 | [ 433 | ExampleEnumInteger.a, 434 | ExampleEnumInteger.b, 435 | ExampleEnumInteger.c, 436 | ExampleEnumInteger.d, 437 | ], 438 | ); 439 | 440 | static ExampleEnumInteger valueOf(int v) { 441 | if (ExampleEnumInteger.a.value == v) return ExampleEnumInteger.a; 442 | if (ExampleEnumInteger.b.value == v) return ExampleEnumInteger.b; 443 | if (ExampleEnumInteger.c.value == v) return ExampleEnumInteger.c; 444 | if (ExampleEnumInteger.d.value == v) return ExampleEnumInteger.d; 445 | return null; 446 | } 447 | 448 | ExampleEnumInteger._(this._value) : super._(int); 449 | 450 | static final ExampleEnumInteger a = 451 | new ExampleEnumInteger._(_ExampleEnumIntegerBase.a ?? 0); 452 | static final ExampleEnumInteger b = 453 | new ExampleEnumInteger._(_ExampleEnumIntegerBase.b ?? 1); 454 | static final ExampleEnumInteger c = 455 | new ExampleEnumInteger._(_ExampleEnumIntegerBase.c ?? 2); 456 | static final ExampleEnumInteger d = 457 | new ExampleEnumInteger._(_ExampleEnumIntegerBase.d ?? 3); 458 | 459 | @override 460 | int get value => _value; 461 | 462 | @override 463 | ExampleEnumInteger valueOfOther(int v) => ExampleEnumInteger.valueOf(v); 464 | 465 | @override 466 | Set get allValues => ExampleEnumInteger.values; 467 | 468 | @override 469 | bool operator ==(dynamic other) { 470 | if (identical(other, this)) return true; 471 | if (other is! ExampleEnumInteger) return false; 472 | return value == other.value; 473 | } 474 | 475 | @override 476 | int get hashCode { 477 | return $jf($jc(0, value.hashCode)); 478 | } 479 | 480 | @override 481 | String toString() { 482 | if (this == ExampleEnumInteger.a) return 'ExampleEnumInteger.a: $_value'; 483 | if (this == ExampleEnumInteger.b) return 'ExampleEnumInteger.b: $_value'; 484 | if (this == ExampleEnumInteger.c) return 'ExampleEnumInteger.c: $_value'; 485 | if (this == ExampleEnumInteger.d) return 'ExampleEnumInteger.d: $_value'; 486 | return ''; 487 | } 488 | } 489 | 490 | abstract class _ExampleEnumIntegerBase 491 | extends EnumClass { 492 | _ExampleEnumIntegerBase._(Type type) : super(type); 493 | static int a; 494 | static int b; 495 | static int c = 1000; 496 | static int d; 497 | } 498 | 499 | class ExampleEnumString extends _ExampleEnumStringBase { 500 | final String _value; 501 | 502 | static final values = Set.from( 503 | [ 504 | ExampleEnumString.a, 505 | ExampleEnumString.b, 506 | ExampleEnumString.c, 507 | ], 508 | ); 509 | 510 | static ExampleEnumString valueOf(String v) { 511 | if (ExampleEnumString.a.value == v) return ExampleEnumString.a; 512 | if (ExampleEnumString.b.value == v) return ExampleEnumString.b; 513 | if (ExampleEnumString.c.value == v) return ExampleEnumString.c; 514 | return null; 515 | } 516 | 517 | ExampleEnumString._(this._value) : super._(String); 518 | 519 | static final ExampleEnumString a = 520 | new ExampleEnumString._(_ExampleEnumStringBase.a ?? 'a'); 521 | static final ExampleEnumString b = 522 | new ExampleEnumString._(_ExampleEnumStringBase.b ?? 'b'); 523 | static final ExampleEnumString c = 524 | new ExampleEnumString._(_ExampleEnumStringBase.c ?? 'c'); 525 | 526 | @override 527 | String get value => _value; 528 | 529 | @override 530 | ExampleEnumString valueOfOther(String v) => ExampleEnumString.valueOf(v); 531 | 532 | @override 533 | Set get allValues => ExampleEnumString.values; 534 | 535 | @override 536 | bool operator ==(dynamic other) { 537 | if (identical(other, this)) return true; 538 | if (other is! ExampleEnumString) return false; 539 | return value == other.value; 540 | } 541 | 542 | @override 543 | int get hashCode { 544 | return $jf($jc(0, value.hashCode)); 545 | } 546 | 547 | @override 548 | String toString() { 549 | if (this == ExampleEnumString.a) return 'ExampleEnumString.a: $_value'; 550 | if (this == ExampleEnumString.b) return 'ExampleEnumString.b: $_value'; 551 | if (this == ExampleEnumString.c) return 'ExampleEnumString.c: $_value'; 552 | return ''; 553 | } 554 | } 555 | 556 | abstract class _ExampleEnumStringBase 557 | extends EnumClass { 558 | _ExampleEnumStringBase._(Type type) : super(type); 559 | static String a; 560 | static String b; 561 | static String c = 'custom'; 562 | } 563 | 564 | class ProtocolState extends _ProtocolStateBase { 565 | final Signal _value; 566 | 567 | static final values = Set.from( 568 | [ 569 | ProtocolState.waiting, 570 | ProtocolState.talking, 571 | ], 572 | ); 573 | 574 | static ProtocolState valueOf(Signal v) { 575 | if (ProtocolState.waiting.value == v) return ProtocolState.waiting; 576 | if (ProtocolState.talking.value == v) return ProtocolState.talking; 577 | return null; 578 | } 579 | 580 | ProtocolState._(this._value) : super._(Signal); 581 | 582 | static final ProtocolState waiting = 583 | new ProtocolState._(_ProtocolStateBase.waiting); 584 | static final ProtocolState talking = 585 | new ProtocolState._(_ProtocolStateBase.talking); 586 | 587 | @override 588 | Signal get value => _value; 589 | 590 | @override 591 | ProtocolState valueOfOther(Signal v) => ProtocolState.valueOf(v); 592 | 593 | @override 594 | Set get allValues => ProtocolState.values; 595 | 596 | @override 597 | bool operator ==(dynamic other) { 598 | if (identical(other, this)) return true; 599 | if (other is! ProtocolState) return false; 600 | return value == other.value; 601 | } 602 | 603 | @override 604 | int get hashCode { 605 | return $jf($jc(0, value.hashCode)); 606 | } 607 | 608 | @override 609 | String toString() { 610 | if (this == ProtocolState.waiting) return 'ProtocolState.waiting: $_value'; 611 | if (this == ProtocolState.talking) return 'ProtocolState.talking: $_value'; 612 | return ''; 613 | } 614 | } 615 | 616 | abstract class _ProtocolStateBase extends EnumClass { 617 | _ProtocolStateBase._(Type type) : super(type); 618 | static const Waiting waiting = Waiting(); 619 | static const Talking talking = Talking(); 620 | } 621 | 622 | class BinaryTree extends _BinaryTreeBase { 623 | final T _leaf; 624 | final bool _leafSet; 625 | 626 | final Branch _branch; 627 | final bool _branchSet; 628 | 629 | BinaryTree.leafFactory(this._leaf) 630 | : _branchSet = false, 631 | _branch = null, 632 | _leafSet = true; 633 | 634 | BinaryTree.branchFactory(this._branch) 635 | : _leafSet = false, 636 | _leaf = null, 637 | _branchSet = true; 638 | 639 | T get leaf => _leaf; 640 | bool get leafSet => _leafSet; 641 | 642 | Branch get branch => _branch; 643 | bool get branchSet => _branchSet; 644 | 645 | W when({ 646 | @required W leaf(T leaf), 647 | @required W branch(Branch branch), 648 | }) { 649 | if (_leafSet) return leaf(this.leaf); 650 | return branch(this.branch); 651 | } 652 | 653 | @override 654 | bool operator ==(dynamic other) { 655 | if (identical(other, this)) return true; 656 | if (other is! BinaryTree) return false; 657 | return leaf == other.leaf && branch == other.branch; 658 | } 659 | 660 | @override 661 | int get hashCode { 662 | return $jf($jc($jc(0, leaf.hashCode), branch.hashCode)); 663 | } 664 | } 665 | 666 | abstract class _BinaryTreeBase extends SealedClass { 667 | T get leaf; 668 | Branch get branch; 669 | bool get leafSet; 670 | 671 | bool get branchSet; 672 | @override 673 | Iterable get computedFields => []; 674 | 675 | @override 676 | Iterable get unionFields => [ 677 | new SealedClassField("leaf"), 678 | new SealedClassField>("branch") 679 | ]; 680 | W when({ 681 | @required W leaf(T leaf), 682 | @required W branch(Branch branch), 683 | }); 684 | } 685 | 686 | abstract class _BranchBase extends DataClass { 687 | T get val; 688 | BinaryTree get left; 689 | BinaryTree get right; 690 | @override 691 | Iterable get computedFields => []; 692 | 693 | @override 694 | Iterable get nonDefaultedFields => [ 695 | new DataClassField("val"), 696 | new DataClassField>("left"), 697 | new DataClassField>("right") 698 | ]; 699 | 700 | @override 701 | Iterable get defaultedFields => []; 702 | 703 | Iterable _fields; 704 | @override 705 | Iterable get fields => 706 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 707 | } 708 | 709 | class Branch extends _BranchBase { 710 | final T _val; 711 | final BinaryTree _left; 712 | final BinaryTree _right; 713 | 714 | Branch({ 715 | @required T val, 716 | @required BinaryTree left, 717 | @required BinaryTree right, 718 | }) : _val = val, 719 | _left = left, 720 | _right = right, 721 | super() { 722 | assert(this.val != null, "null value provided for field val"); 723 | assert(this.left != null, "null value provided for field left"); 724 | assert(this.right != null, "null value provided for field right"); 725 | } 726 | 727 | Branch clone({ 728 | T val, 729 | BinaryTree left, 730 | BinaryTree right, 731 | }) => 732 | new Branch( 733 | val: val ?? _val, 734 | left: left ?? _left, 735 | right: right ?? _right, 736 | ); 737 | 738 | @override 739 | T get val => _val; 740 | @override 741 | BinaryTree get left => _left; 742 | @override 743 | BinaryTree get right => _right; 744 | 745 | @override 746 | bool operator ==(dynamic other) { 747 | if (identical(other, this)) return true; 748 | if (other is! Branch) return false; 749 | return val == other.val && left == other.left && right == other.right; 750 | } 751 | 752 | @override 753 | int get hashCode { 754 | return $jf($jc($jc($jc(0, val.hashCode), left.hashCode), right.hashCode)); 755 | } 756 | } 757 | -------------------------------------------------------------------------------- /meta_types/lib/meta_types.dart: -------------------------------------------------------------------------------- 1 | export 'package:meta/meta.dart' show required; 2 | 3 | /// [computed] is used to annotate fields that are computed and not set explicitly. 4 | /// [computed] can be used in sealed and data classes. 5 | const computed = 'computed'; 6 | 7 | /// [DataClass] is used to annotate classes to generate data class boilerplate 8 | /// if `isInterface` is true, no constructor will be generated. 9 | class DataClass { 10 | final bool isFinal; 11 | final bool isInterface; 12 | final bool isAbstract; 13 | 14 | const DataClass({ 15 | bool isFinal = true, 16 | this.isInterface = false, 17 | this.isAbstract = false, 18 | }) : this.isFinal = isAbstract || isInterface ? false : isFinal; 19 | 20 | Iterable get computedFields => 21 | throw NotGenerated('computedFields'); 22 | Iterable get nonDefaultedFields => 23 | throw NotGenerated('nonDefaultedFields'); 24 | Iterable get defaultedFields => 25 | throw NotGenerated('defaultedFields'); 26 | Iterable get fields => throw NotGenerated('fields'); 27 | T valueOf(DataClassField field) => throw NotGenerated('valueOf'); 28 | } 29 | 30 | /// [EnumClass] can be used to annotate classes to generate enumeration 31 | /// class boilerplate 32 | class EnumClass { 33 | final Type type; 34 | const EnumClass([Type type]) : this.type = type ?? Object; 35 | T get value => throw NotGenerated('value'); 36 | Set get allValues => throw NotGenerated('values'); 37 | E valueOfOther(T t) => throw NotGenerated('valueOf'); 38 | } 39 | 40 | /// [SealedClass] can be used to annotate classes to generate sealed 41 | /// class boilerplate 42 | class SealedClass { 43 | const SealedClass(); 44 | Iterable get computedFields => 45 | throw NotGenerated('computedFields'); 46 | Iterable get unionFields => 47 | throw NotGenerated('unionFields'); 48 | T valueOf(SealedClassField field) => throw NotGenerated('valueOf'); 49 | bool isSet(SealedClassField field) => throw NotGenerated('isSet'); 50 | } 51 | 52 | /// [DataClassMixin] is used to declare that this mixin is for data classes 53 | class DataClassMixin { 54 | const DataClassMixin(); 55 | } 56 | 57 | /// [SealedClassMixin] is used to declare that this mixin is for sealed classes 58 | class SealedClassMixin { 59 | const SealedClassMixin(); 60 | } 61 | 62 | /// [EnumClassMixin] is used to declare that this mixin is for enum classes 63 | class EnumClassMixin { 64 | const EnumClassMixin(); 65 | } 66 | 67 | /// [MetaTypeMixin] is used to declare that this mixin is for any metatype 68 | class MetaTypeMixin { 69 | const MetaTypeMixin(); 70 | } 71 | 72 | /// [Nullable] is used to represent nullable fields in other union and data 73 | /// classes. Use of nullable is required so one can set a field to null 74 | /// vial the data class's clone method. 75 | class Nullable { 76 | final T _value; 77 | Nullable.val(this._value); 78 | Nullable.nil() : _value = null; 79 | 80 | T get value => _value; 81 | 82 | /// [isNull] retuns true if the [Nullable] represents null 83 | /// i.e. no value is set 84 | bool get isNull => _value == null; 85 | 86 | /// [when] calls the whenNull if the [Nullable] represents null 87 | /// and calls whenValue if the value is set 88 | R when(R whenValue(T value), R whenNull()) { 89 | if (isNull) return whenNull(); 90 | return whenValue(_value); 91 | } 92 | 93 | @override 94 | bool operator ==(dynamic other) { 95 | if (identical(other, this)) return true; 96 | if (other is! Nullable) return false; 97 | return _value == other._value; 98 | } 99 | 100 | @override 101 | int get hashCode { 102 | return $jf($jc(0, _value.hashCode)); 103 | } 104 | } 105 | 106 | /// For use by generated code in calculating hash codes. Do not use directly. 107 | int $jc(int hash, int value) { 108 | // Jenkins hash "combine". 109 | hash = 0x1fffffff & (hash + value); 110 | hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); 111 | return hash ^ (hash >> 6); 112 | } 113 | 114 | /// For use by generated code in calculating hash codes. Do not use directly. 115 | int $jf(int hash) { 116 | // Jenkins hash "finish". 117 | hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); 118 | hash = hash ^ (hash >> 11); 119 | return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); 120 | } 121 | 122 | class NotGenerated implements Exception { 123 | NotGenerated(String message); 124 | } 125 | 126 | class Field { 127 | final String name; 128 | const Field(this.name); 129 | Type get dartType => T; 130 | } 131 | 132 | class DataClassField extends Field { 133 | const DataClassField(String name) : super(name); 134 | } 135 | 136 | class SealedClassField extends Field { 137 | const SealedClassField(String name) : super(name); 138 | } 139 | 140 | class EnumClassField extends Field { 141 | const EnumClassField(String name) : super(name); 142 | } 143 | 144 | class ComputedField extends Field { 145 | const ComputedField(String name) : super(name); 146 | } 147 | -------------------------------------------------------------------------------- /meta_types/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: meta_types 2 | version: 0.1.0 3 | description: 4 | metatypes 5 | authors: 6 | - David Marne 7 | homepage: https://github.com/davidmarne/dart_meta_types/meta_types 8 | 9 | dependencies: 10 | meta: ^1.0.0 11 | 12 | dev_dependencies: 13 | build_runner: ^0.9.0 14 | meta_types_generator: ^0.1.0 15 | 16 | environment: 17 | sdk: '>=2-0-0-dev <3.0.0' 18 | -------------------------------------------------------------------------------- /meta_types_generator/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.1 2 | 3 | * initial builder for union, enum, and data classes -------------------------------------------------------------------------------- /meta_types_generator/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 David Marne 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /meta_types_generator/README.md: -------------------------------------------------------------------------------- 1 | # meta_types_generator 2 | 3 | * Add meta_types_generator and build_runner to your dev_dependencies 4 | * generate code by running `pub run build_runner run` 5 | 6 | See meta_types/example for examples on how to write model definitions. 7 | 8 | ## rules 9 | 10 | * Always use generated classes in code. 11 | * Always use definition classes when referencing other metatypes in your definitions. 12 | * Sealed classes should never extend, only implement others. 13 | * Interfaces cannot have computed accessors. 14 | * Additional functionality can be added to any meta type by generating additional mixins. 15 | -------------------------------------------------------------------------------- /meta_types_generator/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: 3 | implicit-casts: false 4 | implicit-dynamic: false 5 | -------------------------------------------------------------------------------- /meta_types_generator/build.yaml: -------------------------------------------------------------------------------- 1 | targets: 2 | $default: 3 | builders: 4 | meta_types_generator|meta_types: 5 | enabled: true 6 | 7 | builders: 8 | meta_types: 9 | target: ":meta_types_generator" 10 | import: "package:meta_types_generator/builder.dart" 11 | builder_factories: ["metaTypes"] 12 | build_extensions: {".dart": [".meta_types.g.part"]} 13 | auto_apply: dependents 14 | build_to: cache 15 | applies_builders: ["source_gen|combining_builder"] -------------------------------------------------------------------------------- /meta_types_generator/example/example.dart: -------------------------------------------------------------------------------- 1 | /// See meta_types example for code examples. 2 | /// 3 | /// use `pub run build_runner build` to run the generator 4 | /// 5 | /// make sure build_runner and meta_types_generator are 6 | /// dev_dependencies in you pubspec.yaml 7 | -------------------------------------------------------------------------------- /meta_types_generator/lib/builder.dart: -------------------------------------------------------------------------------- 1 | import 'package:build/build.dart'; 2 | import 'package:source_gen/source_gen.dart'; 3 | 4 | import 'src/generator.dart'; 5 | 6 | Builder metaTypes(BuilderOptions options) => 7 | new SharedPartBuilder([new MetaTypesGenerator()], 'meta_types'); 8 | -------------------------------------------------------------------------------- /meta_types_generator/lib/generator_api.dart: -------------------------------------------------------------------------------- 1 | export 'src/generator_util.dart' 2 | show MetaMixin, Field, elementMetaType, MetaTypes; 3 | export 'src/data_class.dart'; 4 | export 'src/enum_class.dart'; 5 | export 'src/sealed_class.dart'; 6 | -------------------------------------------------------------------------------- /meta_types_generator/lib/src/data_class.dart: -------------------------------------------------------------------------------- 1 | import 'package:analyzer/dart/element/element.dart'; 2 | import 'generator_util.dart'; 3 | 4 | final dataClassCache = {}; 5 | 6 | DataClass getDataClass(Element element) { 7 | if (element is! ClassElement) { 8 | throw new Exception('DataClass annotation should only be used on classes'); 9 | } 10 | 11 | final classElement = element as ClassElement; 12 | final genClassName = classElement.name.replaceAll('\$', ''); 13 | final genClassGenerics = classGenerics(classElement); 14 | 15 | // if the data class has already been computed return it 16 | if (dataClassCache[classElement] != null) return dataClassCache[classElement]; 17 | 18 | if (classElement.accessors.any((a) => !a.isGetter || a.isPrivate)) { 19 | throw new Exception('All dataclass accessors should be public getters'); 20 | } 21 | 22 | if (classElement.fields.any((f) => !f.isFinal)) { 23 | throw new Exception('All fields should be final'); 24 | } 25 | 26 | if (classElement.methods.isNotEmpty) { 27 | throw new Exception('No methods should exist.'); 28 | } 29 | 30 | DataClass supertype; 31 | try { 32 | if (classElement.supertype.name != 'Object') { 33 | supertype = getDataClass(classElement.supertype.element); 34 | } 35 | } catch (e) { 36 | throw new Exception( 37 | 'Supertype must be Object or other DataClass.\n Validating supertype raised $e'); 38 | } 39 | 40 | if (supertype != null && supertype.isFinal) { 41 | throw new Exception('Supertype cannot be final.'); 42 | } 43 | 44 | Iterable interfaces; 45 | try { 46 | interfaces = classElement.interfaces.map((i) => getDataClass(i.element)); 47 | } catch (e) { 48 | throw new Exception( 49 | 'Interfaces must be DataClasses. Validating interface raised $e'); 50 | } 51 | 52 | if (interfaces.any((i) => !i.isInterface)) { 53 | throw new Exception('Interfaces must have isInterface set to true.'); 54 | } 55 | 56 | final annotation = 57 | getElementMetaAnnotation(classElement).computeConstantValue(); 58 | final isFinal = annotation.getField('isFinal').toBoolValue(); 59 | final isInterface = annotation.getField('isInterface').toBoolValue(); 60 | final isAbstract = annotation.getField('isAbstract').toBoolValue(); 61 | 62 | final supertypes = []; 63 | var tmpSupertype = supertype; 64 | while (tmpSupertype != null) { 65 | supertypes.add(tmpSupertype); 66 | tmpSupertype = tmpSupertype.supertype; 67 | } 68 | 69 | final mixins = classElement.metadata 70 | .map((m) => m.computeConstantValue()) 71 | .where((c) => c.type.element is ClassElement) 72 | .where((c) => (c.type.element as ClassElement) 73 | .allSupertypes 74 | .any((s) => s.name == 'MetaTypeMixin' || s.name == 'DataClassMixin')) 75 | .map((c) => new MetaMixin(c, '${genClassName}${c.type.element.name}', 76 | baseClassName(genClassName) + genClassGenerics)); 77 | 78 | if (isInterface && mixins.isNotEmpty) { 79 | throw new Exception('Interfaces cannot include mixins'); 80 | } 81 | 82 | if (isAbstract && isFinal) { 83 | throw new Exception('Abstract classes cannot be final.'); 84 | } 85 | 86 | if (isInterface && isFinal) { 87 | throw new Exception('Interfaces cannot be final.'); 88 | } 89 | 90 | final defaultedFields = _defaultedFields(classElement).toSet() 91 | ..addAll(interfaces.expand((st) => st.defaultedFields)); 92 | 93 | final nonDefaultedFields = _nonDefaultedFields(classElement).toSet() 94 | ..addAll(interfaces.expand((st) => st.nonDefaultedFields)); 95 | 96 | final computedFields = _computedFields(classElement).toSet() 97 | ..addAll(interfaces.expand((st) => st.computedFields)); 98 | 99 | final nonComputedFields = _nonComputedFields(classElement).toSet() 100 | ..addAll(interfaces.expand((st) => st.nonComputedFields)); 101 | 102 | if (isInterface && defaultedFields.isNotEmpty) { 103 | throw new Exception('Interfaces cannot have defaulted fields.'); 104 | } 105 | 106 | if (isInterface && computedFields.isNotEmpty) { 107 | throw new Exception('Interfaces cannot have computed fields.'); 108 | } 109 | 110 | final allFields = nonComputedFields.toSet() 111 | ..addAll(interfaces.expand((s) => s.nonComputedFields)) 112 | ..addAll(supertypes.expand((s) => s.nonComputedFields)); 113 | 114 | final dataClass = new DataClass( 115 | classElement, 116 | genClassName, 117 | classElement.name, 118 | baseClassName(genClassName), 119 | genClassGenerics, 120 | supertype, 121 | supertypes, 122 | interfaces, 123 | mixins, 124 | nonComputedFields, 125 | computedFields, 126 | nonDefaultedFields, 127 | defaultedFields, 128 | allFields, 129 | isFinal, 130 | isInterface, 131 | isAbstract, 132 | ); 133 | 134 | dataClassCache[classElement] = dataClass; 135 | return dataClass; 136 | } 137 | 138 | class DataClass { 139 | final ClassElement element; 140 | final String generatedClassName; 141 | final String templateClassName; 142 | final String baseClassName; 143 | final String classGenerics; 144 | final DataClass supertype; 145 | final Iterable supertypes; 146 | final Iterable interfaces; 147 | final Iterable mixins; 148 | final Iterable nonComputedFields; 149 | final Iterable computedFields; 150 | final Iterable nonDefaultedFields; 151 | final Iterable defaultedFields; 152 | final Iterable allFields; // has super fields 153 | final bool isFinal; 154 | final bool isInterface; 155 | final bool isAbstract; 156 | 157 | DataClass( 158 | this.element, 159 | this.generatedClassName, 160 | this.templateClassName, 161 | this.baseClassName, 162 | this.classGenerics, 163 | this.supertype, 164 | this.supertypes, 165 | this.interfaces, 166 | this.mixins, 167 | this.nonComputedFields, 168 | this.computedFields, 169 | this.nonDefaultedFields, 170 | this.defaultedFields, 171 | this.allFields, 172 | this.isFinal, 173 | this.isInterface, 174 | this.isAbstract, 175 | ); 176 | } 177 | 178 | Iterable _defaultedFields(ClassElement e) => 179 | e.accessors.where((m) => !m.isAbstract && !isComputed(m)).map(_toField); 180 | 181 | Iterable _nonDefaultedFields(ClassElement e) => 182 | e.accessors.where((m) => m.isAbstract).map(_toField); 183 | 184 | Iterable _computedFields(ClassElement e) => 185 | e.accessors.where((m) => !m.isAbstract && isComputed(m)).map(_toField); 186 | 187 | Iterable _nonComputedFields(ClassElement e) => 188 | e.accessors.where((m) => !(!m.isAbstract && isComputed(m))).map(_toField); 189 | 190 | Field _toField(PropertyAccessorElement element) => new Field( 191 | element.displayName, 192 | element.returnType, 193 | ); 194 | -------------------------------------------------------------------------------- /meta_types_generator/lib/src/data_class_template.dart: -------------------------------------------------------------------------------- 1 | import 'package:analyzer/dart/element/element.dart'; 2 | import 'generator_util.dart'; 3 | import 'data_class.dart'; 4 | 5 | String generateDataClass(Element e) => _dataClass(getDataClass(e)); 6 | 7 | String _dataClass(DataClass e) => 8 | e.isInterface ? _interface(e) : _classBase(e) + _class(e); 9 | 10 | String _interface(DataClass e) { 11 | var source = e.element.computeNode().toSource(); 12 | source = source.replaceRange( 13 | source.lastIndexOf('}'), 14 | source.lastIndexOf('}') + 1, 15 | _abstractClone(e) + '}', 16 | ); 17 | 18 | // remove annotation 19 | source = source.replaceRange( 20 | source.indexOf('@DataClass'), source.indexOf(')') + 1, ''); 21 | 22 | // change the class name 23 | source = source.replaceFirst(e.templateClassName, e.generatedClassName); 24 | return source; 25 | } 26 | 27 | String _class(DataClass e) => ''' 28 | ${_abstract(e)} class ${e.generatedClassName}${_generics(e)} extends ${e.baseClassName}${_generics(e)} ${_mixins(e)} ${_interfaces(e)} { 29 | ${_genFields(e)} 30 | 31 | ${_constructor(e)} 32 | 33 | ${_clone(e)} 34 | 35 | ${_cloneInterfaces(e)} 36 | 37 | ${_cloneSupertypes(e)} 38 | 39 | ${_getters(e)} 40 | 41 | ${_equality(e)} 42 | 43 | ${_hashCode(e)} 44 | } 45 | '''; 46 | 47 | String _metaImplementations(DataClass e) => """ 48 | @override 49 | Iterable get computedFields => [${_computedFieldsReturnValue(e)}]; 50 | 51 | @override 52 | Iterable get nonDefaultedFields => [${_nonDefaultedFieldsReturnValue(e)}]; 53 | 54 | @override 55 | Iterable get defaultedFields => [${_defaultedFieldsReturnValue(e)}]; 56 | 57 | Iterable _fields; 58 | @override 59 | Iterable get fields => _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 60 | """; 61 | 62 | String _generics(DataClass e) { 63 | return e.element.typeParameters.isEmpty 64 | ? '' 65 | : '<${e.element.typeParameters.map((p) => p.name).join(",")}>'; 66 | } 67 | 68 | String _classBase(DataClass e) { 69 | var source = e.element.computeNode().toSource(); 70 | 71 | // remove annotations 72 | source = source.substring(source.indexOf('abstract class')); 73 | 74 | // change the class name 75 | source = source.replaceFirst(e.templateClassName, e.baseClassName); 76 | source = source.replaceAll('\$', ''); 77 | 78 | if (e.supertype == null && e.interfaces.isEmpty) { 79 | // if there is no supertype make it extend DataClass 80 | source = source.replaceFirst('{', 'extends DataClass {'); 81 | } else if (e.supertype == null && e.interfaces.isNotEmpty) { 82 | source = source.replaceFirst('implements', 'extends DataClass implements'); 83 | } else { 84 | source = source.replaceFirst('{', '{ ${_baseConstructor(e)}'); 85 | } 86 | 87 | final closingBracket = source.lastIndexOf('}'); 88 | source = 89 | source.replaceRange(closingBracket, null, _metaImplementations(e) + '}'); 90 | 91 | // strip generator tokens on interface 92 | return e.interfaces.fold( 93 | source, 94 | (source, interface) => source.replaceFirst( 95 | interface.templateClassName, interface.generatedClassName)); 96 | } 97 | 98 | String _interfaces(DataClass e) => e.interfaces.isEmpty 99 | ? '' 100 | : 'implements ' + e.interfaces.map((i) => i.generatedClassName).join(','); 101 | 102 | String _mixins(DataClass e) => e.mixins.isEmpty 103 | ? '' 104 | : 'with ' + e.mixins.map((m) => m.generatedName).join(','); 105 | 106 | String _abstract(DataClass e) => e.isAbstract ? 'abstract' : ''; 107 | 108 | String _equality(DataClass e) => ''' 109 | @override 110 | bool operator ==(dynamic other) { 111 | if (identical(other, this)) return true; 112 | if (other is! ${e.generatedClassName}) return false; 113 | return ${_equalityFold(e.nonComputedFields)}; 114 | } 115 | '''; 116 | 117 | String _equalityFold(Iterable e) => 118 | e.map((field) => '${field.name} == other.${field.name}').join('&&'); 119 | 120 | String _hashCode(DataClass e) => ''' 121 | @override 122 | int get hashCode { 123 | return \$jf(${_hashFold(e.nonComputedFields)}); 124 | } 125 | '''; 126 | 127 | String _hashFold(Iterable e) => e.fold( 128 | '', 129 | (params, field) => 130 | '\$jc(${params.isNotEmpty ? params : 0}, ${field.name}.hashCode)'); 131 | 132 | String _baseConstructor(DataClass e) => ''' 133 | ${e.baseClassName}( 134 | ${_genConstructorParams(e.supertype)} 135 | ) : super( 136 | ${_superConstructorParams(e)} 137 | );'''; 138 | 139 | String _constructor(DataClass e) => ''' 140 | ${e.generatedClassName}( 141 | ${_genConstructorParams(e)} 142 | ) : ${initializer(e)}, super( 143 | ${_superConstructorParams(e)} 144 | ) { 145 | ${_genNullAssertions(e)} 146 | }'''; 147 | 148 | String _cloneInterfaces(DataClass e) => e.interfaces 149 | .fold('', (combined, next) => '$combined\n${_cloneInterface(e, next)}'); 150 | 151 | String _cloneSupertypes(DataClass e) => e.supertypes 152 | .fold('', (combined, next) => '$combined\n${_cloneSupertype(e, next)}'); 153 | 154 | String _cloneSupertype(DataClass e, DataClass supertype) => e.isAbstract 155 | ? _abstractCloneSupertype(e, supertype) 156 | : _cloneInterface(e, supertype); 157 | 158 | String _cloneInterface(DataClass e, DataClass supertype) { 159 | var params = _genOptionalCloneParams(supertype); 160 | if (params.isNotEmpty) params = '{$params}'; 161 | return ''' 162 | @override 163 | ${e.generatedClassName} clone${supertype.generatedClassName}( 164 | $params 165 | ) => ${_cloneName(e)}( 166 | ${_genCloneInitializer(supertype)} 167 | ); 168 | '''; 169 | } 170 | 171 | String _abstractCloneSupertype(DataClass e, DataClass supertype) { 172 | var params = _genOptionalCloneParams(supertype); 173 | if (params.isNotEmpty) params = '{$params}'; 174 | return ''' 175 | @override 176 | ${e.generatedClassName} clone${supertype.generatedClassName}( 177 | $params 178 | ); 179 | '''; 180 | } 181 | 182 | String _clone(DataClass e) { 183 | var params = _genOptionalCloneParams(e); 184 | if (params.isNotEmpty) params = '{$params}'; 185 | if (e.isInterface || e.isAbstract) 186 | return ''' 187 | ${e.generatedClassName} clone${e.generatedClassName}( 188 | $params 189 | ); 190 | '''; 191 | else 192 | return ''' 193 | ${e.generatedClassName} ${_cloneName(e)}( 194 | $params 195 | ) => new ${e.generatedClassName}${_generics(e)}( 196 | ${_genCloneInitializer(e)} 197 | ); 198 | '''; 199 | } 200 | 201 | String _cloneName(DataClass e) => 202 | e.isFinal ? 'clone' : 'clone${e.generatedClassName}'; 203 | 204 | String _abstractClone(DataClass e) { 205 | var params = _genOptionalCloneParams(e); 206 | if (params.isNotEmpty) params = '{$params}'; 207 | return ''' 208 | ${e.generatedClassName} clone${e.generatedClassName}( 209 | $params 210 | ); 211 | '''; 212 | } 213 | 214 | String _genNullAssertions(DataClass e) => e.nonComputedFields.fold( 215 | '', 216 | (params, field) => 217 | '${params}assert(this.${field.name} != null, "null value provided for field ${field.name}");'); 218 | 219 | String _genCloneInitializer(DataClass e) => e.allFields.fold( 220 | '', 221 | (params, field) => 222 | '${params}${field.name}: ${field.name} ?? _${field.name},'); 223 | 224 | String _genOptionalCloneParams(DataClass e) => e.allFields 225 | .fold('', (params, field) => '${params}${field.typeString} ${field.name},'); 226 | 227 | String _genFields(DataClass e) => 228 | _finalFields(e.nonDefaultedFields) + 229 | _finalFields(e.defaultedFields) + 230 | _variableFields(e.computedFields); 231 | 232 | String _finalFields(Iterable e) => e.fold('', 233 | (params, field) => '${params}final ${field.typeString} _${field.name};'); 234 | 235 | String _variableFields(Iterable e) => e.fold( 236 | '', (params, field) => '${params}${field.typeString} _${field.name};'); 237 | 238 | String _getters(DataClass e) => 239 | _nonDefaulGetters(e.nonDefaultedFields) + 240 | _defaultGetters(e.defaultedFields) + 241 | _memozedGetter(e.computedFields); 242 | 243 | String _nonDefaulGetters(Iterable e) => e.fold( 244 | '', 245 | (params, field) => 246 | '${params}\n@override\n${field.typeString} get ${field.name} => _${field.name};'); 247 | 248 | String _defaultGetters(Iterable e) => e.fold( 249 | '', 250 | (params, field) => 251 | '${params}\n@override\n${field.typeString} get ${field.name} => _${field.name} ?? super.${field.name};'); 252 | 253 | String _memozedGetter(Iterable e) => e.fold( 254 | '', 255 | (params, field) => 256 | '${params}\n@override\n${field.typeString} get ${field.name} => _${field.name} ??= super.${field.name};'); 257 | 258 | String _genConstructorParams(DataClass e) { 259 | final params = _genRequiredConstructorParams(e) + 260 | e.supertypes.fold( 261 | '', (comb, st) => comb + _genRequiredConstructorParams(st)) + 262 | _genOptionalConstructorParams(e) + 263 | e.supertypes.fold( 264 | '', (comb, st) => comb + _genOptionalConstructorParams(st)); 265 | if (params.isEmpty) return params; 266 | return '{$params}'; 267 | } 268 | 269 | String _superConstructorParams(DataClass e) => 270 | e.supertypes.fold('', (comb, st) => comb + _superParams(st)); 271 | 272 | String initializer(DataClass e) { 273 | final optionalParamsInitializers = _genOptionalConstructorInitializer(e); 274 | 275 | if (optionalParamsInitializers.isEmpty) return ''; 276 | return '$optionalParamsInitializers'; 277 | } 278 | 279 | String _superParams(DataClass e) => e.nonComputedFields 280 | .fold('', (params, field) => '${params}${field.name}: ${field.name},'); 281 | 282 | String _genRequiredConstructorParams(DataClass e) => e.nonDefaultedFields.fold( 283 | '', 284 | (params, field) => '${params}@required ${field.typeString} ${field.name},'); 285 | 286 | String _genOptionalConstructorParams(DataClass e) => e.defaultedFields 287 | .fold('', (params, field) => '${params}${field.typeString} ${field.name},'); 288 | 289 | String _genOptionalConstructorInitializer(DataClass e) => e.nonComputedFields 290 | .map((field) => '_${field.name} = ${field.name}') 291 | .join(','); 292 | 293 | String _computedFieldsReturnValue(DataClass e) => 294 | e.computedFields.map(_computedFieldReturnValue).join(','); 295 | String _nonDefaultedFieldsReturnValue(DataClass e) => 296 | e.nonDefaultedFields.map(_fieldReturnValue).join(','); 297 | String _defaultedFieldsReturnValue(DataClass e) => 298 | e.defaultedFields.map(_fieldReturnValue).join(','); 299 | 300 | String _computedFieldReturnValue(Field e) => 301 | 'new ComputedField<${e.typeString}>(\"${e.name}\")'; 302 | String _fieldReturnValue(Field e) => 303 | 'new DataClassField<${e.typeString}>(\"${e.name}\")'; 304 | -------------------------------------------------------------------------------- /meta_types_generator/lib/src/enum_class.dart: -------------------------------------------------------------------------------- 1 | import 'package:analyzer/dart/element/element.dart'; 2 | import 'package:analyzer/dart/element/type.dart'; 3 | import 'generator_util.dart'; 4 | 5 | final enumClassCache = {}; 6 | 7 | EnumClass getEnumClass(Element element) { 8 | if (element is! ClassElement) { 9 | throw Exception('EnumClass annotation should only be used on classes'); 10 | } 11 | 12 | final classElement = element as ClassElement; 13 | final generatedClassName = classElement.name.replaceAll('\$', ''); 14 | 15 | // if the enum class has already been computed return it 16 | if (enumClassCache[classElement] != null) return enumClassCache[classElement]; 17 | 18 | if (classElement.accessors.any((a) => !a.isStatic)) { 19 | throw Exception('Enum class should only contain static fields'); 20 | } 21 | 22 | final staticFields = classElement.fields.where((a) => a.isStatic); 23 | if (staticFields.isEmpty) { 24 | throw Exception('Enum class should contain at least one static field'); 25 | } 26 | 27 | final enumType = getElementMetaAnnotation(classElement) 28 | .computeConstantValue() 29 | .getField('type') 30 | .toTypeValue(); 31 | 32 | if (!staticFields.every((f) => f.type.isSubtypeOf(enumType))) { 33 | throw Exception('Enum class static fields should all be of the same type'); 34 | } 35 | 36 | if (enumType.name != 'int' && 37 | enumType.name != 'String' && 38 | staticFields.any((f) => f.initializer == null)) { 39 | throw Exception( 40 | 'Non int/String enum class fields should all be intialized'); 41 | } 42 | 43 | final mixins = classElement.metadata 44 | .map((m) => m.computeConstantValue()) 45 | .where((c) => c.type.element is ClassElement) 46 | .where((c) => (c.type.element as ClassElement).allSupertypes.any( 47 | (s) => s.name == 'MetaTypeMixin' || s.name == 'SealedClassMixin')) 48 | .map((c) => new MetaMixin( 49 | c, 50 | '${generatedClassName}${c.type.element.name}', 51 | baseClassName(generatedClassName))); 52 | 53 | return EnumClass( 54 | classElement, 55 | generatedClassName, 56 | classElement.name, 57 | baseClassName(generatedClassName), 58 | mixins, 59 | enumType, 60 | enumType.name.toString(), 61 | staticFields.map((f) => Field(f.name, f.type)), 62 | ); 63 | } 64 | 65 | class EnumClass { 66 | final ClassElement element; 67 | final String generatedClassName; 68 | final String templateClassName; 69 | final String baseClassName; 70 | final Iterable mixins; 71 | final DartType type; 72 | final String typeString; 73 | final Iterable fields; 74 | 75 | EnumClass( 76 | this.element, 77 | this.generatedClassName, 78 | this.templateClassName, 79 | this.baseClassName, 80 | this.mixins, 81 | this.type, 82 | this.typeString, 83 | this.fields, 84 | ); 85 | } 86 | -------------------------------------------------------------------------------- /meta_types_generator/lib/src/enum_class_template.dart: -------------------------------------------------------------------------------- 1 | import 'package:analyzer/dart/element/element.dart'; 2 | import 'generator_util.dart'; 3 | import 'enum_class.dart'; 4 | 5 | String generateEnumClass(Element e) => _generateEnumClass(getEnumClass(e)); 6 | 7 | String _generateEnumClass(EnumClass e) => _class(e) + _classBase(e); 8 | 9 | String _classBase(EnumClass e) { 10 | var source = e.element.computeNode().toSource(); 11 | 12 | // remove annotations 13 | source = source.substring(source.indexOf('abstract class')); 14 | 15 | // change the class name 16 | source = source.replaceFirst(e.templateClassName, e.baseClassName); 17 | source = source.replaceAll('\$', ''); 18 | // add the extends clause 19 | source = source.replaceFirst( 20 | '{', 'extends EnumClass<${e.generatedClassName}, ${e.typeString}> {'); 21 | source = source.replaceFirst( 22 | '{', '{ ${e.baseClassName}._(Type type) : super(type);'); 23 | return source; 24 | } 25 | 26 | String _class(EnumClass e) => ''' 27 | class ${e.generatedClassName} extends ${e.baseClassName} ${_mixins(e)} { 28 | final ${e.typeString} _value; 29 | 30 | static final values = Set<${e.generatedClassName}>.from(<${e.generatedClassName}>[ 31 | ${valuesEntries(e)} 32 | ],); 33 | 34 | static ${e.generatedClassName} valueOf(${e.typeString} v) { 35 | ${valuesOfChecks(e)} 36 | return null; 37 | } 38 | 39 | ${e.generatedClassName}._(this._value) : super._(${e.typeString}); 40 | 41 | ${generateEnumClassStaticFields(e)} 42 | 43 | @override 44 | ${e.typeString} get value => _value; 45 | 46 | @override 47 | ${e.generatedClassName} valueOfOther(${e.typeString} v) => ${e.generatedClassName}.valueOf(v); 48 | 49 | @override 50 | Set<${e.generatedClassName}> get allValues => ${e.generatedClassName}.values; 51 | 52 | ${generateEnumClassEquality(e)} 53 | 54 | ${generateEnumClassHashcode(e)} 55 | 56 | ${generateEnumClassToString(e)} 57 | } 58 | '''; 59 | 60 | String generateEnumClassStaticFields(EnumClass e) => e.fields.fold( 61 | '', 62 | (params, field) => 63 | '${params}static final ${e.generatedClassName} ${field.name} = new ${e.generatedClassName}._(${_constructorValue(e, field)});'); 64 | 65 | String _constructorValue(EnumClass e, Field f) { 66 | final redirectedValue = '${e.baseClassName}.${f.name}'; 67 | if (e.typeString == 'int') 68 | return '$redirectedValue ?? ${e.fields.toList().indexOf(f)}'; 69 | if (e.typeString == 'String') return '$redirectedValue ?? \'${f.name}\''; 70 | return redirectedValue; 71 | } 72 | 73 | String valuesEntries(EnumClass e) => e.fields.fold( 74 | '', (params, field) => '$params${e.generatedClassName}.${field.name},'); 75 | 76 | String valuesOfChecks(EnumClass e) => e.fields.fold( 77 | '', 78 | (params, field) => 79 | '${params}if(${e.generatedClassName}.${field.name}.value == v) return ${e.generatedClassName}.${field.name};'); 80 | 81 | String generateEnumClassEquality(EnumClass e) => ''' 82 | @override 83 | bool operator ==(dynamic other) { 84 | if (identical(other, this)) return true; 85 | if (other is! ${e.generatedClassName}) return false; 86 | return value == other.value; 87 | } 88 | '''; 89 | 90 | String generateEnumClassHashcode(EnumClass e) => ''' 91 | @override 92 | int get hashCode { 93 | return \$jf(\$jc(0, value.hashCode)); 94 | } 95 | '''; 96 | 97 | String generateEnumClassToString(EnumClass e) => ''' 98 | @override 99 | String toString() { 100 | ${_generateEnumClassToStringClauses(e)} 101 | return ''; 102 | } 103 | '''; 104 | 105 | String _generateEnumClassToStringClauses(EnumClass e) => e.fields.fold( 106 | '', 107 | (comb, next) => 108 | '${comb}if (this == ${e.generatedClassName}.${next.name}) return \'${e.generatedClassName}.${next.name}: \$_value\';'); 109 | 110 | String generateEnumName(String name) { 111 | if (name.startsWith('_\$')) return name.substring(2); 112 | return name.substring(1); 113 | } 114 | 115 | String _mixins(EnumClass e) => e.mixins.isEmpty 116 | ? '' 117 | : 'with ' + e.mixins.map((m) => m.generatedName).join(','); 118 | -------------------------------------------------------------------------------- /meta_types_generator/lib/src/generator.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:analyzer/dart/element/element.dart'; 3 | import 'package:build/build.dart'; 4 | import 'package:source_gen/source_gen.dart'; 5 | 6 | import 'data_class_template.dart'; 7 | import 'enum_class_template.dart'; 8 | import 'sealed_class_template.dart'; 9 | import 'generator_util.dart'; 10 | 11 | class MetaTypesGenerator extends Generator { 12 | @override 13 | Future generate(LibraryReader library, BuildStep buildStep) async { 14 | final result = new StringBuffer(); 15 | for (final element in library.allElements) { 16 | try { 17 | if (elementHasMetaAnnotation(element)) { 18 | result.write(_generateElement(element)); 19 | } 20 | } catch (e, s) { 21 | log.severe('failed to generate class for ${element.name}. $s', e, s); 22 | } 23 | } 24 | 25 | return result.toString(); 26 | } 27 | 28 | String _generateElement(Element e) { 29 | switch (elementMetaType(e)) { 30 | case MetaTypes.dataClass: 31 | return generateDataClass(e); 32 | break; 33 | case MetaTypes.sealedClass: 34 | return generateSealedClass(e); 35 | break; 36 | case MetaTypes.enumClass: 37 | return generateEnumClass(e); 38 | break; 39 | default: 40 | throw Exception('_generateElement default case hit'); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /meta_types_generator/lib/src/generator_util.dart: -------------------------------------------------------------------------------- 1 | import 'package:analyzer/dart/element/element.dart'; 2 | import 'package:analyzer/dart/constant/value.dart'; 3 | import 'package:meta_types/meta_types.dart' 4 | hide SealedClass, DataClass, EnumClass; 5 | import 'package:analyzer/dart/element/type.dart'; 6 | 7 | enum MetaTypes { 8 | dataClass, 9 | sealedClass, 10 | enumClass, 11 | invalid, 12 | } 13 | 14 | bool elementHasMetaAnnotation(Element e) => 15 | e.metadata.any(isMetaTypesAnnotation); 16 | 17 | ElementAnnotation getElementMetaAnnotation(Element e) => 18 | e.metadata.firstWhere(isMetaTypesAnnotation); 19 | 20 | bool isMetaTypesAnnotation(ElementAnnotation a) { 21 | switch (metaToMetaType(a)) { 22 | case MetaTypes.dataClass: 23 | case MetaTypes.sealedClass: 24 | case MetaTypes.enumClass: 25 | return true; 26 | default: 27 | return false; 28 | } 29 | } 30 | 31 | bool isValidElementName(Element element) => 32 | element.name.startsWith('_\$') || element.name.startsWith('\$'); 33 | 34 | MetaTypes elementMetaType(Element element) => 35 | metaToMetaType(getElementMetaAnnotation(element)); 36 | 37 | MetaTypes metaToMetaType(ElementAnnotation annotation) { 38 | final val = annotation.computeConstantValue(); 39 | switch (val.type.name.toString()) { 40 | case 'DataClass': 41 | return MetaTypes.dataClass; 42 | case 'SealedClass': 43 | return MetaTypes.sealedClass; 44 | case 'EnumClass': 45 | return MetaTypes.enumClass; 46 | default: 47 | return MetaTypes.invalid; 48 | } 49 | } 50 | 51 | String className(ClassElement element) { 52 | final entities = element.computeNode().childEntities.where((e) { 53 | final str = e.toString(); 54 | return !str.startsWith('@') && str != 'class' && str != 'abstract'; 55 | }); 56 | 57 | if (entities.elementAt(1).toString().startsWith('<')) 58 | return entities.elementAt(0).toString() + entities.elementAt(1).toString(); 59 | 60 | return entities.first.toString(); 61 | } 62 | 63 | String stripGeneratorTokens(String name) { 64 | if (name.startsWith('_\$')) return name.substring(2); 65 | if (name.startsWith('\$')) return name.substring(1); 66 | return name; 67 | } 68 | 69 | String capd(String name) => name[0].toUpperCase() + name.substring(1); 70 | 71 | bool isComputed(PropertyAccessorElement method) => method.metadata 72 | .any((meta) => meta.computeConstantValue().toStringValue() == computed); 73 | 74 | class Field { 75 | final DartType dartType; 76 | final String name; 77 | Field(this.name, this.dartType); 78 | 79 | String _typeString; 80 | String get typeString => 81 | _typeString ??= _computeFieldName().replaceAll('\$', ''); 82 | 83 | String _computeFieldName() { 84 | if (dartType is InterfaceType && 85 | (dartType as InterfaceType).typeArguments.isNotEmpty) 86 | return dartType.name + 87 | '<${(dartType as InterfaceType).typeArguments.map((p) => p.name).join(",")}>'; 88 | return dartType.name; 89 | } 90 | 91 | @override 92 | bool operator ==(dynamic other) { 93 | if (identical(other, this)) return true; 94 | if (other is! Field) return false; 95 | return typeString == other.typeString && 96 | name == other.name && 97 | dartType == other.dartType; 98 | } 99 | 100 | @override 101 | int get hashCode { 102 | return $jf($jc($jc(0, name.hashCode), typeString.hashCode)); 103 | } 104 | } 105 | 106 | class MetaMixin { 107 | final DartObject constValue; 108 | final String generatedName; 109 | final String baseClassName; 110 | MetaMixin(this.constValue, this.generatedName, this.baseClassName); 111 | } 112 | 113 | String baseClassName(String name) { 114 | if (!name.startsWith('_')) name = '_$name'; 115 | return '${name}Base'; 116 | } 117 | 118 | String classGenerics(ClassElement e) { 119 | return e.typeParameters.isEmpty 120 | ? '' 121 | : '<${e.typeParameters.map((p) => p.name).join(",")}>'; 122 | } 123 | -------------------------------------------------------------------------------- /meta_types_generator/lib/src/sealed_class.dart: -------------------------------------------------------------------------------- 1 | import 'package:analyzer/dart/element/element.dart'; 2 | import 'generator_util.dart'; 3 | 4 | final sealedClassCache = {}; 5 | 6 | SealedClass getSealedClass(Element element) { 7 | if (element is! ClassElement) { 8 | throw new Exception( 9 | 'SealedClass annotation should only be used on classes'); 10 | } 11 | 12 | final classElement = element as ClassElement; 13 | final genClassName = classElement.name.replaceAll('\$', ''); 14 | final genClassGenerics = classGenerics(classElement); 15 | 16 | // if the data class has already been computed return it 17 | if (sealedClassCache[classElement] != null) 18 | return sealedClassCache[classElement]; 19 | 20 | final mixins = classElement.metadata 21 | .map((m) => m.computeConstantValue()) 22 | .where((c) => c.type.element is ClassElement) 23 | .where((c) => (c.type.element as ClassElement).allSupertypes.any( 24 | (s) => s.name == 'MetaTypeMixin' || s.name == 'SealedClassMixin')) 25 | .map((c) => new MetaMixin(c, '${genClassName}${c.type.element.name}', 26 | baseClassName(genClassName) + genClassGenerics)); 27 | 28 | if (classElement.accessors 29 | .any((a) => !a.isGetter || !a.isAbstract || !a.isPublic)) { 30 | throw new Exception( 31 | 'SealedClass accessors should all be public abstract getters'); 32 | } 33 | 34 | if (classElement.supertype.name != 'Object') { 35 | throw new Exception( 36 | 'SealedClasses cannot extend anything other than Object'); 37 | } 38 | 39 | if (classElement.methods.isNotEmpty) { 40 | throw new Exception('No methods should exist.'); 41 | } 42 | 43 | // raise if there are any interfaces for now 44 | // additional work is required in the template for interface support 45 | if (classElement.interfaces.isNotEmpty) { 46 | throw new Exception('Interfaces not supported for SealedClasses'); 47 | } 48 | 49 | Iterable interfaces; 50 | try { 51 | interfaces = classElement.interfaces.map((i) => getSealedClass(i.element)); 52 | } catch (e) { 53 | throw new Exception( 54 | 'Interfaces must be SealedClasses. Validating interface raised $e'); 55 | } 56 | 57 | final sealedClass = new SealedClass( 58 | classElement, 59 | genClassName, 60 | classElement.name, 61 | baseClassName(genClassName), 62 | genClassGenerics, 63 | mixins, 64 | interfaces, 65 | _computedFields(classElement), 66 | _unionFields(classElement).toSet() 67 | ..addAll(interfaces.expand((i) => i.unionFields)), 68 | ); 69 | 70 | sealedClassCache[classElement] = sealedClass; 71 | return sealedClass; 72 | } 73 | 74 | class SealedClass { 75 | final ClassElement element; 76 | final String generatedClassName; 77 | final String templateClassName; 78 | final String baseClassName; 79 | final String genClassGenerics; 80 | final Iterable mixins; 81 | final Iterable interfaces; 82 | final Iterable computedFields; 83 | final Iterable unionFields; 84 | SealedClass( 85 | this.element, 86 | this.generatedClassName, 87 | this.templateClassName, 88 | this.baseClassName, 89 | this.genClassGenerics, 90 | this.mixins, 91 | this.interfaces, 92 | this.computedFields, 93 | this.unionFields, 94 | ); 95 | } 96 | 97 | Iterable _unionFields(ClassElement e) => 98 | e.accessors.where((m) => m.isAbstract && !isComputed(m)).map(_toField); 99 | 100 | Iterable _computedFields(ClassElement e) => 101 | e.accessors.where((m) => !m.isAbstract && isComputed(m)).map(_toField); 102 | 103 | Field _toField(PropertyAccessorElement element) => new Field( 104 | element.displayName, 105 | element.returnType, 106 | ); 107 | -------------------------------------------------------------------------------- /meta_types_generator/lib/src/sealed_class_template.dart: -------------------------------------------------------------------------------- 1 | import 'package:analyzer/dart/element/element.dart'; 2 | 3 | import 'generator_util.dart'; 4 | import 'sealed_class.dart'; 5 | 6 | String generateSealedClass(Element e) => 7 | _generateSealedClass(getSealedClass(e)); 8 | 9 | String _generateSealedClass(SealedClass e) => _class(e) + _classBase(e); 10 | 11 | String _classBase(SealedClass e) { 12 | var source = e.element.computeNode().toSource(); 13 | 14 | // remove annotations 15 | source = source.substring(source.indexOf('abstract class')); 16 | 17 | // change the class name 18 | source = source.replaceFirst(e.templateClassName, e.baseClassName); 19 | source = source.replaceAll('\$', ''); 20 | 21 | // make it extend SealedClass 22 | if (e.interfaces.isEmpty) { 23 | source = source.replaceFirst('{', 'extends SealedClass {'); 24 | } else { 25 | source = 26 | source.replaceFirst('implements', 'extends SealedClass implements'); 27 | } 28 | 29 | final closingBracket = source.lastIndexOf('}'); 30 | source = source.replaceRange( 31 | closingBracket, 32 | null, 33 | _abstractFieldIsSets(e.unionFields) + 34 | _metaImplementations(e) + 35 | _genAbstractWhen(e) + 36 | '}'); 37 | 38 | // strip generator tokens on interface 39 | return e.interfaces.fold( 40 | source, 41 | (source, interface) => source.replaceFirst( 42 | interface.templateClassName, interface.generatedClassName)); 43 | } 44 | 45 | String _mixins(SealedClass e) => e.mixins.isEmpty 46 | ? '' 47 | : 'with ' + e.mixins.map((m) => m.generatedName).join(','); 48 | 49 | String _class(SealedClass e) => ''' 50 | class ${e.generatedClassName}${_generics(e)} extends ${e.baseClassName}${_generics(e)} ${_mixins(e)} ${_interfaces(e)} { 51 | ${_genFields(e)} 52 | 53 | ${_genConstructors(e)} 54 | 55 | ${_genGetters(e)} 56 | 57 | ${_genWhen(e)} 58 | 59 | ${_genEquality(e)} 60 | 61 | ${_genHashCode(e)} 62 | } 63 | '''; 64 | 65 | String _metaImplementations(SealedClass e) => """ 66 | @override 67 | Iterable get computedFields => [${_computedFieldsReturnValue(e)}]; 68 | 69 | @override 70 | Iterable get unionFields => [${_unionFieldsReturnValue(e)}]; 71 | """; 72 | 73 | String _genWhen(SealedClass e) => ''' 74 | W when({ 75 | ${_genWhenParameters(e)} 76 | }) { 77 | ${_genWhenConditions(e)} 78 | } 79 | '''; 80 | 81 | String _genAbstractWhen(SealedClass e) => ''' 82 | W when({ 83 | ${_genWhenParameters(e)} 84 | }); 85 | '''; 86 | 87 | String _genWhenParameters(SealedClass e) => e.unionFields.fold( 88 | '', 89 | (params, field) => '''$params 90 | @required W ${field.name}(${field.typeString} ${field.name}), 91 | '''); 92 | 93 | String _genWhenConditions(SealedClass e) => e.unionFields.fold( 94 | '', 95 | (params, field) => field == e.unionFields.last 96 | ? '''$params 97 | return ${field.name}(this.${field.name});''' 98 | : '''$params 99 | if (_${field.name}Set) return ${field.name}(this.${field.name});'''); 100 | 101 | String _genEquality(SealedClass e) => ''' 102 | @override 103 | bool operator ==(dynamic other) { 104 | if (identical(other, this)) return true; 105 | if (other is! ${e.generatedClassName}) return false; 106 | return ${_equalityFold(e.unionFields)}; 107 | } 108 | '''; 109 | 110 | String _equalityFold(Iterable e) => 111 | e.map((field) => '${field.name} == other.${field.name}').join('&&'); 112 | 113 | String _genHashCode(SealedClass e) => ''' 114 | @override 115 | int get hashCode { 116 | return \$jf(${_hashFold(e.unionFields)}); 117 | } 118 | '''; 119 | 120 | String _interfaces(SealedClass e) => e.interfaces.isEmpty 121 | ? '' 122 | : 'implements ' + e.interfaces.map((i) => i.generatedClassName).join(','); 123 | 124 | String _hashFold(Iterable e) => e.fold( 125 | '', 126 | (params, field) => 127 | '\$jc(${params.isNotEmpty ? params : 0}, ${field.name}.hashCode)'); 128 | 129 | String _generics(SealedClass e) { 130 | return e.element.typeParameters.isEmpty 131 | ? '' 132 | : '<${e.element.typeParameters.map((p) => p.name).join(",")}>'; 133 | } 134 | 135 | String _genConstructors(SealedClass e) => e.unionFields 136 | .fold('', (params, field) => params + generateUnionConstructor(e, field)); 137 | 138 | String generateUnionConstructor(SealedClass e, Field field) => ''' 139 | ${e.generatedClassName}.${field.name}Factory(this._${field.name}) : 140 | ${_uninitializedInitializers(e, field)} 141 | _${field.name}Set = true; 142 | 143 | '''; 144 | 145 | String _uninitializedInitializers(SealedClass e, Field field) => 146 | e.unionFields.where((f) => f.name != field.name).fold( 147 | '', 148 | (params, f) => f == field 149 | ? '$params' 150 | : '''$params 151 | _${f.name}Set = false, 152 | _${f.name} = null, 153 | '''); 154 | 155 | String _genFields(SealedClass e) => 156 | _finalFields(e.unionFields) + _variableFields(e.computedFields); 157 | 158 | String _finalFields(Iterable e) => e.fold( 159 | '', 160 | (params, field) => '''${params} 161 | final ${field.typeString} _${field.name}; 162 | final bool _${field.name}Set; 163 | '''); 164 | 165 | String _variableFields(Iterable e) => e.fold( 166 | '', (params, field) => '${params}${field.typeString} _${field.name};'); 167 | 168 | String _genGetters(SealedClass e) => 169 | _unionFieldGetters(e.unionFields) + _memozedGetter(e.computedFields); 170 | 171 | String _unionFieldGetters(Iterable e) => e.fold( 172 | '', 173 | (params, field) => '''${params} 174 | ${field.typeString} get ${field.name} => _${field.name}; 175 | bool get ${field.name}Set => _${field.name}Set; 176 | '''); 177 | 178 | String _memozedGetter(Iterable e) => e.fold( 179 | '', 180 | (params, field) => 181 | '${params}${field.typeString} get ${field.name} => _${field.name} ??= super.${field.name};'); 182 | 183 | String _computedFieldsReturnValue(SealedClass e) => 184 | e.computedFields.map(_computedFieldReturnValue).join(','); 185 | String _unionFieldsReturnValue(SealedClass e) => 186 | e.unionFields.map(_fieldReturnValue).join(','); 187 | 188 | String _computedFieldReturnValue(Field e) => 189 | 'new ComputedField<${e.typeString}>(\"${e.name}\")'; 190 | String _fieldReturnValue(Field e) => 191 | 'new SealedClassField<${e.typeString}>(\"${e.name}\")'; 192 | 193 | String _abstractFieldIsSets(Iterable e) => e.fold( 194 | '', 195 | (params, field) => '''${params} 196 | bool get ${field.name}Set; 197 | '''); 198 | -------------------------------------------------------------------------------- /meta_types_generator/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: meta_types_generator 2 | version: 0.1.0 3 | description: 4 | meta_types_generator 5 | authors: 6 | - David Marne 7 | homepage: https://github.com/davidmarne/dart_meta_types/meta_types_generator 8 | 9 | dependencies: 10 | analyzer: ^0.32.0 11 | build: ^0.12.0 12 | source_gen: ^0.9.0 13 | meta_types: ^0.1.0 14 | dev_dependencies: 15 | build_runner: ^0.9.0 16 | build_test: ^0.10.2 17 | test: ^1.0.0 18 | 19 | environment: 20 | sdk: '>=2-0-0-dev <3.0.0' 21 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/data_class_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:test/test.dart'; 2 | 3 | import 'models/models.dart'; 4 | 5 | void main() { 6 | group('dataclass: ', () { 7 | group('field types: ', () { 8 | test('using default', () { 9 | final testFieldWithNoDefault = 9; 10 | final instance = 11 | new TestDataClass(fieldWithNoDefault: testFieldWithNoDefault); 12 | final clone = instance.clone(); 13 | 14 | // test equality & hash override 15 | expect(clone == instance, isTrue); 16 | expect(clone.hashCode == instance.hashCode, isTrue); 17 | 18 | expect(instance.fieldWithNoDefault, testFieldWithNoDefault); 19 | expect(instance.fieldWithDefault, 10); 20 | expect(instance.computedField, 10); 21 | }); 22 | 23 | test('overriding default', () { 24 | final testFieldWithNoDefault = 9; 25 | final testFieldWithDefault = 99; 26 | final instance = new TestDataClass( 27 | fieldWithNoDefault: testFieldWithNoDefault, 28 | fieldWithDefault: testFieldWithDefault); 29 | final clone = instance.clone(); 30 | 31 | // test equality & hash override 32 | expect(clone == instance, isTrue); 33 | expect(clone.hashCode == instance.hashCode, isTrue); 34 | 35 | expect(instance.fieldWithNoDefault, testFieldWithNoDefault); 36 | expect(instance.fieldWithDefault, testFieldWithDefault); 37 | expect(instance.computedField, testFieldWithDefault); 38 | }); 39 | }); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/definitions/b_tree.dart: -------------------------------------------------------------------------------- 1 | part of models; 2 | 3 | // Binary tree is an example of an algebreic data type 4 | // It is the combination of two unions 5 | 6 | @SealedClass() 7 | abstract class $BinaryTree { 8 | T get leaf; 9 | $Branch get branch; 10 | } 11 | 12 | @DataClass() 13 | abstract class $Branch { 14 | T get value; 15 | $BinaryTree get left; 16 | $BinaryTree get right; 17 | } 18 | 19 | String preorderTraversal(BinaryTree tree) => tree.when( 20 | leaf: (val) => '$val', 21 | branch: (b) => [ 22 | '${b.value}', 23 | preorderTraversal(b.left), 24 | preorderTraversal(b.right), 25 | ].join(','), 26 | ); 27 | 28 | final testTree = BinaryTree.branchFactory( 29 | Branch( 30 | value: 1, 31 | left: BinaryTree.branchFactory( 32 | Branch( 33 | value: 2, 34 | left: BinaryTree.leafFactory(3), 35 | right: BinaryTree.leafFactory(4), 36 | ), 37 | ), 38 | right: BinaryTree.leafFactory(5), 39 | ), 40 | ); 41 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/definitions/data_class.dart: -------------------------------------------------------------------------------- 1 | part of models; 2 | 3 | @DataClass() 4 | abstract class $TestDataClass { 5 | int get fieldWithNoDefault; 6 | 7 | int get fieldWithDefault => 10; 8 | 9 | @computed 10 | int get computedField => fieldWithDefault; 11 | } 12 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/definitions/data_class_final.dart: -------------------------------------------------------------------------------- 1 | part of models; 2 | 3 | @DataClass(isFinal: true) 4 | abstract class $FinalDataClass implements $NonFinalInterfaceDataClass { 5 | int get foo; 6 | } 7 | 8 | @DataClass(isInterface: true) 9 | abstract class $NonFinalInterfaceDataClass { 10 | String get bar; 11 | } 12 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/definitions/data_class_generic.dart: -------------------------------------------------------------------------------- 1 | part of models; 2 | 3 | @DataClass() 4 | abstract class $GenericDataClass { 5 | int get foo; 6 | T get bar; 7 | } 8 | 9 | @DataClass() 10 | abstract class $GenericsDataClass { 11 | int get foo; 12 | T get bar; 13 | P get baz; 14 | } 15 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/definitions/data_class_inheritence.dart: -------------------------------------------------------------------------------- 1 | part of models; 2 | 3 | @DataClass() 4 | abstract class $BaseDataClass extends $SuperDataClass 5 | implements $OtherDataClass { 6 | int get foo; 7 | } 8 | 9 | @DataClass(isAbstract: true) 10 | abstract class $SuperDataClass extends $Super2DataClass { 11 | int get bar; 12 | } 13 | 14 | @DataClass(isAbstract: true) 15 | abstract class $Super2DataClass { 16 | String get baz; 17 | } 18 | 19 | @DataClass(isInterface: true) 20 | abstract class $OtherDataClass { 21 | int get other; 22 | } 23 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/definitions/data_class_interfaces.dart: -------------------------------------------------------------------------------- 1 | part of models; 2 | 3 | @DataClass() 4 | abstract class $ImplementorDataClass implements $InterfaceOne, $InterfaceThree { 5 | int get implementor; 6 | } 7 | 8 | @DataClass(isInterface: true) 9 | abstract class $InterfaceOne implements $InterfaceTwo { 10 | int get one; 11 | } 12 | 13 | @DataClass(isInterface: true) 14 | abstract class $InterfaceTwo { 15 | String get two; 16 | } 17 | 18 | @DataClass(isInterface: true) 19 | abstract class $InterfaceThree { 20 | int get three; 21 | } 22 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/definitions/data_class_mixin.dart: -------------------------------------------------------------------------------- 1 | part of models; 2 | 3 | @DCM() 4 | @DataClass() 5 | abstract class $DataClassMixinBase { 6 | int get implementor; 7 | } 8 | 9 | class DCM extends DataClassMixin { 10 | const DCM(); 11 | } 12 | 13 | abstract class DataClassMixinBaseDCM implements _DataClassMixinBaseBase { 14 | void mixinFunction() { 15 | print('successfully mixed in ${implementor}'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/definitions/data_class_nesting.dart: -------------------------------------------------------------------------------- 1 | part of models; 2 | 3 | @DataClass() 4 | abstract class $NestingDataClass { 5 | $NestedDataClass get nested; 6 | $GenericNestedDataClass get genericNested; 7 | } 8 | 9 | @DataClass() 10 | abstract class $NestedDataClass { 11 | String get baz => 'baz'; 12 | } 13 | 14 | @DataClass() 15 | abstract class $GenericNestedDataClass { 16 | T get nested; 17 | } 18 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/definitions/enum_class.dart: -------------------------------------------------------------------------------- 1 | part of models; 2 | 3 | @EnumClass(Signal) 4 | abstract class $ProtocolState { 5 | static const Waiting waiting = Waiting(); 6 | static const Talking talking = Talking(); 7 | } 8 | 9 | abstract class Signal { 10 | ProtocolState get signal; 11 | } 12 | 13 | class Waiting implements Signal { 14 | const Waiting(); 15 | ProtocolState get signal => ProtocolState.waiting; 16 | } 17 | 18 | class Talking implements Signal { 19 | const Talking(); 20 | ProtocolState get signal => ProtocolState.talking; 21 | } 22 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/definitions/enum_class_mixin.dart: -------------------------------------------------------------------------------- 1 | part of models; 2 | 3 | @ECM() 4 | @EnumClass(int) 5 | abstract class $EnumClassMixinBase { 6 | static int a; 7 | static int b; 8 | } 9 | 10 | class ECM extends EnumClassMixin { 11 | const ECM(); 12 | } 13 | 14 | abstract class EnumClassMixinBaseECM implements _EnumClassMixinBaseBase { 15 | void mixinFunction() { 16 | print('successfully mixed in ${value}'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/definitions/enum_double.dart: -------------------------------------------------------------------------------- 1 | part of models; 2 | 3 | @EnumClass(double) 4 | abstract class $DoubleEnum { 5 | static double a = 0.1; 6 | static double b = 0.2; 7 | } 8 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/definitions/enum_int.dart: -------------------------------------------------------------------------------- 1 | part of models; 2 | 3 | @EnumClass(int) 4 | abstract class $IntEnum { 5 | static int a = 7000; 6 | static int b; 7 | } 8 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/definitions/enum_string.dart: -------------------------------------------------------------------------------- 1 | part of models; 2 | 3 | @EnumClass(String) 4 | abstract class $StringEnum { 5 | static String a = 'a'; 6 | static String b; 7 | } 8 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/definitions/sealed_class.dart: -------------------------------------------------------------------------------- 1 | part of models; 2 | 3 | @SealedClass() 4 | abstract class $TestSealedClass { 5 | int get integer; 6 | String get string; 7 | } 8 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/definitions/sealed_class_generics.dart: -------------------------------------------------------------------------------- 1 | part of models; 2 | 3 | @SealedClass() 4 | abstract class $Generic1SealedClass { 5 | T get t; 6 | String get string; 7 | } 8 | 9 | @SealedClass() 10 | abstract class $GenericSealedClass { 11 | T1 get t1; 12 | T2 get t2; 13 | } 14 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/definitions/sealed_class_mixin.dart: -------------------------------------------------------------------------------- 1 | part of models; 2 | 3 | @SCM() 4 | @SealedClass() 5 | abstract class $SealedClassMixinBase { 6 | int get a; 7 | int get b; 8 | } 9 | 10 | class SCM extends SealedClassMixin { 11 | const SCM(); 12 | } 13 | 14 | abstract class SealedClassMixinBaseSCM implements _SealedClassMixinBaseBase { 15 | void mixinFunction() { 16 | print('successfully mixed in ${a}'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/definitions/sealed_class_nesting.dart: -------------------------------------------------------------------------------- 1 | part of models; 2 | 3 | @SealedClass() 4 | abstract class $NestingSealedClass { 5 | int get integer; 6 | $NestedSealedClass get nested; 7 | } 8 | 9 | @SealedClass() 10 | abstract class $NestedSealedClass { 11 | int get integer; 12 | String get string; 13 | } 14 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/models.dart: -------------------------------------------------------------------------------- 1 | library models; 2 | 3 | import 'package:meta_types/meta_types.dart'; 4 | 5 | part 'definitions/b_tree.dart'; 6 | part 'definitions/data_class_generic.dart'; 7 | part 'definitions/data_class_inheritence.dart'; 8 | part 'definitions/data_class_interfaces.dart'; 9 | part 'definitions/data_class_final.dart'; 10 | part 'definitions/data_class_mixin.dart'; 11 | part 'definitions/data_class_nesting.dart'; 12 | part 'definitions/data_class.dart'; 13 | part 'definitions/enum_class.dart'; 14 | part 'definitions/enum_class_mixin.dart'; 15 | part 'definitions/enum_double.dart'; 16 | part 'definitions/enum_int.dart'; 17 | part 'definitions/enum_string.dart'; 18 | part 'definitions/sealed_class_mixin.dart'; 19 | part 'definitions/sealed_class.dart'; 20 | part 'definitions/sealed_class_generics.dart'; 21 | part 'definitions/sealed_class_nesting.dart'; 22 | 23 | part 'models.g.dart'; 24 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/models/models.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of models; 4 | 5 | // ************************************************************************** 6 | // MetaTypesGenerator 7 | // ************************************************************************** 8 | 9 | class BinaryTree extends _BinaryTreeBase { 10 | final T _leaf; 11 | final bool _leafSet; 12 | 13 | final Branch _branch; 14 | final bool _branchSet; 15 | 16 | BinaryTree.leafFactory(this._leaf) 17 | : _branchSet = false, 18 | _branch = null, 19 | _leafSet = true; 20 | 21 | BinaryTree.branchFactory(this._branch) 22 | : _leafSet = false, 23 | _leaf = null, 24 | _branchSet = true; 25 | 26 | T get leaf => _leaf; 27 | bool get leafSet => _leafSet; 28 | 29 | Branch get branch => _branch; 30 | bool get branchSet => _branchSet; 31 | 32 | W when({ 33 | @required W leaf(T leaf), 34 | @required W branch(Branch branch), 35 | }) { 36 | if (_leafSet) return leaf(this.leaf); 37 | return branch(this.branch); 38 | } 39 | 40 | @override 41 | bool operator ==(dynamic other) { 42 | if (identical(other, this)) return true; 43 | if (other is! BinaryTree) return false; 44 | return leaf == other.leaf && branch == other.branch; 45 | } 46 | 47 | @override 48 | int get hashCode { 49 | return $jf($jc($jc(0, leaf.hashCode), branch.hashCode)); 50 | } 51 | } 52 | 53 | abstract class _BinaryTreeBase extends SealedClass { 54 | T get leaf; 55 | Branch get branch; 56 | bool get leafSet; 57 | 58 | bool get branchSet; 59 | @override 60 | Iterable get computedFields => []; 61 | 62 | @override 63 | Iterable get unionFields => [ 64 | new SealedClassField("leaf"), 65 | new SealedClassField>("branch") 66 | ]; 67 | W when({ 68 | @required W leaf(T leaf), 69 | @required W branch(Branch branch), 70 | }); 71 | } 72 | 73 | abstract class _BranchBase extends DataClass { 74 | T get value; 75 | BinaryTree get left; 76 | BinaryTree get right; 77 | @override 78 | Iterable get computedFields => []; 79 | 80 | @override 81 | Iterable get nonDefaultedFields => [ 82 | new DataClassField("value"), 83 | new DataClassField>("left"), 84 | new DataClassField>("right") 85 | ]; 86 | 87 | @override 88 | Iterable get defaultedFields => []; 89 | 90 | Iterable _fields; 91 | @override 92 | Iterable get fields => 93 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 94 | } 95 | 96 | class Branch extends _BranchBase { 97 | final T _value; 98 | final BinaryTree _left; 99 | final BinaryTree _right; 100 | 101 | Branch({ 102 | @required T value, 103 | @required BinaryTree left, 104 | @required BinaryTree right, 105 | }) : _value = value, 106 | _left = left, 107 | _right = right, 108 | super() { 109 | assert(this.value != null, "null value provided for field value"); 110 | assert(this.left != null, "null value provided for field left"); 111 | assert(this.right != null, "null value provided for field right"); 112 | } 113 | 114 | Branch clone({ 115 | T value, 116 | BinaryTree left, 117 | BinaryTree right, 118 | }) => 119 | new Branch( 120 | value: value ?? _value, 121 | left: left ?? _left, 122 | right: right ?? _right, 123 | ); 124 | 125 | @override 126 | T get value => _value; 127 | @override 128 | BinaryTree get left => _left; 129 | @override 130 | BinaryTree get right => _right; 131 | 132 | @override 133 | bool operator ==(dynamic other) { 134 | if (identical(other, this)) return true; 135 | if (other is! Branch) return false; 136 | return value == other.value && left == other.left && right == other.right; 137 | } 138 | 139 | @override 140 | int get hashCode { 141 | return $jf($jc($jc($jc(0, value.hashCode), left.hashCode), right.hashCode)); 142 | } 143 | } 144 | 145 | abstract class _GenericDataClassBase extends DataClass { 146 | int get foo; 147 | T get bar; 148 | @override 149 | Iterable get computedFields => []; 150 | 151 | @override 152 | Iterable get nonDefaultedFields => 153 | [new DataClassField("foo"), new DataClassField("bar")]; 154 | 155 | @override 156 | Iterable get defaultedFields => []; 157 | 158 | Iterable _fields; 159 | @override 160 | Iterable get fields => 161 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 162 | } 163 | 164 | class GenericDataClass extends _GenericDataClassBase { 165 | final int _foo; 166 | final T _bar; 167 | 168 | GenericDataClass({ 169 | @required int foo, 170 | @required T bar, 171 | }) : _foo = foo, 172 | _bar = bar, 173 | super() { 174 | assert(this.foo != null, "null value provided for field foo"); 175 | assert(this.bar != null, "null value provided for field bar"); 176 | } 177 | 178 | GenericDataClass clone({ 179 | int foo, 180 | T bar, 181 | }) => 182 | new GenericDataClass( 183 | foo: foo ?? _foo, 184 | bar: bar ?? _bar, 185 | ); 186 | 187 | @override 188 | int get foo => _foo; 189 | @override 190 | T get bar => _bar; 191 | 192 | @override 193 | bool operator ==(dynamic other) { 194 | if (identical(other, this)) return true; 195 | if (other is! GenericDataClass) return false; 196 | return foo == other.foo && bar == other.bar; 197 | } 198 | 199 | @override 200 | int get hashCode { 201 | return $jf($jc($jc(0, foo.hashCode), bar.hashCode)); 202 | } 203 | } 204 | 205 | abstract class _GenericsDataClassBase extends DataClass { 206 | int get foo; 207 | T get bar; 208 | P get baz; 209 | @override 210 | Iterable get computedFields => []; 211 | 212 | @override 213 | Iterable get nonDefaultedFields => [ 214 | new DataClassField("foo"), 215 | new DataClassField("bar"), 216 | new DataClassField

("baz") 217 | ]; 218 | 219 | @override 220 | Iterable get defaultedFields => []; 221 | 222 | Iterable _fields; 223 | @override 224 | Iterable get fields => 225 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 226 | } 227 | 228 | class GenericsDataClass extends _GenericsDataClassBase { 229 | final int _foo; 230 | final T _bar; 231 | final P _baz; 232 | 233 | GenericsDataClass({ 234 | @required int foo, 235 | @required T bar, 236 | @required P baz, 237 | }) : _foo = foo, 238 | _bar = bar, 239 | _baz = baz, 240 | super() { 241 | assert(this.foo != null, "null value provided for field foo"); 242 | assert(this.bar != null, "null value provided for field bar"); 243 | assert(this.baz != null, "null value provided for field baz"); 244 | } 245 | 246 | GenericsDataClass clone({ 247 | int foo, 248 | T bar, 249 | P baz, 250 | }) => 251 | new GenericsDataClass( 252 | foo: foo ?? _foo, 253 | bar: bar ?? _bar, 254 | baz: baz ?? _baz, 255 | ); 256 | 257 | @override 258 | int get foo => _foo; 259 | @override 260 | T get bar => _bar; 261 | @override 262 | P get baz => _baz; 263 | 264 | @override 265 | bool operator ==(dynamic other) { 266 | if (identical(other, this)) return true; 267 | if (other is! GenericsDataClass) return false; 268 | return foo == other.foo && bar == other.bar && baz == other.baz; 269 | } 270 | 271 | @override 272 | int get hashCode { 273 | return $jf($jc($jc($jc(0, foo.hashCode), bar.hashCode), baz.hashCode)); 274 | } 275 | } 276 | 277 | abstract class _BaseDataClassBase extends SuperDataClass 278 | implements OtherDataClass { 279 | _BaseDataClassBase({ 280 | @required int bar, 281 | @required String baz, 282 | }) : super( 283 | bar: bar, 284 | baz: baz, 285 | ); 286 | int get foo; 287 | @override 288 | Iterable get computedFields => []; 289 | 290 | @override 291 | Iterable get nonDefaultedFields => 292 | [new DataClassField("foo"), new DataClassField("other")]; 293 | 294 | @override 295 | Iterable get defaultedFields => []; 296 | 297 | Iterable _fields; 298 | @override 299 | Iterable get fields => 300 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 301 | } 302 | 303 | class BaseDataClass extends _BaseDataClassBase implements OtherDataClass { 304 | final int _foo; 305 | final int _other; 306 | 307 | BaseDataClass({ 308 | @required int foo, 309 | @required int other, 310 | @required int bar, 311 | @required String baz, 312 | }) : _foo = foo, 313 | _other = other, 314 | super( 315 | bar: bar, 316 | baz: baz, 317 | ) { 318 | assert(this.foo != null, "null value provided for field foo"); 319 | assert(this.other != null, "null value provided for field other"); 320 | } 321 | 322 | BaseDataClass clone({ 323 | int foo, 324 | int other, 325 | int bar, 326 | String baz, 327 | }) => 328 | new BaseDataClass( 329 | foo: foo ?? _foo, 330 | other: other ?? _other, 331 | bar: bar ?? _bar, 332 | baz: baz ?? _baz, 333 | ); 334 | 335 | @override 336 | BaseDataClass cloneOtherDataClass({ 337 | int other, 338 | }) => 339 | clone( 340 | other: other ?? _other, 341 | ); 342 | 343 | @override 344 | BaseDataClass cloneSuperDataClass({ 345 | int bar, 346 | String baz, 347 | }) => 348 | clone( 349 | bar: bar ?? _bar, 350 | baz: baz ?? _baz, 351 | ); 352 | 353 | @override 354 | BaseDataClass cloneSuper2DataClass({ 355 | String baz, 356 | }) => 357 | clone( 358 | baz: baz ?? _baz, 359 | ); 360 | 361 | @override 362 | int get foo => _foo; 363 | @override 364 | int get other => _other; 365 | 366 | @override 367 | bool operator ==(dynamic other) { 368 | if (identical(other, this)) return true; 369 | if (other is! BaseDataClass) return false; 370 | return foo == other.foo && other == other.other; 371 | } 372 | 373 | @override 374 | int get hashCode { 375 | return $jf($jc($jc(0, foo.hashCode), other.hashCode)); 376 | } 377 | } 378 | 379 | abstract class _SuperDataClassBase extends Super2DataClass { 380 | _SuperDataClassBase({ 381 | @required String baz, 382 | }) : super( 383 | baz: baz, 384 | ); 385 | int get bar; 386 | @override 387 | Iterable get computedFields => []; 388 | 389 | @override 390 | Iterable get nonDefaultedFields => 391 | [new DataClassField("bar")]; 392 | 393 | @override 394 | Iterable get defaultedFields => []; 395 | 396 | Iterable _fields; 397 | @override 398 | Iterable get fields => 399 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 400 | } 401 | 402 | abstract class SuperDataClass extends _SuperDataClassBase { 403 | final int _bar; 404 | 405 | SuperDataClass({ 406 | @required int bar, 407 | @required String baz, 408 | }) : _bar = bar, 409 | super( 410 | baz: baz, 411 | ) { 412 | assert(this.bar != null, "null value provided for field bar"); 413 | } 414 | 415 | SuperDataClass cloneSuperDataClass({ 416 | int bar, 417 | String baz, 418 | }); 419 | 420 | @override 421 | SuperDataClass cloneSuper2DataClass({ 422 | String baz, 423 | }); 424 | 425 | @override 426 | int get bar => _bar; 427 | 428 | @override 429 | bool operator ==(dynamic other) { 430 | if (identical(other, this)) return true; 431 | if (other is! SuperDataClass) return false; 432 | return bar == other.bar; 433 | } 434 | 435 | @override 436 | int get hashCode { 437 | return $jf($jc(0, bar.hashCode)); 438 | } 439 | } 440 | 441 | abstract class _Super2DataClassBase extends DataClass { 442 | String get baz; 443 | @override 444 | Iterable get computedFields => []; 445 | 446 | @override 447 | Iterable get nonDefaultedFields => 448 | [new DataClassField("baz")]; 449 | 450 | @override 451 | Iterable get defaultedFields => []; 452 | 453 | Iterable _fields; 454 | @override 455 | Iterable get fields => 456 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 457 | } 458 | 459 | abstract class Super2DataClass extends _Super2DataClassBase { 460 | final String _baz; 461 | 462 | Super2DataClass({ 463 | @required String baz, 464 | }) : _baz = baz, 465 | super() { 466 | assert(this.baz != null, "null value provided for field baz"); 467 | } 468 | 469 | Super2DataClass cloneSuper2DataClass({ 470 | String baz, 471 | }); 472 | 473 | @override 474 | String get baz => _baz; 475 | 476 | @override 477 | bool operator ==(dynamic other) { 478 | if (identical(other, this)) return true; 479 | if (other is! Super2DataClass) return false; 480 | return baz == other.baz; 481 | } 482 | 483 | @override 484 | int get hashCode { 485 | return $jf($jc(0, baz.hashCode)); 486 | } 487 | } 488 | 489 | abstract class OtherDataClass { 490 | int get other; 491 | OtherDataClass cloneOtherDataClass({ 492 | int other, 493 | }); 494 | } 495 | 496 | abstract class _ImplementorDataClassBase extends DataClass 497 | implements InterfaceOne, InterfaceThree { 498 | int get implementor; 499 | @override 500 | Iterable get computedFields => []; 501 | 502 | @override 503 | Iterable get nonDefaultedFields => [ 504 | new DataClassField("implementor"), 505 | new DataClassField("one"), 506 | new DataClassField("two"), 507 | new DataClassField("three") 508 | ]; 509 | 510 | @override 511 | Iterable get defaultedFields => []; 512 | 513 | Iterable _fields; 514 | @override 515 | Iterable get fields => 516 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 517 | } 518 | 519 | class ImplementorDataClass extends _ImplementorDataClassBase 520 | implements InterfaceOne, InterfaceThree { 521 | final int _implementor; 522 | final int _one; 523 | final String _two; 524 | final int _three; 525 | 526 | ImplementorDataClass({ 527 | @required int implementor, 528 | @required int one, 529 | @required String two, 530 | @required int three, 531 | }) : _implementor = implementor, 532 | _one = one, 533 | _two = two, 534 | _three = three, 535 | super() { 536 | assert( 537 | this.implementor != null, "null value provided for field implementor"); 538 | assert(this.one != null, "null value provided for field one"); 539 | assert(this.two != null, "null value provided for field two"); 540 | assert(this.three != null, "null value provided for field three"); 541 | } 542 | 543 | ImplementorDataClass clone({ 544 | int implementor, 545 | int one, 546 | String two, 547 | int three, 548 | }) => 549 | new ImplementorDataClass( 550 | implementor: implementor ?? _implementor, 551 | one: one ?? _one, 552 | two: two ?? _two, 553 | three: three ?? _three, 554 | ); 555 | 556 | @override 557 | ImplementorDataClass cloneInterfaceOne({ 558 | int one, 559 | String two, 560 | }) => 561 | clone( 562 | one: one ?? _one, 563 | two: two ?? _two, 564 | ); 565 | 566 | @override 567 | ImplementorDataClass cloneInterfaceThree({ 568 | int three, 569 | }) => 570 | clone( 571 | three: three ?? _three, 572 | ); 573 | 574 | @override 575 | int get implementor => _implementor; 576 | @override 577 | int get one => _one; 578 | @override 579 | String get two => _two; 580 | @override 581 | int get three => _three; 582 | 583 | @override 584 | bool operator ==(dynamic other) { 585 | if (identical(other, this)) return true; 586 | if (other is! ImplementorDataClass) return false; 587 | return implementor == other.implementor && 588 | one == other.one && 589 | two == other.two && 590 | three == other.three; 591 | } 592 | 593 | @override 594 | int get hashCode { 595 | return $jf($jc( 596 | $jc($jc($jc(0, implementor.hashCode), one.hashCode), two.hashCode), 597 | three.hashCode)); 598 | } 599 | } 600 | 601 | abstract class InterfaceOne implements $InterfaceTwo { 602 | int get one; 603 | InterfaceOne cloneInterfaceOne({ 604 | int one, 605 | String two, 606 | }); 607 | } 608 | 609 | abstract class InterfaceTwo { 610 | String get two; 611 | InterfaceTwo cloneInterfaceTwo({ 612 | String two, 613 | }); 614 | } 615 | 616 | abstract class InterfaceThree { 617 | int get three; 618 | InterfaceThree cloneInterfaceThree({ 619 | int three, 620 | }); 621 | } 622 | 623 | abstract class _FinalDataClassBase extends DataClass 624 | implements NonFinalInterfaceDataClass { 625 | int get foo; 626 | @override 627 | Iterable get computedFields => []; 628 | 629 | @override 630 | Iterable get nonDefaultedFields => 631 | [new DataClassField("foo"), new DataClassField("bar")]; 632 | 633 | @override 634 | Iterable get defaultedFields => []; 635 | 636 | Iterable _fields; 637 | @override 638 | Iterable get fields => 639 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 640 | } 641 | 642 | class FinalDataClass extends _FinalDataClassBase 643 | implements NonFinalInterfaceDataClass { 644 | final int _foo; 645 | final String _bar; 646 | 647 | FinalDataClass({ 648 | @required int foo, 649 | @required String bar, 650 | }) : _foo = foo, 651 | _bar = bar, 652 | super() { 653 | assert(this.foo != null, "null value provided for field foo"); 654 | assert(this.bar != null, "null value provided for field bar"); 655 | } 656 | 657 | FinalDataClass clone({ 658 | int foo, 659 | String bar, 660 | }) => 661 | new FinalDataClass( 662 | foo: foo ?? _foo, 663 | bar: bar ?? _bar, 664 | ); 665 | 666 | @override 667 | FinalDataClass cloneNonFinalInterfaceDataClass({ 668 | String bar, 669 | }) => 670 | clone( 671 | bar: bar ?? _bar, 672 | ); 673 | 674 | @override 675 | int get foo => _foo; 676 | @override 677 | String get bar => _bar; 678 | 679 | @override 680 | bool operator ==(dynamic other) { 681 | if (identical(other, this)) return true; 682 | if (other is! FinalDataClass) return false; 683 | return foo == other.foo && bar == other.bar; 684 | } 685 | 686 | @override 687 | int get hashCode { 688 | return $jf($jc($jc(0, foo.hashCode), bar.hashCode)); 689 | } 690 | } 691 | 692 | abstract class NonFinalInterfaceDataClass { 693 | String get bar; 694 | NonFinalInterfaceDataClass cloneNonFinalInterfaceDataClass({ 695 | String bar, 696 | }); 697 | } 698 | 699 | abstract class _DataClassMixinBaseBase extends DataClass { 700 | int get implementor; 701 | @override 702 | Iterable get computedFields => []; 703 | 704 | @override 705 | Iterable get nonDefaultedFields => 706 | [new DataClassField("implementor")]; 707 | 708 | @override 709 | Iterable get defaultedFields => []; 710 | 711 | Iterable _fields; 712 | @override 713 | Iterable get fields => 714 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 715 | } 716 | 717 | class DataClassMixinBase extends _DataClassMixinBaseBase 718 | with DataClassMixinBaseDCM { 719 | final int _implementor; 720 | 721 | DataClassMixinBase({ 722 | @required int implementor, 723 | }) : _implementor = implementor, 724 | super() { 725 | assert( 726 | this.implementor != null, "null value provided for field implementor"); 727 | } 728 | 729 | DataClassMixinBase clone({ 730 | int implementor, 731 | }) => 732 | new DataClassMixinBase( 733 | implementor: implementor ?? _implementor, 734 | ); 735 | 736 | @override 737 | int get implementor => _implementor; 738 | 739 | @override 740 | bool operator ==(dynamic other) { 741 | if (identical(other, this)) return true; 742 | if (other is! DataClassMixinBase) return false; 743 | return implementor == other.implementor; 744 | } 745 | 746 | @override 747 | int get hashCode { 748 | return $jf($jc(0, implementor.hashCode)); 749 | } 750 | } 751 | 752 | abstract class _NestingDataClassBase extends DataClass { 753 | NestedDataClass get nested; 754 | GenericNestedDataClass get genericNested; 755 | @override 756 | Iterable get computedFields => []; 757 | 758 | @override 759 | Iterable get nonDefaultedFields => [ 760 | new DataClassField("nested"), 761 | new DataClassField>("genericNested") 762 | ]; 763 | 764 | @override 765 | Iterable get defaultedFields => []; 766 | 767 | Iterable _fields; 768 | @override 769 | Iterable get fields => 770 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 771 | } 772 | 773 | class NestingDataClass extends _NestingDataClassBase { 774 | final NestedDataClass _nested; 775 | final GenericNestedDataClass _genericNested; 776 | 777 | NestingDataClass({ 778 | @required NestedDataClass nested, 779 | @required GenericNestedDataClass genericNested, 780 | }) : _nested = nested, 781 | _genericNested = genericNested, 782 | super() { 783 | assert(this.nested != null, "null value provided for field nested"); 784 | assert(this.genericNested != null, 785 | "null value provided for field genericNested"); 786 | } 787 | 788 | NestingDataClass clone({ 789 | NestedDataClass nested, 790 | GenericNestedDataClass genericNested, 791 | }) => 792 | new NestingDataClass( 793 | nested: nested ?? _nested, 794 | genericNested: genericNested ?? _genericNested, 795 | ); 796 | 797 | @override 798 | NestedDataClass get nested => _nested; 799 | @override 800 | GenericNestedDataClass get genericNested => _genericNested; 801 | 802 | @override 803 | bool operator ==(dynamic other) { 804 | if (identical(other, this)) return true; 805 | if (other is! NestingDataClass) return false; 806 | return nested == other.nested && genericNested == other.genericNested; 807 | } 808 | 809 | @override 810 | int get hashCode { 811 | return $jf($jc($jc(0, nested.hashCode), genericNested.hashCode)); 812 | } 813 | } 814 | 815 | abstract class _NestedDataClassBase extends DataClass { 816 | String get baz => 'baz'; 817 | @override 818 | Iterable get computedFields => []; 819 | 820 | @override 821 | Iterable get nonDefaultedFields => []; 822 | 823 | @override 824 | Iterable get defaultedFields => 825 | [new DataClassField("baz")]; 826 | 827 | Iterable _fields; 828 | @override 829 | Iterable get fields => 830 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 831 | } 832 | 833 | class NestedDataClass extends _NestedDataClassBase { 834 | final String _baz; 835 | 836 | NestedDataClass({ 837 | String baz, 838 | }) : _baz = baz, 839 | super() { 840 | assert(this.baz != null, "null value provided for field baz"); 841 | } 842 | 843 | NestedDataClass clone({ 844 | String baz, 845 | }) => 846 | new NestedDataClass( 847 | baz: baz ?? _baz, 848 | ); 849 | 850 | @override 851 | String get baz => _baz ?? super.baz; 852 | 853 | @override 854 | bool operator ==(dynamic other) { 855 | if (identical(other, this)) return true; 856 | if (other is! NestedDataClass) return false; 857 | return baz == other.baz; 858 | } 859 | 860 | @override 861 | int get hashCode { 862 | return $jf($jc(0, baz.hashCode)); 863 | } 864 | } 865 | 866 | abstract class _GenericNestedDataClassBase extends DataClass { 867 | T get nested; 868 | @override 869 | Iterable get computedFields => []; 870 | 871 | @override 872 | Iterable get nonDefaultedFields => 873 | [new DataClassField("nested")]; 874 | 875 | @override 876 | Iterable get defaultedFields => []; 877 | 878 | Iterable _fields; 879 | @override 880 | Iterable get fields => 881 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 882 | } 883 | 884 | class GenericNestedDataClass extends _GenericNestedDataClassBase { 885 | final T _nested; 886 | 887 | GenericNestedDataClass({ 888 | @required T nested, 889 | }) : _nested = nested, 890 | super() { 891 | assert(this.nested != null, "null value provided for field nested"); 892 | } 893 | 894 | GenericNestedDataClass clone({ 895 | T nested, 896 | }) => 897 | new GenericNestedDataClass( 898 | nested: nested ?? _nested, 899 | ); 900 | 901 | @override 902 | T get nested => _nested; 903 | 904 | @override 905 | bool operator ==(dynamic other) { 906 | if (identical(other, this)) return true; 907 | if (other is! GenericNestedDataClass) return false; 908 | return nested == other.nested; 909 | } 910 | 911 | @override 912 | int get hashCode { 913 | return $jf($jc(0, nested.hashCode)); 914 | } 915 | } 916 | 917 | abstract class _TestDataClassBase extends DataClass { 918 | int get fieldWithNoDefault; 919 | int get fieldWithDefault => 10; 920 | @computed 921 | int get computedField => fieldWithDefault; 922 | @override 923 | Iterable get computedFields => 924 | [new ComputedField("computedField")]; 925 | 926 | @override 927 | Iterable get nonDefaultedFields => 928 | [new DataClassField("fieldWithNoDefault")]; 929 | 930 | @override 931 | Iterable get defaultedFields => 932 | [new DataClassField("fieldWithDefault")]; 933 | 934 | Iterable _fields; 935 | @override 936 | Iterable get fields => 937 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 938 | } 939 | 940 | class TestDataClass extends _TestDataClassBase { 941 | final int _fieldWithNoDefault; 942 | final int _fieldWithDefault; 943 | int _computedField; 944 | 945 | TestDataClass({ 946 | @required int fieldWithNoDefault, 947 | int fieldWithDefault, 948 | }) : _fieldWithNoDefault = fieldWithNoDefault, 949 | _fieldWithDefault = fieldWithDefault, 950 | super() { 951 | assert(this.fieldWithNoDefault != null, 952 | "null value provided for field fieldWithNoDefault"); 953 | assert(this.fieldWithDefault != null, 954 | "null value provided for field fieldWithDefault"); 955 | } 956 | 957 | TestDataClass clone({ 958 | int fieldWithNoDefault, 959 | int fieldWithDefault, 960 | }) => 961 | new TestDataClass( 962 | fieldWithNoDefault: fieldWithNoDefault ?? _fieldWithNoDefault, 963 | fieldWithDefault: fieldWithDefault ?? _fieldWithDefault, 964 | ); 965 | 966 | @override 967 | int get fieldWithNoDefault => _fieldWithNoDefault; 968 | @override 969 | int get fieldWithDefault => _fieldWithDefault ?? super.fieldWithDefault; 970 | @override 971 | int get computedField => _computedField ??= super.computedField; 972 | 973 | @override 974 | bool operator ==(dynamic other) { 975 | if (identical(other, this)) return true; 976 | if (other is! TestDataClass) return false; 977 | return fieldWithNoDefault == other.fieldWithNoDefault && 978 | fieldWithDefault == other.fieldWithDefault; 979 | } 980 | 981 | @override 982 | int get hashCode { 983 | return $jf( 984 | $jc($jc(0, fieldWithNoDefault.hashCode), fieldWithDefault.hashCode)); 985 | } 986 | } 987 | 988 | class ProtocolState extends _ProtocolStateBase { 989 | final Signal _value; 990 | 991 | static final values = Set.from( 992 | [ 993 | ProtocolState.waiting, 994 | ProtocolState.talking, 995 | ], 996 | ); 997 | 998 | static ProtocolState valueOf(Signal v) { 999 | if (ProtocolState.waiting.value == v) return ProtocolState.waiting; 1000 | if (ProtocolState.talking.value == v) return ProtocolState.talking; 1001 | return null; 1002 | } 1003 | 1004 | ProtocolState._(this._value) : super._(Signal); 1005 | 1006 | static final ProtocolState waiting = 1007 | new ProtocolState._(_ProtocolStateBase.waiting); 1008 | static final ProtocolState talking = 1009 | new ProtocolState._(_ProtocolStateBase.talking); 1010 | 1011 | @override 1012 | Signal get value => _value; 1013 | 1014 | @override 1015 | ProtocolState valueOfOther(Signal v) => ProtocolState.valueOf(v); 1016 | 1017 | @override 1018 | Set get allValues => ProtocolState.values; 1019 | 1020 | @override 1021 | bool operator ==(dynamic other) { 1022 | if (identical(other, this)) return true; 1023 | if (other is! ProtocolState) return false; 1024 | return value == other.value; 1025 | } 1026 | 1027 | @override 1028 | int get hashCode { 1029 | return $jf($jc(0, value.hashCode)); 1030 | } 1031 | 1032 | @override 1033 | String toString() { 1034 | if (this == ProtocolState.waiting) return 'ProtocolState.waiting: $_value'; 1035 | if (this == ProtocolState.talking) return 'ProtocolState.talking: $_value'; 1036 | return ''; 1037 | } 1038 | } 1039 | 1040 | abstract class _ProtocolStateBase extends EnumClass { 1041 | _ProtocolStateBase._(Type type) : super(type); 1042 | static const Waiting waiting = Waiting(); 1043 | static const Talking talking = Talking(); 1044 | } 1045 | 1046 | class EnumClassMixinBase extends _EnumClassMixinBaseBase { 1047 | final int _value; 1048 | 1049 | static final values = Set.from( 1050 | [ 1051 | EnumClassMixinBase.a, 1052 | EnumClassMixinBase.b, 1053 | ], 1054 | ); 1055 | 1056 | static EnumClassMixinBase valueOf(int v) { 1057 | if (EnumClassMixinBase.a.value == v) return EnumClassMixinBase.a; 1058 | if (EnumClassMixinBase.b.value == v) return EnumClassMixinBase.b; 1059 | return null; 1060 | } 1061 | 1062 | EnumClassMixinBase._(this._value) : super._(int); 1063 | 1064 | static final EnumClassMixinBase a = 1065 | new EnumClassMixinBase._(_EnumClassMixinBaseBase.a ?? 0); 1066 | static final EnumClassMixinBase b = 1067 | new EnumClassMixinBase._(_EnumClassMixinBaseBase.b ?? 1); 1068 | 1069 | @override 1070 | int get value => _value; 1071 | 1072 | @override 1073 | EnumClassMixinBase valueOfOther(int v) => EnumClassMixinBase.valueOf(v); 1074 | 1075 | @override 1076 | Set get allValues => EnumClassMixinBase.values; 1077 | 1078 | @override 1079 | bool operator ==(dynamic other) { 1080 | if (identical(other, this)) return true; 1081 | if (other is! EnumClassMixinBase) return false; 1082 | return value == other.value; 1083 | } 1084 | 1085 | @override 1086 | int get hashCode { 1087 | return $jf($jc(0, value.hashCode)); 1088 | } 1089 | 1090 | @override 1091 | String toString() { 1092 | if (this == EnumClassMixinBase.a) return 'EnumClassMixinBase.a: $_value'; 1093 | if (this == EnumClassMixinBase.b) return 'EnumClassMixinBase.b: $_value'; 1094 | return ''; 1095 | } 1096 | } 1097 | 1098 | abstract class _EnumClassMixinBaseBase 1099 | extends EnumClass { 1100 | _EnumClassMixinBaseBase._(Type type) : super(type); 1101 | static int a; 1102 | static int b; 1103 | } 1104 | 1105 | class DoubleEnum extends _DoubleEnumBase { 1106 | final double _value; 1107 | 1108 | static final values = Set.from( 1109 | [ 1110 | DoubleEnum.a, 1111 | DoubleEnum.b, 1112 | ], 1113 | ); 1114 | 1115 | static DoubleEnum valueOf(double v) { 1116 | if (DoubleEnum.a.value == v) return DoubleEnum.a; 1117 | if (DoubleEnum.b.value == v) return DoubleEnum.b; 1118 | return null; 1119 | } 1120 | 1121 | DoubleEnum._(this._value) : super._(double); 1122 | 1123 | static final DoubleEnum a = new DoubleEnum._(_DoubleEnumBase.a); 1124 | static final DoubleEnum b = new DoubleEnum._(_DoubleEnumBase.b); 1125 | 1126 | @override 1127 | double get value => _value; 1128 | 1129 | @override 1130 | DoubleEnum valueOfOther(double v) => DoubleEnum.valueOf(v); 1131 | 1132 | @override 1133 | Set get allValues => DoubleEnum.values; 1134 | 1135 | @override 1136 | bool operator ==(dynamic other) { 1137 | if (identical(other, this)) return true; 1138 | if (other is! DoubleEnum) return false; 1139 | return value == other.value; 1140 | } 1141 | 1142 | @override 1143 | int get hashCode { 1144 | return $jf($jc(0, value.hashCode)); 1145 | } 1146 | 1147 | @override 1148 | String toString() { 1149 | if (this == DoubleEnum.a) return 'DoubleEnum.a: $_value'; 1150 | if (this == DoubleEnum.b) return 'DoubleEnum.b: $_value'; 1151 | return ''; 1152 | } 1153 | } 1154 | 1155 | abstract class _DoubleEnumBase extends EnumClass { 1156 | _DoubleEnumBase._(Type type) : super(type); 1157 | static double a = 0.1; 1158 | static double b = 0.2; 1159 | } 1160 | 1161 | class IntEnum extends _IntEnumBase { 1162 | final int _value; 1163 | 1164 | static final values = Set.from( 1165 | [ 1166 | IntEnum.a, 1167 | IntEnum.b, 1168 | ], 1169 | ); 1170 | 1171 | static IntEnum valueOf(int v) { 1172 | if (IntEnum.a.value == v) return IntEnum.a; 1173 | if (IntEnum.b.value == v) return IntEnum.b; 1174 | return null; 1175 | } 1176 | 1177 | IntEnum._(this._value) : super._(int); 1178 | 1179 | static final IntEnum a = new IntEnum._(_IntEnumBase.a ?? 0); 1180 | static final IntEnum b = new IntEnum._(_IntEnumBase.b ?? 1); 1181 | 1182 | @override 1183 | int get value => _value; 1184 | 1185 | @override 1186 | IntEnum valueOfOther(int v) => IntEnum.valueOf(v); 1187 | 1188 | @override 1189 | Set get allValues => IntEnum.values; 1190 | 1191 | @override 1192 | bool operator ==(dynamic other) { 1193 | if (identical(other, this)) return true; 1194 | if (other is! IntEnum) return false; 1195 | return value == other.value; 1196 | } 1197 | 1198 | @override 1199 | int get hashCode { 1200 | return $jf($jc(0, value.hashCode)); 1201 | } 1202 | 1203 | @override 1204 | String toString() { 1205 | if (this == IntEnum.a) return 'IntEnum.a: $_value'; 1206 | if (this == IntEnum.b) return 'IntEnum.b: $_value'; 1207 | return ''; 1208 | } 1209 | } 1210 | 1211 | abstract class _IntEnumBase extends EnumClass { 1212 | _IntEnumBase._(Type type) : super(type); 1213 | static int a = 7000; 1214 | static int b; 1215 | } 1216 | 1217 | class StringEnum extends _StringEnumBase { 1218 | final String _value; 1219 | 1220 | static final values = Set.from( 1221 | [ 1222 | StringEnum.a, 1223 | StringEnum.b, 1224 | ], 1225 | ); 1226 | 1227 | static StringEnum valueOf(String v) { 1228 | if (StringEnum.a.value == v) return StringEnum.a; 1229 | if (StringEnum.b.value == v) return StringEnum.b; 1230 | return null; 1231 | } 1232 | 1233 | StringEnum._(this._value) : super._(String); 1234 | 1235 | static final StringEnum a = new StringEnum._(_StringEnumBase.a ?? 'a'); 1236 | static final StringEnum b = new StringEnum._(_StringEnumBase.b ?? 'b'); 1237 | 1238 | @override 1239 | String get value => _value; 1240 | 1241 | @override 1242 | StringEnum valueOfOther(String v) => StringEnum.valueOf(v); 1243 | 1244 | @override 1245 | Set get allValues => StringEnum.values; 1246 | 1247 | @override 1248 | bool operator ==(dynamic other) { 1249 | if (identical(other, this)) return true; 1250 | if (other is! StringEnum) return false; 1251 | return value == other.value; 1252 | } 1253 | 1254 | @override 1255 | int get hashCode { 1256 | return $jf($jc(0, value.hashCode)); 1257 | } 1258 | 1259 | @override 1260 | String toString() { 1261 | if (this == StringEnum.a) return 'StringEnum.a: $_value'; 1262 | if (this == StringEnum.b) return 'StringEnum.b: $_value'; 1263 | return ''; 1264 | } 1265 | } 1266 | 1267 | abstract class _StringEnumBase extends EnumClass { 1268 | _StringEnumBase._(Type type) : super(type); 1269 | static String a = 'a'; 1270 | static String b; 1271 | } 1272 | 1273 | class SealedClassMixinBase extends _SealedClassMixinBaseBase 1274 | with SealedClassMixinBaseSCM { 1275 | final int _a; 1276 | final bool _aSet; 1277 | 1278 | final int _b; 1279 | final bool _bSet; 1280 | 1281 | SealedClassMixinBase.aFactory(this._a) 1282 | : _bSet = false, 1283 | _b = null, 1284 | _aSet = true; 1285 | 1286 | SealedClassMixinBase.bFactory(this._b) 1287 | : _aSet = false, 1288 | _a = null, 1289 | _bSet = true; 1290 | 1291 | int get a => _a; 1292 | bool get aSet => _aSet; 1293 | 1294 | int get b => _b; 1295 | bool get bSet => _bSet; 1296 | 1297 | W when({ 1298 | @required W a(int a), 1299 | @required W b(int b), 1300 | }) { 1301 | if (_aSet) return a(this.a); 1302 | return b(this.b); 1303 | } 1304 | 1305 | @override 1306 | bool operator ==(dynamic other) { 1307 | if (identical(other, this)) return true; 1308 | if (other is! SealedClassMixinBase) return false; 1309 | return a == other.a && b == other.b; 1310 | } 1311 | 1312 | @override 1313 | int get hashCode { 1314 | return $jf($jc($jc(0, a.hashCode), b.hashCode)); 1315 | } 1316 | } 1317 | 1318 | abstract class _SealedClassMixinBaseBase extends SealedClass { 1319 | int get a; 1320 | int get b; 1321 | bool get aSet; 1322 | 1323 | bool get bSet; 1324 | @override 1325 | Iterable get computedFields => []; 1326 | 1327 | @override 1328 | Iterable get unionFields => 1329 | [new SealedClassField("a"), new SealedClassField("b")]; 1330 | W when({ 1331 | @required W a(int a), 1332 | @required W b(int b), 1333 | }); 1334 | } 1335 | 1336 | class TestSealedClass extends _TestSealedClassBase { 1337 | final int _integer; 1338 | final bool _integerSet; 1339 | 1340 | final String _string; 1341 | final bool _stringSet; 1342 | 1343 | TestSealedClass.integerFactory(this._integer) 1344 | : _stringSet = false, 1345 | _string = null, 1346 | _integerSet = true; 1347 | 1348 | TestSealedClass.stringFactory(this._string) 1349 | : _integerSet = false, 1350 | _integer = null, 1351 | _stringSet = true; 1352 | 1353 | int get integer => _integer; 1354 | bool get integerSet => _integerSet; 1355 | 1356 | String get string => _string; 1357 | bool get stringSet => _stringSet; 1358 | 1359 | W when({ 1360 | @required W integer(int integer), 1361 | @required W string(String string), 1362 | }) { 1363 | if (_integerSet) return integer(this.integer); 1364 | return string(this.string); 1365 | } 1366 | 1367 | @override 1368 | bool operator ==(dynamic other) { 1369 | if (identical(other, this)) return true; 1370 | if (other is! TestSealedClass) return false; 1371 | return integer == other.integer && string == other.string; 1372 | } 1373 | 1374 | @override 1375 | int get hashCode { 1376 | return $jf($jc($jc(0, integer.hashCode), string.hashCode)); 1377 | } 1378 | } 1379 | 1380 | abstract class _TestSealedClassBase extends SealedClass { 1381 | int get integer; 1382 | String get string; 1383 | bool get integerSet; 1384 | 1385 | bool get stringSet; 1386 | @override 1387 | Iterable get computedFields => []; 1388 | 1389 | @override 1390 | Iterable get unionFields => [ 1391 | new SealedClassField("integer"), 1392 | new SealedClassField("string") 1393 | ]; 1394 | W when({ 1395 | @required W integer(int integer), 1396 | @required W string(String string), 1397 | }); 1398 | } 1399 | 1400 | class Generic1SealedClass extends _Generic1SealedClassBase { 1401 | final T _t; 1402 | final bool _tSet; 1403 | 1404 | final String _string; 1405 | final bool _stringSet; 1406 | 1407 | Generic1SealedClass.tFactory(this._t) 1408 | : _stringSet = false, 1409 | _string = null, 1410 | _tSet = true; 1411 | 1412 | Generic1SealedClass.stringFactory(this._string) 1413 | : _tSet = false, 1414 | _t = null, 1415 | _stringSet = true; 1416 | 1417 | T get t => _t; 1418 | bool get tSet => _tSet; 1419 | 1420 | String get string => _string; 1421 | bool get stringSet => _stringSet; 1422 | 1423 | W when({ 1424 | @required W t(T t), 1425 | @required W string(String string), 1426 | }) { 1427 | if (_tSet) return t(this.t); 1428 | return string(this.string); 1429 | } 1430 | 1431 | @override 1432 | bool operator ==(dynamic other) { 1433 | if (identical(other, this)) return true; 1434 | if (other is! Generic1SealedClass) return false; 1435 | return t == other.t && string == other.string; 1436 | } 1437 | 1438 | @override 1439 | int get hashCode { 1440 | return $jf($jc($jc(0, t.hashCode), string.hashCode)); 1441 | } 1442 | } 1443 | 1444 | abstract class _Generic1SealedClassBase extends SealedClass { 1445 | T get t; 1446 | String get string; 1447 | bool get tSet; 1448 | 1449 | bool get stringSet; 1450 | @override 1451 | Iterable get computedFields => []; 1452 | 1453 | @override 1454 | Iterable get unionFields => 1455 | [new SealedClassField("t"), new SealedClassField("string")]; 1456 | W when({ 1457 | @required W t(T t), 1458 | @required W string(String string), 1459 | }); 1460 | } 1461 | 1462 | class GenericSealedClass extends _GenericSealedClassBase { 1463 | final T1 _t1; 1464 | final bool _t1Set; 1465 | 1466 | final T2 _t2; 1467 | final bool _t2Set; 1468 | 1469 | GenericSealedClass.t1Factory(this._t1) 1470 | : _t2Set = false, 1471 | _t2 = null, 1472 | _t1Set = true; 1473 | 1474 | GenericSealedClass.t2Factory(this._t2) 1475 | : _t1Set = false, 1476 | _t1 = null, 1477 | _t2Set = true; 1478 | 1479 | T1 get t1 => _t1; 1480 | bool get t1Set => _t1Set; 1481 | 1482 | T2 get t2 => _t2; 1483 | bool get t2Set => _t2Set; 1484 | 1485 | W when({ 1486 | @required W t1(T1 t1), 1487 | @required W t2(T2 t2), 1488 | }) { 1489 | if (_t1Set) return t1(this.t1); 1490 | return t2(this.t2); 1491 | } 1492 | 1493 | @override 1494 | bool operator ==(dynamic other) { 1495 | if (identical(other, this)) return true; 1496 | if (other is! GenericSealedClass) return false; 1497 | return t1 == other.t1 && t2 == other.t2; 1498 | } 1499 | 1500 | @override 1501 | int get hashCode { 1502 | return $jf($jc($jc(0, t1.hashCode), t2.hashCode)); 1503 | } 1504 | } 1505 | 1506 | abstract class _GenericSealedClassBase extends SealedClass { 1507 | T1 get t1; 1508 | T2 get t2; 1509 | bool get t1Set; 1510 | 1511 | bool get t2Set; 1512 | @override 1513 | Iterable get computedFields => []; 1514 | 1515 | @override 1516 | Iterable get unionFields => 1517 | [new SealedClassField("t1"), new SealedClassField("t2")]; 1518 | W when({ 1519 | @required W t1(T1 t1), 1520 | @required W t2(T2 t2), 1521 | }); 1522 | } 1523 | 1524 | class NestingSealedClass extends _NestingSealedClassBase { 1525 | final int _integer; 1526 | final bool _integerSet; 1527 | 1528 | final NestedSealedClass _nested; 1529 | final bool _nestedSet; 1530 | 1531 | NestingSealedClass.integerFactory(this._integer) 1532 | : _nestedSet = false, 1533 | _nested = null, 1534 | _integerSet = true; 1535 | 1536 | NestingSealedClass.nestedFactory(this._nested) 1537 | : _integerSet = false, 1538 | _integer = null, 1539 | _nestedSet = true; 1540 | 1541 | int get integer => _integer; 1542 | bool get integerSet => _integerSet; 1543 | 1544 | NestedSealedClass get nested => _nested; 1545 | bool get nestedSet => _nestedSet; 1546 | 1547 | W when({ 1548 | @required W integer(int integer), 1549 | @required W nested(NestedSealedClass nested), 1550 | }) { 1551 | if (_integerSet) return integer(this.integer); 1552 | return nested(this.nested); 1553 | } 1554 | 1555 | @override 1556 | bool operator ==(dynamic other) { 1557 | if (identical(other, this)) return true; 1558 | if (other is! NestingSealedClass) return false; 1559 | return integer == other.integer && nested == other.nested; 1560 | } 1561 | 1562 | @override 1563 | int get hashCode { 1564 | return $jf($jc($jc(0, integer.hashCode), nested.hashCode)); 1565 | } 1566 | } 1567 | 1568 | abstract class _NestingSealedClassBase extends SealedClass { 1569 | int get integer; 1570 | NestedSealedClass get nested; 1571 | bool get integerSet; 1572 | 1573 | bool get nestedSet; 1574 | @override 1575 | Iterable get computedFields => []; 1576 | 1577 | @override 1578 | Iterable get unionFields => [ 1579 | new SealedClassField("integer"), 1580 | new SealedClassField("nested") 1581 | ]; 1582 | W when({ 1583 | @required W integer(int integer), 1584 | @required W nested(NestedSealedClass nested), 1585 | }); 1586 | } 1587 | 1588 | class NestedSealedClass extends _NestedSealedClassBase { 1589 | final int _integer; 1590 | final bool _integerSet; 1591 | 1592 | final String _string; 1593 | final bool _stringSet; 1594 | 1595 | NestedSealedClass.integerFactory(this._integer) 1596 | : _stringSet = false, 1597 | _string = null, 1598 | _integerSet = true; 1599 | 1600 | NestedSealedClass.stringFactory(this._string) 1601 | : _integerSet = false, 1602 | _integer = null, 1603 | _stringSet = true; 1604 | 1605 | int get integer => _integer; 1606 | bool get integerSet => _integerSet; 1607 | 1608 | String get string => _string; 1609 | bool get stringSet => _stringSet; 1610 | 1611 | W when({ 1612 | @required W integer(int integer), 1613 | @required W string(String string), 1614 | }) { 1615 | if (_integerSet) return integer(this.integer); 1616 | return string(this.string); 1617 | } 1618 | 1619 | @override 1620 | bool operator ==(dynamic other) { 1621 | if (identical(other, this)) return true; 1622 | if (other is! NestedSealedClass) return false; 1623 | return integer == other.integer && string == other.string; 1624 | } 1625 | 1626 | @override 1627 | int get hashCode { 1628 | return $jf($jc($jc(0, integer.hashCode), string.hashCode)); 1629 | } 1630 | } 1631 | 1632 | abstract class _NestedSealedClassBase extends SealedClass { 1633 | int get integer; 1634 | String get string; 1635 | bool get integerSet; 1636 | 1637 | bool get stringSet; 1638 | @override 1639 | Iterable get computedFields => []; 1640 | 1641 | @override 1642 | Iterable get unionFields => [ 1643 | new SealedClassField("integer"), 1644 | new SealedClassField("string") 1645 | ]; 1646 | W when({ 1647 | @required W integer(int integer), 1648 | @required W string(String string), 1649 | }); 1650 | } 1651 | -------------------------------------------------------------------------------- /meta_types_generator/test/unit/union_class_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:test/test.dart'; 2 | 3 | import 'models/models.dart'; 4 | 5 | void main() { 6 | group('Sealed class: ', () { 7 | test('string-int', () { 8 | final testInteger = 9; 9 | final testString = '9'; 10 | final intInstance = new TestSealedClass.integerFactory(testInteger); 11 | final stringInstance = new TestSealedClass.stringFactory(testString); 12 | 13 | // test equality & hash override 14 | expect(intInstance == stringInstance, isFalse); 15 | expect(intInstance.hashCode == stringInstance.hashCode, isFalse); 16 | 17 | final intClone = new TestSealedClass.integerFactory(testInteger); 18 | expect(intInstance == intClone, isTrue); 19 | expect(intInstance.hashCode == intClone.hashCode, isTrue); 20 | 21 | final stringClone = new TestSealedClass.stringFactory(testString); 22 | expect(stringInstance == stringClone, isTrue); 23 | expect(stringInstance.hashCode == stringClone.hashCode, isTrue); 24 | 25 | expect(intInstance.integer, testInteger); 26 | expect(intInstance.integerSet, isTrue); 27 | expect(intInstance.string, isNull); 28 | expect(intInstance.stringSet, isFalse); 29 | 30 | expect(stringInstance.string, testString); 31 | expect(stringInstance.stringSet, isTrue); 32 | expect(stringInstance.integer, isNull); 33 | expect(stringInstance.integerSet, isFalse); 34 | 35 | intInstance.when( 36 | integer: expectAsync1((int v) {}), 37 | string: (String v) => fail('string should not be called'), 38 | ); 39 | 40 | stringInstance.when( 41 | integer: (int v) => fail('int should not be called'), 42 | string: expectAsync1((String v) {}), 43 | ); 44 | }); 45 | 46 | test('nested', () { 47 | final testInteger = 9; 48 | final testString = '9'; 49 | final intInstance = new NestingSealedClass.nestedFactory( 50 | new NestedSealedClass.integerFactory(testInteger), 51 | ); 52 | final stringInstance = new NestingSealedClass.nestedFactory( 53 | new NestedSealedClass.stringFactory(testString), 54 | ); 55 | 56 | // test equality & hash override 57 | expect(intInstance == stringInstance, isFalse); 58 | expect(intInstance.hashCode == stringInstance.hashCode, isFalse); 59 | 60 | final intClone = new NestingSealedClass.nestedFactory( 61 | new NestedSealedClass.integerFactory(testInteger), 62 | ); 63 | expect(intInstance == intClone, isTrue); 64 | expect(intInstance.hashCode == intClone.hashCode, isTrue); 65 | 66 | final stringClone = new NestingSealedClass.nestedFactory( 67 | new NestedSealedClass.stringFactory(testString), 68 | ); 69 | expect(stringInstance == stringClone, isTrue); 70 | expect(stringInstance.hashCode == stringClone.hashCode, isTrue); 71 | 72 | expect(intInstance.nested.integer, testInteger); 73 | expect(intInstance.nested.integerSet, isTrue); 74 | expect(intInstance.nested.string, isNull); 75 | expect(intInstance.nested.stringSet, isFalse); 76 | 77 | expect(stringInstance.nested.string, testString); 78 | expect(stringInstance.nested.stringSet, isTrue); 79 | expect(stringInstance.nested.integer, isNull); 80 | expect(stringInstance.nested.integerSet, isFalse); 81 | 82 | intInstance.nested.when( 83 | integer: expectAsync1((int v) {}), 84 | string: (String v) => fail('string should not be called'), 85 | ); 86 | 87 | stringInstance.nested.when( 88 | integer: (int v) => fail('int should not be called'), 89 | string: expectAsync1((String v) {}), 90 | ); 91 | 92 | final result = stringInstance.when( 93 | integer: (int v) => fail('int should not be called'), 94 | nested: expectAsync1( 95 | (v) => v.when( 96 | integer: (int v) => fail('int should not be called'), 97 | string: expectAsync1((String v) => 5), 98 | ), 99 | ), 100 | ); 101 | 102 | expect(result, 5); 103 | }); 104 | 105 | test('b-tree dfs traversal', () { 106 | expect(preorderTraversal(testTree), '1,2,3,4,5'); 107 | }); 108 | }); 109 | } 110 | -------------------------------------------------------------------------------- /meta_types_json/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.1 2 | 3 | * initial annotations for annotating classes with MetaJson() -------------------------------------------------------------------------------- /meta_types_json/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 David Marne 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /meta_types_json/README.md: -------------------------------------------------------------------------------- 1 | # meta_types_json 2 | 3 | json mixin generation for meta_types -------------------------------------------------------------------------------- /meta_types_json/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: 3 | implicit-casts: false 4 | implicit-dynamic: false 5 | -------------------------------------------------------------------------------- /meta_types_json/example/example.dart: -------------------------------------------------------------------------------- 1 | import 'package:meta_types/meta_types.dart'; 2 | import 'package:meta_types_json/meta_types_json.dart'; 3 | 4 | part 'example.g.dart'; 5 | 6 | @MetaJson() 7 | @EnumClass(int) 8 | abstract class $MyEnum { 9 | static int a; 10 | static int b; 11 | } 12 | 13 | @MetaJson() 14 | @SealedClass() 15 | abstract class $MySealedClass { 16 | String get string; 17 | int get integer; 18 | } 19 | 20 | @MetaJson() 21 | @DataClass() 22 | abstract class $MyDataClass { 23 | int get value => 0; 24 | $NestedObject get nested; 25 | List get list; 26 | Set get st; 27 | Map get map; 28 | List<$NestedObject> get listNested; 29 | Set<$NestedObject> get setNested; 30 | Map get mapNested; 31 | $MyEnum get enumValue; 32 | $MySealedClass get sealed; 33 | } 34 | 35 | @MetaJson() 36 | @DataClass() 37 | abstract class $NestedObject { 38 | int get value => 0; 39 | } 40 | 41 | void main() { 42 | final myObj = MyDataClass( 43 | value: 2, 44 | nested: NestedObject(value: 99), 45 | list: [5], 46 | st: [22222].toSet(), 47 | map: {'sdf': 4}, 48 | listNested: [NestedObject(value: 34)], 49 | setNested: [NestedObject(value: 4)].toSet(), 50 | mapNested: {'sdf': NestedObject(value: 4)}, 51 | sealed: MySealedClass.integerFactory(2), 52 | enumValue: MyEnum.a, 53 | ); 54 | 55 | print('original'); 56 | print(myObj.value); 57 | print(myObj.nested.value); 58 | print(myObj.list); 59 | print(myObj.st); 60 | print(myObj.map); 61 | print(myObj.listNested); 62 | print(myObj.setNested); 63 | print(myObj.mapNested); 64 | print(myObj.sealed); 65 | print(myObj.enumValue); 66 | 67 | final dynamic json = myObj.toJson(); 68 | print('serialized'); 69 | print(json); 70 | 71 | final deserialized = 72 | MyDataClassMetaJson.fromJson(json as Map); 73 | 74 | print('deserialized'); 75 | print(deserialized.value); 76 | print(deserialized.nested.value); 77 | print(deserialized.list); 78 | print(deserialized.st); 79 | print(deserialized.map); 80 | print(deserialized.listNested); 81 | print(deserialized.setNested); 82 | print(deserialized.mapNested); 83 | print(deserialized.sealed); 84 | print(deserialized.enumValue); 85 | } 86 | -------------------------------------------------------------------------------- /meta_types_json/example/example.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'example.dart'; 4 | 5 | // ************************************************************************** 6 | // MetaTypesGenerator 7 | // ************************************************************************** 8 | 9 | class MyEnum extends _MyEnumBase with MyEnumMetaJson { 10 | final int _value; 11 | 12 | static final values = Set.from( 13 | [ 14 | MyEnum.a, 15 | MyEnum.b, 16 | ], 17 | ); 18 | 19 | static MyEnum valueOf(int v) { 20 | if (MyEnum.a.value == v) return MyEnum.a; 21 | if (MyEnum.b.value == v) return MyEnum.b; 22 | return null; 23 | } 24 | 25 | MyEnum._(this._value) : super._(int); 26 | 27 | static final MyEnum a = new MyEnum._(_MyEnumBase.a ?? 0); 28 | static final MyEnum b = new MyEnum._(_MyEnumBase.b ?? 1); 29 | 30 | @override 31 | int get value => _value; 32 | 33 | @override 34 | MyEnum valueOfOther(int v) => MyEnum.valueOf(v); 35 | 36 | @override 37 | Set get allValues => MyEnum.values; 38 | 39 | @override 40 | bool operator ==(dynamic other) { 41 | if (identical(other, this)) return true; 42 | if (other is! MyEnum) return false; 43 | return value == other.value; 44 | } 45 | 46 | @override 47 | int get hashCode { 48 | return $jf($jc(0, value.hashCode)); 49 | } 50 | 51 | @override 52 | String toString() { 53 | if (this == MyEnum.a) return 'MyEnum.a: $_value'; 54 | if (this == MyEnum.b) return 'MyEnum.b: $_value'; 55 | return ''; 56 | } 57 | } 58 | 59 | abstract class _MyEnumBase extends EnumClass { 60 | _MyEnumBase._(Type type) : super(type); 61 | static int a; 62 | static int b; 63 | } 64 | 65 | class MySealedClass extends _MySealedClassBase with MySealedClassMetaJson { 66 | final String _string; 67 | final bool _stringSet; 68 | 69 | final int _integer; 70 | final bool _integerSet; 71 | 72 | MySealedClass.stringFactory(this._string) 73 | : _integerSet = false, 74 | _integer = null, 75 | _stringSet = true; 76 | 77 | MySealedClass.integerFactory(this._integer) 78 | : _stringSet = false, 79 | _string = null, 80 | _integerSet = true; 81 | 82 | String get string => _string; 83 | bool get stringSet => _stringSet; 84 | 85 | int get integer => _integer; 86 | bool get integerSet => _integerSet; 87 | 88 | W when({ 89 | @required W string(String string), 90 | @required W integer(int integer), 91 | }) { 92 | if (_stringSet) return string(this.string); 93 | return integer(this.integer); 94 | } 95 | 96 | @override 97 | bool operator ==(dynamic other) { 98 | if (identical(other, this)) return true; 99 | if (other is! MySealedClass) return false; 100 | return string == other.string && integer == other.integer; 101 | } 102 | 103 | @override 104 | int get hashCode { 105 | return $jf($jc($jc(0, string.hashCode), integer.hashCode)); 106 | } 107 | } 108 | 109 | abstract class _MySealedClassBase extends SealedClass { 110 | String get string; 111 | int get integer; 112 | bool get stringSet; 113 | 114 | bool get integerSet; 115 | @override 116 | Iterable get computedFields => []; 117 | 118 | @override 119 | Iterable get unionFields => [ 120 | new SealedClassField("string"), 121 | new SealedClassField("integer") 122 | ]; 123 | W when({ 124 | @required W string(String string), 125 | @required W integer(int integer), 126 | }); 127 | } 128 | 129 | abstract class _MyDataClassBase extends DataClass { 130 | int get value => 0; 131 | NestedObject get nested; 132 | List get list; 133 | Set get st; 134 | Map get map; 135 | List get listNested; 136 | Set get setNested; 137 | Map get mapNested; 138 | MyEnum get enumValue; 139 | MySealedClass get sealed; 140 | @override 141 | Iterable get computedFields => []; 142 | 143 | @override 144 | Iterable get nonDefaultedFields => [ 145 | new DataClassField("nested"), 146 | new DataClassField>("list"), 147 | new DataClassField>("st"), 148 | new DataClassField>("map"), 149 | new DataClassField>("listNested"), 150 | new DataClassField>("setNested"), 151 | new DataClassField>("mapNested"), 152 | new DataClassField("enumValue"), 153 | new DataClassField("sealed") 154 | ]; 155 | 156 | @override 157 | Iterable get defaultedFields => 158 | [new DataClassField("value")]; 159 | 160 | Iterable _fields; 161 | @override 162 | Iterable get fields => 163 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 164 | } 165 | 166 | class MyDataClass extends _MyDataClassBase with MyDataClassMetaJson { 167 | final NestedObject _nested; 168 | final List _list; 169 | final Set _st; 170 | final Map _map; 171 | final List _listNested; 172 | final Set _setNested; 173 | final Map _mapNested; 174 | final MyEnum _enumValue; 175 | final MySealedClass _sealed; 176 | final int _value; 177 | 178 | MyDataClass({ 179 | @required NestedObject nested, 180 | @required List list, 181 | @required Set st, 182 | @required Map map, 183 | @required List listNested, 184 | @required Set setNested, 185 | @required Map mapNested, 186 | @required MyEnum enumValue, 187 | @required MySealedClass sealed, 188 | int value, 189 | }) : _value = value, 190 | _nested = nested, 191 | _list = list, 192 | _st = st, 193 | _map = map, 194 | _listNested = listNested, 195 | _setNested = setNested, 196 | _mapNested = mapNested, 197 | _enumValue = enumValue, 198 | _sealed = sealed, 199 | super() { 200 | assert(this.value != null, "null value provided for field value"); 201 | assert(this.nested != null, "null value provided for field nested"); 202 | assert(this.list != null, "null value provided for field list"); 203 | assert(this.st != null, "null value provided for field st"); 204 | assert(this.map != null, "null value provided for field map"); 205 | assert(this.listNested != null, "null value provided for field listNested"); 206 | assert(this.setNested != null, "null value provided for field setNested"); 207 | assert(this.mapNested != null, "null value provided for field mapNested"); 208 | assert(this.enumValue != null, "null value provided for field enumValue"); 209 | assert(this.sealed != null, "null value provided for field sealed"); 210 | } 211 | 212 | MyDataClass clone({ 213 | int value, 214 | NestedObject nested, 215 | List list, 216 | Set st, 217 | Map map, 218 | List listNested, 219 | Set setNested, 220 | Map mapNested, 221 | MyEnum enumValue, 222 | MySealedClass sealed, 223 | }) => 224 | new MyDataClass( 225 | value: value ?? _value, 226 | nested: nested ?? _nested, 227 | list: list ?? _list, 228 | st: st ?? _st, 229 | map: map ?? _map, 230 | listNested: listNested ?? _listNested, 231 | setNested: setNested ?? _setNested, 232 | mapNested: mapNested ?? _mapNested, 233 | enumValue: enumValue ?? _enumValue, 234 | sealed: sealed ?? _sealed, 235 | ); 236 | 237 | @override 238 | NestedObject get nested => _nested; 239 | @override 240 | List get list => _list; 241 | @override 242 | Set get st => _st; 243 | @override 244 | Map get map => _map; 245 | @override 246 | List get listNested => _listNested; 247 | @override 248 | Set get setNested => _setNested; 249 | @override 250 | Map get mapNested => _mapNested; 251 | @override 252 | MyEnum get enumValue => _enumValue; 253 | @override 254 | MySealedClass get sealed => _sealed; 255 | @override 256 | int get value => _value ?? super.value; 257 | 258 | @override 259 | bool operator ==(dynamic other) { 260 | if (identical(other, this)) return true; 261 | if (other is! MyDataClass) return false; 262 | return value == other.value && 263 | nested == other.nested && 264 | list == other.list && 265 | st == other.st && 266 | map == other.map && 267 | listNested == other.listNested && 268 | setNested == other.setNested && 269 | mapNested == other.mapNested && 270 | enumValue == other.enumValue && 271 | sealed == other.sealed; 272 | } 273 | 274 | @override 275 | int get hashCode { 276 | return $jf($jc( 277 | $jc( 278 | $jc( 279 | $jc( 280 | $jc( 281 | $jc( 282 | $jc( 283 | $jc( 284 | $jc($jc(0, value.hashCode), 285 | nested.hashCode), 286 | list.hashCode), 287 | st.hashCode), 288 | map.hashCode), 289 | listNested.hashCode), 290 | setNested.hashCode), 291 | mapNested.hashCode), 292 | enumValue.hashCode), 293 | sealed.hashCode)); 294 | } 295 | } 296 | 297 | abstract class _NestedObjectBase extends DataClass { 298 | int get value => 0; 299 | @override 300 | Iterable get computedFields => []; 301 | 302 | @override 303 | Iterable get nonDefaultedFields => []; 304 | 305 | @override 306 | Iterable get defaultedFields => 307 | [new DataClassField("value")]; 308 | 309 | Iterable _fields; 310 | @override 311 | Iterable get fields => 312 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 313 | } 314 | 315 | class NestedObject extends _NestedObjectBase with NestedObjectMetaJson { 316 | final int _value; 317 | 318 | NestedObject({ 319 | int value, 320 | }) : _value = value, 321 | super() { 322 | assert(this.value != null, "null value provided for field value"); 323 | } 324 | 325 | NestedObject clone({ 326 | int value, 327 | }) => 328 | new NestedObject( 329 | value: value ?? _value, 330 | ); 331 | 332 | @override 333 | int get value => _value ?? super.value; 334 | 335 | @override 336 | bool operator ==(dynamic other) { 337 | if (identical(other, this)) return true; 338 | if (other is! NestedObject) return false; 339 | return value == other.value; 340 | } 341 | 342 | @override 343 | int get hashCode { 344 | return $jf($jc(0, value.hashCode)); 345 | } 346 | } 347 | 348 | // ************************************************************************** 349 | // _MetaTypesjsonGenerator 350 | // ************************************************************************** 351 | 352 | abstract class MyEnumMetaJson implements _MyEnumBase, ToJson { 353 | static MyEnum fromJson(dynamic j) => MyEnum.valueOf(j as int); 354 | dynamic toJson() => value; 355 | } 356 | 357 | abstract class MySealedClassMetaJson implements _MySealedClassBase, ToJson { 358 | static MySealedClass fromJson(dynamic j) { 359 | final m = j as Map; 360 | switch (m.keys.first) { 361 | case 'string': 362 | return MySealedClass.stringFactory(m.values.first as String); 363 | case 'integer': 364 | return MySealedClass.integerFactory(m.values.first as int); 365 | default: 366 | throw Exception('invalid key ${m.keys.first}'); 367 | } 368 | } 369 | 370 | dynamic toJson() => when( 371 | string: (v) => {'string': v}, 372 | integer: (v) => {'integer': v}, 373 | ); 374 | } 375 | 376 | abstract class MyDataClassMetaJson implements _MyDataClassBase, ToJson { 377 | static MyDataClass fromJson(dynamic j) { 378 | final m = j as Map; 379 | return MyDataClass( 380 | value: m['value'] as int, 381 | nested: NestedObjectMetaJson.fromJson(m['nested']), 382 | list: List.unmodifiable((m['list'] as List).cast()), 383 | st: Set.from((m['st'] as List).cast().toSet()), 384 | map: Map.unmodifiable( 385 | (m['map'] as Map).cast()), 386 | listNested: List.unmodifiable( 387 | (m['listNested'] as List) 388 | .map((dynamic v) => 389 | NestedObjectMetaJson.fromJson(v as Map)) 390 | .toList()), 391 | setNested: Set.from((m['setNested'] as List) 392 | .map((dynamic v) => 393 | NestedObjectMetaJson.fromJson(v as Map)) 394 | .toSet()), 395 | mapNested: Map.unmodifiable( 396 | Map.fromIterables( 397 | (m['mapNested'] as Map).keys.cast(), 398 | (m['mapNested'] as Map).values.map((dynamic 399 | k) => 400 | NestedObjectMetaJson.fromJson(k as Map)))), 401 | enumValue: MyEnumMetaJson.fromJson(m['enumValue']), 402 | sealed: MySealedClassMetaJson.fromJson(m['sealed']), 403 | ); 404 | } 405 | 406 | dynamic toJson() => { 407 | 'value': $toJson(value), 408 | 'nested': $toJson(nested), 409 | 'list': $toJson(list), 410 | 'st': $toJson(st), 411 | 'map': $toJson(map), 412 | 'listNested': $toJson(listNested), 413 | 'setNested': $toJson(setNested), 414 | 'mapNested': $toJson(mapNested), 415 | 'enumValue': $toJson(enumValue), 416 | 'sealed': $toJson(sealed), 417 | }; 418 | } 419 | 420 | abstract class NestedObjectMetaJson implements _NestedObjectBase, ToJson { 421 | static NestedObject fromJson(dynamic j) { 422 | final m = j as Map; 423 | return NestedObject( 424 | value: m['value'] as int, 425 | ); 426 | } 427 | 428 | dynamic toJson() => { 429 | 'value': $toJson(value), 430 | }; 431 | } 432 | -------------------------------------------------------------------------------- /meta_types_json/lib/meta_types_json.dart: -------------------------------------------------------------------------------- 1 | import 'package:meta_types/meta_types.dart'; 2 | 3 | class MetaJson extends MetaTypeMixin { 4 | const MetaJson(); 5 | } 6 | 7 | abstract class ToJson { 8 | dynamic toJson(); 9 | } 10 | 11 | final $toJson = toJson; 12 | dynamic toJson(dynamic value) { 13 | if (value is ToJson) return value.toJson(); 14 | if (value is DateTime) return value.toIso8601String(); 15 | if (value is Iterable) 16 | return new List.unmodifiable(value.map(toJson)); 17 | if (value is Map) { 18 | var newmap = {}; 19 | for (dynamic k in value.keys) newmap[k] = toJson(value[k]); 20 | return new Map.unmodifiable(newmap); 21 | } 22 | return value; 23 | } 24 | -------------------------------------------------------------------------------- /meta_types_json/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: meta_types_json 2 | version: 0.0.1 3 | description: 4 | meta_types_json 5 | authors: 6 | - David Marne 7 | homepage: https://github.com/davidmarne/dart_meta_types/meta_types_json 8 | 9 | dependencies: 10 | meta: ^1.0.0 11 | meta_types: ^0.1.0 12 | 13 | dev_dependencies: 14 | build_runner: ^0.9.0 15 | meta_types_generator: ^0.1.0 16 | meta_types_json_generator: ^0.0.1 17 | 18 | environment: 19 | sdk: '>=2-0-0-dev <3.0.0' 20 | -------------------------------------------------------------------------------- /meta_types_json_generator/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.1 2 | 3 | * initial generator implementation -------------------------------------------------------------------------------- /meta_types_json_generator/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 David Marne 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /meta_types_json_generator/README.md: -------------------------------------------------------------------------------- 1 | # meta_types_json 2 | 3 | json mixin generation for meta_types -------------------------------------------------------------------------------- /meta_types_json_generator/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: 3 | implicit-casts: false 4 | implicit-dynamic: false 5 | -------------------------------------------------------------------------------- /meta_types_json_generator/build.yaml: -------------------------------------------------------------------------------- 1 | targets: 2 | $default: 3 | builders: 4 | meta_types_json_generator|meta_types_json: 5 | enabled: true 6 | 7 | builders: 8 | meta_types_json: 9 | target: ":meta_types_json_generator" 10 | import: "package:meta_types_json_generator/builder.dart" 11 | builder_factories: ["metaTypesjson"] 12 | build_extensions: {".dart": [".meta_types_json.g.part"]} 13 | auto_apply: dependents 14 | build_to: cache 15 | applies_builders: ["source_gen|combining_builder"] -------------------------------------------------------------------------------- /meta_types_json_generator/example/example.dart: -------------------------------------------------------------------------------- 1 | /// See meta_types_redux example for code examples. 2 | /// 3 | /// use `pub run build_runner build` to run the generator 4 | /// 5 | /// make sure build_runner meta_types_generator, and meta_types_generator_json are 6 | /// dev_dependencies in you pubspec.yaml 7 | -------------------------------------------------------------------------------- /meta_types_json_generator/lib/builder.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:build/build.dart'; 3 | import 'package:source_gen/source_gen.dart'; 4 | import 'package:meta_types_generator/generator_api.dart'; 5 | import 'package:analyzer/dart/element/element.dart'; 6 | import 'package:analyzer/dart/element/type.dart'; 7 | 8 | Builder metaTypesjson(BuilderOptions options) => 9 | new SharedPartBuilder([new _MetaTypesjsonGenerator()], 'meta_types_json'); 10 | 11 | class _MetaTypesjsonGenerator extends Generator { 12 | @override 13 | Future generate(LibraryReader library, BuildStep buildStep) async { 14 | final result = new StringBuffer(); 15 | for (final element in library.allElements) { 16 | try { 17 | if (_elementHasJsonAnnotation(element)) { 18 | result.write(_generateMixin(element)); 19 | } 20 | } catch (e, s) { 21 | log.severe('failed to generate class for ${element.name}. $s', e, s); 22 | } 23 | } 24 | 25 | return result.toString(); 26 | } 27 | 28 | bool _elementHasJsonAnnotation(Element e) => 29 | e.metadata.any((a) => a.computeConstantValue().type.name == 'MetaJson'); 30 | 31 | String _generateMixin(Element e) { 32 | final meta = e.metadata 33 | .firstWhere((a) => a.computeConstantValue().type.name == 'MetaJson') 34 | .computeConstantValue(); 35 | 36 | final metaType = elementMetaType(e); 37 | switch (metaType) { 38 | case MetaTypes.dataClass: 39 | return _dataClass(getDataClass(e), meta.type.name); 40 | case MetaTypes.enumClass: 41 | return _enumClass(getEnumClass(e), meta.type.name); 42 | case MetaTypes.sealedClass: 43 | return _sealedClass(getSealedClass(e), meta.type.name); 44 | default: 45 | throw Exception('invalid meta type'); 46 | } 47 | } 48 | 49 | String _dataClass(DataClass d, String metaTypeName) { 50 | final mixin = 51 | d.mixins.firstWhere((m) => m.constValue.type.name == metaTypeName); 52 | final mixinClassName = mixin.generatedName; 53 | return ''' 54 | abstract class $mixinClassName implements ${mixin.baseClassName}, ToJson { 55 | ${_fromJsonDataClass(d)} 56 | dynamic toJson() => {${_toJsonParams(d)}}; 57 | } 58 | '''; 59 | } 60 | 61 | String _enumClass(EnumClass e, String metaTypeName) { 62 | final mixin = 63 | e.mixins.firstWhere((m) => m.constValue.type.name == metaTypeName); 64 | final mixinClassName = mixin.generatedName; 65 | return ''' 66 | abstract class $mixinClassName implements ${mixin.baseClassName}, ToJson { 67 | ${_fromJsonEnumClass(e)} 68 | dynamic toJson() => value; 69 | } 70 | '''; 71 | } 72 | 73 | String _sealedClass(SealedClass s, String metaTypeName) { 74 | final mixin = 75 | s.mixins.firstWhere((m) => m.constValue.type.name == metaTypeName); 76 | final mixinClassName = mixin.generatedName; 77 | return ''' 78 | abstract class $mixinClassName implements ${mixin.baseClassName}, ToJson { 79 | ${_fromJsonSealedClass(s)} 80 | dynamic toJson() => when( 81 | ${_toJsonSealedFields(s)} 82 | ); 83 | } 84 | '''; 85 | } 86 | 87 | String _fromJsonDataClass(DataClass d) => 88 | '''static ${d.generatedClassName} fromJson(dynamic j) { 89 | final m = j as Map; 90 | return ${d.generatedClassName}(${_genDataClassConstructorInputs(d)}); 91 | }'''; 92 | 93 | String _fromJsonEnumClass(EnumClass d) => 94 | 'static ${d.generatedClassName} fromJson(dynamic j) => ${d.generatedClassName}.valueOf(${_typeCast(d.type, d.typeString, "j")});'; 95 | 96 | String _fromJsonSealedClass(SealedClass d) => 97 | '''static ${d.generatedClassName} fromJson(dynamic j) { 98 | final m = j as Map; 99 | switch (m.keys.first) { 100 | ${_sealedKeysCases(d)} 101 | default: 102 | throw Exception(\'invalid key \${m.keys.first}\'); 103 | } 104 | }'''; 105 | 106 | String _sealedKeysCases(SealedClass d) => d.unionFields.fold( 107 | '', 108 | (comb, f) => 109 | '${comb}case \'${f.name}\': return ${d.generatedClassName}.${f.name}Factory(${_typeCast(f.dartType, f.typeString, "m.values.first")});'); 110 | 111 | String _toJsonSealedFields(SealedClass s) => s.unionFields.fold( 112 | '', 113 | (comb, next) => 114 | '${comb}${next.name}: (v) => {\'${next.name}\': v},'); 115 | 116 | String _genDataClassConstructorInputs(DataClass d) => d.nonComputedFields 117 | .fold('', (comb, f) => '$comb${_genDataClassConstructorInput(f)},'); 118 | 119 | String _genDataClassConstructorInput(Field f) { 120 | final lookup = 'm[\'${f.name}\']'; 121 | return '${f.name}: ${_typeCast(f.dartType, f.typeString, lookup)}'; 122 | } 123 | 124 | String _typeCast(DartType t, String typeString, String value) { 125 | if (typeString.startsWith('List<')) 126 | return '${typeString}.unmodifiable(${_genListCast(t, value)})'; 127 | if (typeString.startsWith('Map<')) 128 | return '${typeString}.unmodifiable(${_genMapCast(t, typeString, value)})'; 129 | if (typeString.startsWith('Set<')) 130 | return '${typeString}.from(${_genSetCast(t, value)})'; 131 | if (_elementHasJsonAnnotation(t.element)) 132 | return '${typeString}MetaJson.fromJson($value)'; 133 | return '$value as ${typeString}'; 134 | } 135 | 136 | // TODO: recursive searches for nested lists/maps/sets 137 | String _genMapCast(DartType t, String typeString, String lookup) { 138 | final args = (t as InterfaceType).typeArguments; 139 | final keyType = args.elementAt(0); 140 | final valueType = args.elementAt(1); 141 | final keyIsMetaType = _elementHasJsonAnnotation(keyType.element); 142 | final valIsMetaType = _elementHasJsonAnnotation(valueType.element); 143 | final keyTypeStr = keyType.name.replaceAll('\$', ''); 144 | final valTypeStr = valueType.name.replaceAll('\$', ''); 145 | if (!keyIsMetaType && !valIsMetaType) 146 | return '($lookup as Map).cast<$keyTypeStr, $valTypeStr>()'; 147 | 148 | String keyParam, valParam; 149 | if (keyIsMetaType) 150 | keyParam = 151 | '($lookup as Map).keys.map((dynamic k) => ${keyTypeStr}MetaJson.fromJson(k as Map))'; 152 | else 153 | keyParam = '($lookup as Map).keys.cast<$keyTypeStr>()'; 154 | 155 | if (valIsMetaType) 156 | valParam = 157 | '($lookup as Map).values.map((dynamic k) => ${valTypeStr}MetaJson.fromJson(k as Map))'; 158 | else 159 | valParam = 160 | '($lookup as Map).values.cast<$valTypeStr>()'; 161 | 162 | return '${typeString}.fromIterables($keyParam, $valParam)'; 163 | } 164 | 165 | // TODO: recursive searches for nested lists/maps/sets 166 | String _genListCast(DartType t, String lookup) { 167 | final typeparam = (t as InterfaceType).typeArguments.elementAt(0); 168 | if (!_elementHasJsonAnnotation(typeparam.element)) 169 | return '($lookup as List).cast<${typeparam.name.replaceAll('\$', '')}>()'; 170 | return '($lookup as List).map((dynamic v) => ${typeparam.name.replaceAll('\$', '')}MetaJson.fromJson(v as Map)).toList()'; 171 | } 172 | 173 | String _genSetCast(DartType t, String lookup) { 174 | final typeparam = (t as InterfaceType).typeArguments.elementAt(0); 175 | if (!_elementHasJsonAnnotation(typeparam.element)) 176 | return '($lookup as List).cast<${typeparam.name.replaceAll('\$', '')}>().toSet()'; 177 | return '($lookup as List).map((dynamic v) => ${typeparam.name.replaceAll('\$', '')}MetaJson.fromJson(v as Map)).toSet()'; 178 | } 179 | 180 | String _toJsonParams(DataClass d) => d.nonComputedFields 181 | .fold('', (comb, f) => '$comb\'${f.name}\': \$toJson(${f.name}),'); 182 | } 183 | -------------------------------------------------------------------------------- /meta_types_json_generator/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: meta_types_json_generator 2 | version: 0.0.1 3 | description: 4 | meta_types_json_generator 5 | authors: 6 | - David Marne 7 | homepage: https://github.com/davidmarne/dart_meta_types/meta_types_json_generator 8 | 9 | dependencies: 10 | meta: ^1.0.0 11 | analyzer: ^0.32.0 12 | build: ^0.12.0 13 | source_gen: ^0.9.0 14 | meta_types: ^0.1.0 15 | meta_types_generator: ^0.1.0 16 | 17 | dev_dependencies: 18 | build_runner: ^0.9.0 19 | 20 | environment: 21 | sdk: '>=2-0-0-dev <3.0.0' 22 | -------------------------------------------------------------------------------- /meta_types_redux/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.1 2 | 3 | * initial annotations for annotating union, enum, and data classes -------------------------------------------------------------------------------- /meta_types_redux/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 David Marne 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /meta_types_redux/README.md: -------------------------------------------------------------------------------- 1 | # meta_types_redux 2 | 3 | An extension of redux.dart that uses meta types to enforce type safety and implement slick reducer/middlware declarations. -------------------------------------------------------------------------------- /meta_types_redux/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: 3 | implicit-casts: false 4 | implicit-dynamic: false 5 | -------------------------------------------------------------------------------- /meta_types_redux/example/example.dart: -------------------------------------------------------------------------------- 1 | import 'package:meta_types/meta_types.dart'; 2 | import 'package:meta_types_redux/meta_types_redux.dart'; 3 | 4 | part 'example.g.dart'; 5 | 6 | @DataClass() 7 | abstract class $Counter { 8 | int get count => 0; 9 | } 10 | 11 | // $Counter tells the generator the state to use for the 12 | // reducer and middlwarehandler code should be of type Counter 13 | @Actions($Counter) 14 | @SealedClass() 15 | abstract class $CounterActions { 16 | int get increment; 17 | int get decrement; 18 | } 19 | 20 | void main() { 21 | final store = MetaTypesStore( 22 | reducer: myReducer, 23 | initialState: Counter(), 24 | metaMiddleware: [myMiddleware], 25 | syncStream: true, 26 | ); 27 | 28 | store.onChange.listen((state) => print(state.count)); 29 | 30 | store.dispatch(CounterActions.incrementFactory(1)); 31 | // increment mw: 1 32 | // 1 33 | store.dispatch(CounterActions.incrementFactory(4)); 34 | // increment mw: 4 35 | // 5 36 | store.dispatch(CounterActions.decrementFactory(1)); 37 | // decrement mw: 1 38 | // 4 39 | } 40 | 41 | final myReducer = (Counter c, CounterActions a) => a.reduce( 42 | c, 43 | increment: _increment, 44 | decrement: _decrement, 45 | ); 46 | 47 | Counter _increment(Counter state, int val) => 48 | state.clone(count: state.count + val); 49 | 50 | Counter _decrement(Counter state, int val) => 51 | state.clone(count: state.count - val); 52 | 53 | final myMiddleware = ( 54 | MiddlewareApi api, 55 | MetaNextDispatcher next, 56 | CounterActions a, 57 | ) => 58 | a.handleMiddleware( 59 | api, 60 | next, 61 | increment: _incrementHandler, 62 | decrement: _decrementHandler, 63 | ); 64 | 65 | void _incrementHandler(MiddlewareApi api, 66 | MetaNextDispatcher next, int val) { 67 | print('increment mw: $val'); 68 | next(); 69 | } 70 | 71 | void _decrementHandler(MiddlewareApi api, 72 | MetaNextDispatcher next, int val) { 73 | print('decrement mw: $val'); 74 | next(); 75 | } 76 | -------------------------------------------------------------------------------- /meta_types_redux/example/example.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'example.dart'; 4 | 5 | // ************************************************************************** 6 | // MetaTypesGenerator 7 | // ************************************************************************** 8 | 9 | abstract class _CounterBase extends DataClass { 10 | int get count => 0; 11 | @override 12 | Iterable get computedFields => []; 13 | 14 | @override 15 | Iterable get nonDefaultedFields => []; 16 | 17 | @override 18 | Iterable get defaultedFields => 19 | [new DataClassField("count")]; 20 | 21 | Iterable _fields; 22 | @override 23 | Iterable get fields => 24 | _fields ??= []..addAll(nonDefaultedFields)..addAll(defaultedFields); 25 | } 26 | 27 | class Counter extends _CounterBase { 28 | final int _count; 29 | 30 | Counter({ 31 | int count, 32 | }) : _count = count, 33 | super() { 34 | assert(this.count != null, "null value provided for field count"); 35 | } 36 | 37 | Counter clone({ 38 | int count, 39 | }) => 40 | new Counter( 41 | count: count ?? _count, 42 | ); 43 | 44 | @override 45 | int get count => _count ?? super.count; 46 | 47 | @override 48 | bool operator ==(dynamic other) { 49 | if (identical(other, this)) return true; 50 | if (other is! Counter) return false; 51 | return count == other.count; 52 | } 53 | 54 | @override 55 | int get hashCode { 56 | return $jf($jc(0, count.hashCode)); 57 | } 58 | } 59 | 60 | class CounterActions extends _CounterActionsBase with CounterActionsActions { 61 | final int _increment; 62 | final bool _incrementSet; 63 | 64 | final int _decrement; 65 | final bool _decrementSet; 66 | 67 | CounterActions.incrementFactory(this._increment) 68 | : _decrementSet = false, 69 | _decrement = null, 70 | _incrementSet = true; 71 | 72 | CounterActions.decrementFactory(this._decrement) 73 | : _incrementSet = false, 74 | _increment = null, 75 | _decrementSet = true; 76 | 77 | int get increment => _increment; 78 | bool get incrementSet => _incrementSet; 79 | 80 | int get decrement => _decrement; 81 | bool get decrementSet => _decrementSet; 82 | 83 | W when({ 84 | @required W increment(int increment), 85 | @required W decrement(int decrement), 86 | }) { 87 | if (_incrementSet) return increment(this.increment); 88 | return decrement(this.decrement); 89 | } 90 | 91 | @override 92 | bool operator ==(dynamic other) { 93 | if (identical(other, this)) return true; 94 | if (other is! CounterActions) return false; 95 | return increment == other.increment && decrement == other.decrement; 96 | } 97 | 98 | @override 99 | int get hashCode { 100 | return $jf($jc($jc(0, increment.hashCode), decrement.hashCode)); 101 | } 102 | } 103 | 104 | abstract class _CounterActionsBase extends SealedClass { 105 | int get increment; 106 | int get decrement; 107 | bool get incrementSet; 108 | 109 | bool get decrementSet; 110 | @override 111 | Iterable get computedFields => []; 112 | 113 | @override 114 | Iterable get unionFields => [ 115 | new SealedClassField("increment"), 116 | new SealedClassField("decrement") 117 | ]; 118 | W when({ 119 | @required W increment(int increment), 120 | @required W decrement(int decrement), 121 | }); 122 | } 123 | 124 | // ************************************************************************** 125 | // _MetaTypesReduxGenerator 126 | // ************************************************************************** 127 | 128 | abstract class CounterActionsActions implements _CounterActionsBase { 129 | Counter reduce( 130 | Counter state, { 131 | @required Counter increment(Counter state, int increment), 132 | @required Counter decrement(Counter state, int decrement), 133 | }) { 134 | if (incrementSet) return increment(state, this.increment); 135 | return decrement(state, this.decrement); 136 | } 137 | 138 | FutureOr handleMiddleware( 139 | MiddlewareApi api, 140 | MetaNextDispatcher next, { 141 | @required 142 | FutureOr increment(MiddlewareApi api, 143 | MetaNextDispatcher next, int increment), 144 | @required 145 | FutureOr decrement(MiddlewareApi api, 146 | MetaNextDispatcher next, int decrement), 147 | }) { 148 | if (incrementSet) return increment(api, next, this.increment); 149 | return decrement(api, next, this.decrement); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /meta_types_redux/lib/meta_types_redux.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:meta/meta.dart'; 3 | import 'package:meta_types/meta_types.dart'; 4 | import 'package:redux/redux.dart'; 5 | export 'package:meta/meta.dart' show required; 6 | export 'dart:async' show FutureOr; 7 | 8 | class Actions extends SealedClassMixin { 9 | final Type stateType; 10 | const Actions(this.stateType); 11 | } 12 | 13 | typedef D MetaReducer( 14 | D state, 15 | A action, 16 | ); 17 | 18 | typedef FutureOr MetaMiddleware( 20 | MiddlewareApi api, 21 | MetaNextDispatcher next, 22 | A action, 23 | ); 24 | 25 | typedef FutureOr MetaNextDispatcher(); 26 | 27 | class MiddlewareApi { 28 | Store _store; 29 | 30 | MiddlewareApi(this._store); 31 | 32 | D getState() => _store.state; 33 | 34 | void dispatch(A a) { 35 | _store.dispatch(a); 36 | } 37 | } 38 | 39 | class MetaTypesStore 40 | extends Store { 41 | MetaTypesStore({ 42 | @required MetaReducer reducer, 43 | D initialState, 44 | List> metaMiddleware: const [], 45 | List> middleware: const [], 46 | bool syncStream: false, 47 | }) : super((D state, dynamic a) => reducer(state, a as A), 48 | initialState: initialState, 49 | middleware: metaMiddleware 50 | .map((mw) => (Store store, dynamic action, 51 | NextDispatcher next) => 52 | mw(MiddlewareApi(store), () => next(action), action as A)) 53 | .toList() 54 | ..addAll(middleware), 55 | syncStream: syncStream, 56 | distinct: true); 57 | 58 | // protect dispatch so users cannot dispatch non meta actions 59 | @override 60 | void dispatch(covariant A a) { 61 | super.dispatch(a); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /meta_types_redux/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: meta_types_redux 2 | version: 0.1.0 3 | description: 4 | meta_types_redux 5 | authors: 6 | - David Marne 7 | homepage: https://github.com/davidmarne/dart_meta_types/meta_types_redux 8 | 9 | dependencies: 10 | meta: ^1.0.0 11 | meta_types: ^0.1.0 12 | redux: ^3.0.0 13 | 14 | dev_dependencies: 15 | build_runner: ^0.9.0 16 | meta_types_generator: ^0.1.0 17 | meta_types_redux_generator: ^0.1.0 18 | 19 | environment: 20 | sdk: '>=2-0-0-dev <3.0.0' 21 | -------------------------------------------------------------------------------- /meta_types_redux_generator/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.1 2 | 3 | * initial annotations for annotating union, enum, and data classes -------------------------------------------------------------------------------- /meta_types_redux_generator/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 David Marne 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /meta_types_redux_generator/README.md: -------------------------------------------------------------------------------- 1 | # meta_types_redux_generator 2 | 3 | The generator for meta_types_redux -------------------------------------------------------------------------------- /meta_types_redux_generator/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: 3 | implicit-casts: false 4 | implicit-dynamic: false 5 | -------------------------------------------------------------------------------- /meta_types_redux_generator/build.yaml: -------------------------------------------------------------------------------- 1 | targets: 2 | $default: 3 | builders: 4 | meta_types_redux_generator|meta_types_redux: 5 | enabled: true 6 | 7 | builders: 8 | meta_types_redux: 9 | target: ":meta_types_redux_generator" 10 | import: "package:meta_types_redux_generator/builder.dart" 11 | builder_factories: ["metaTypesRedux"] 12 | build_extensions: {".dart": [".meta_types_redux.g.part"]} 13 | auto_apply: dependents 14 | build_to: cache 15 | applies_builders: ["source_gen|combining_builder"] -------------------------------------------------------------------------------- /meta_types_redux_generator/example/example.dart: -------------------------------------------------------------------------------- 1 | /// See meta_types_redux example for code examples. 2 | /// 3 | /// use `pub run build_runner build` to run the generator 4 | /// 5 | /// make sure build_runner meta_types_generator, and meta_types_generator_redux are 6 | /// dev_dependencies in you pubspec.yaml 7 | -------------------------------------------------------------------------------- /meta_types_redux_generator/lib/builder.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:build/build.dart'; 3 | import 'package:source_gen/source_gen.dart'; 4 | import 'package:meta_types_generator/generator_api.dart'; 5 | import 'package:analyzer/dart/element/element.dart'; 6 | 7 | Builder metaTypesRedux(BuilderOptions options) => 8 | new SharedPartBuilder([new _MetaTypesReduxGenerator()], 'meta_types_redux'); 9 | 10 | class _MetaTypesReduxGenerator extends Generator { 11 | @override 12 | Future generate(LibraryReader library, BuildStep buildStep) async { 13 | final result = new StringBuffer(); 14 | for (final element in library.allElements) { 15 | try { 16 | if (_elementHasActionsAnnotation(element)) { 17 | result.write(_generateMixin(element)); 18 | } 19 | } catch (e, s) { 20 | log.severe('failed to generate class for ${element.name}. $s', e, s); 21 | } 22 | } 23 | 24 | return result.toString(); 25 | } 26 | 27 | bool _elementHasActionsAnnotation(Element e) => 28 | e.metadata.any((a) => a.computeConstantValue().type.name == 'Actions'); 29 | 30 | String _generateMixin(Element e) { 31 | final meta = e.metadata 32 | .firstWhere((a) => a.computeConstantValue().type.name == 'Actions') 33 | .computeConstantValue(); 34 | 35 | final sealedClass = getSealedClass(e); 36 | final mixin = sealedClass.mixins 37 | .firstWhere((m) => m.constValue.type.name == meta.type.name); 38 | 39 | final stateType = meta.getField('stateType').toTypeValue(); 40 | final stateTypeString = getDataClass(stateType.element).generatedClassName; 41 | final mixinClassName = mixin.generatedName; 42 | return ''' 43 | abstract class $mixinClassName implements ${mixin.baseClassName}{ 44 | ${_genReduce(stateTypeString, sealedClass)} 45 | ${_genMWHandler(stateTypeString, sealedClass.generatedClassName, sealedClass)} 46 | } 47 | '''; 48 | } 49 | 50 | String _genReduce(String stateType, SealedClass e) => ''' 51 | $stateType reduce( 52 | $stateType state,{ 53 | ${_genReduceParameters(stateType, e)} 54 | }) { 55 | ${_genReduceConditions(e)} 56 | } 57 | '''; 58 | 59 | String _genReduceParameters(String stateType, SealedClass e) => 60 | e.unionFields.fold( 61 | '', 62 | (params, field) => '''$params 63 | @required $stateType ${field.name}($stateType state, ${field.typeString} ${field.name}), 64 | '''); 65 | 66 | String _genReduceConditions(SealedClass e) => e.unionFields.fold( 67 | '', 68 | (params, field) => field == e.unionFields.last 69 | ? '''$params 70 | return ${field.name}(state, this.${field.name});''' 71 | : '''$params 72 | if (${field.name}Set) return ${field.name}(state, this.${field.name});'''); 73 | 74 | String _genMWHandler(String stateType, String actionsType, SealedClass e) => 75 | ''' 76 | FutureOr handleMiddleware( 77 | MiddlewareApi<$stateType, $actionsType> api, 78 | MetaNextDispatcher next, { 79 | ${_genMWHandlerParameters(stateType, actionsType, e)} 80 | }) { 81 | ${_genMWHandlerConditions(e)} 82 | } 83 | '''; 84 | 85 | String _genMWHandlerParameters( 86 | String stateType, String actionsType, SealedClass e) => 87 | e.unionFields.fold( 88 | '', 89 | (params, field) => '''$params 90 | @required FutureOr ${field.name}(MiddlewareApi<$stateType, $actionsType> api, MetaNextDispatcher next, ${field.typeString} ${field.name}), 91 | '''); 92 | 93 | String _genMWHandlerConditions(SealedClass e) => e.unionFields.fold( 94 | '', 95 | (params, field) => field == e.unionFields.last 96 | ? '''$params 97 | return ${field.name}(api, next, this.${field.name});''' 98 | : '''$params 99 | if (${field.name}Set) return ${field.name}(api, next, this.${field.name});'''); 100 | } 101 | -------------------------------------------------------------------------------- /meta_types_redux_generator/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: meta_types_redux_generator 2 | version: 0.1.0 3 | description: 4 | meta_types_redux_generator 5 | authors: 6 | - David Marne 7 | homepage: https://github.com/davidmarne/dart_meta_types/meta_types_redux_generator 8 | 9 | dependencies: 10 | analyzer: ^0.32.0 11 | build: ^0.12.0 12 | source_gen: ^0.9.0 13 | meta_types: ^0.1.0 14 | meta_types_generator: ^0.1.0 15 | 16 | dev_dependencies: 17 | build_runner: ^0.9.0 18 | 19 | environment: 20 | sdk: '>=2-0-0-dev <3.0.0' 21 | -------------------------------------------------------------------------------- /mono_repo.yaml: -------------------------------------------------------------------------------- 1 | # Created by mono_repo 2 | meta_types: 3 | published: true 4 | meta_types_generator: 5 | published: true 6 | meta_types_json: 7 | published: true 8 | meta_types_json_generator: 9 | published: true 10 | meta_types_redux: 11 | published: true 12 | meta_types_redux_generator: 13 | published: true 14 | --------------------------------------------------------------------------------