diff --git a/example/pubspec.yaml b/example/pubspec.yaml index bfd65fd..63b06c6 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -8,11 +8,13 @@ dependency_overrides: path: ../morphy_annotation dependencies: + json_serializable: ^6.7.1 meta: any - morphy: path: ../morphy +# morphy: ^1.0.1 + dev_dependencies: build_runner: ^2.4.6 test: ^1.24.8 diff --git a/example/test/ex21_custom_constructors_test.dart b/example/test/ex21_custom_constructors_test.dart index f76afd3..135f1c0 100644 --- a/example/test/ex21_custom_constructors_test.dart +++ b/example/test/ex21_custom_constructors_test.dart @@ -15,23 +15,23 @@ part 'ex21_custom_constructors_test.morphy.dart'; //In this example class A has an underscore thereby hiding its default constructor. //Instead we create a function called A_DifferentConstructor. -@morphy -abstract class $A_ { +@Morphy(privateConstructor: true) +abstract class $A { String get a; } void main() { test("0 default value", () { - var a = A_._(a: "my default value"); + var a = A._(a: "my default value"); expect(a.a, "my default value"); }); test("1 default value", () { - var a = A_DifferentConstructor(); + var a = A_Factory(); expect(a.a, "my default value"); }); } -A_ A_DifferentConstructor() { - return A_._(a: "my default value"); +A A_Factory() { + return A._(a: "my default value"); } diff --git a/example/test/ex21_custom_constructors_test.morphy.dart b/example/test/ex21_custom_constructors_test.morphy.dart index 983d852..8c4b489 100644 --- a/example/test/ex21_custom_constructors_test.morphy.dart +++ b/example/test/ex21_custom_constructors_test.morphy.dart @@ -7,27 +7,27 @@ part of 'ex21_custom_constructors_test.dart'; // ************************************************************************** /// -class A_ extends $A_ { +class A extends $A { final String a; /// - A_._({ + A._({ required this.a, }); - String toString() => "(A_-a:${a.toString()})"; + String toString() => "(A-a:${a.toString()})"; int get hashCode => hashObjects([a.hashCode]); bool operator ==(Object other) => identical(this, other) || - other is A_ && runtimeType == other.runtimeType && a == other.a; - A_ copyWith_A_({ + other is A && runtimeType == other.runtimeType && a == other.a; + A copyWith_A({ Opt? a, }) { - return A_._( + return A._( a: a == null ? this.a as String : a.value as String, ); } } -extension $A__changeTo_E on $A_ {} +extension $A_changeTo_E on $A {} -enum A_$ { a } +enum A$ { a } diff --git a/example/test/ex46_json_test.dart b/example/test/ex46_json_test.dart index cc24450..ce41b04 100644 --- a/example/test/ex46_json_test.dart +++ b/example/test/ex46_json_test.dart @@ -1,6 +1,5 @@ // ignore_for_file: unnecessary_cast -import 'package:json_annotation/json_annotation.dart'; import 'package:test/test.dart'; import 'package:morphy/morphy.dart'; diff --git a/example/test/ex46_json_test.g.dart b/example/test/ex46_json_test.g.dart deleted file mode 100644 index 8fc15c8..0000000 --- a/example/test/ex46_json_test.g.dart +++ /dev/null @@ -1,15 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'ex46_json_test.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -Pet _$PetFromJson(Map json) => Pet( - kind: json['kind'] as String, - ); - -Map _$PetToJson(Pet instance) => { - 'kind': instance.kind, - }; diff --git a/example/test/ex46_json_test.morphy.dart b/example/test/ex46_json_test.morphy.dart index e164bb5..8d64dce 100644 --- a/example/test/ex46_json_test.morphy.dart +++ b/example/test/ex46_json_test.morphy.dart @@ -8,7 +8,9 @@ part of 'ex46_json_test.dart'; /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class Pet extends $Pet { final String kind; @@ -45,8 +47,8 @@ class Pet extends $Pet { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } diff --git a/example/test/ex47_json_inheritance_test.morphy.dart b/example/test/ex47_json_inheritance_test.morphy.dart index 6f777ea..f662af7 100644 --- a/example/test/ex47_json_inheritance_test.morphy.dart +++ b/example/test/ex47_json_inheritance_test.morphy.dart @@ -8,7 +8,9 @@ part of 'ex47_json_inheritance_test.dart'; /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class A extends $A { final String id; @@ -54,8 +56,8 @@ class A extends $A { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } @@ -98,7 +100,9 @@ enum A$ { id } /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class B extends $B implements A { final String id; @@ -147,8 +151,8 @@ class B extends $B implements A { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } @@ -173,7 +177,9 @@ enum B$ { id } /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class C extends $C implements A { final String id; final List items; @@ -230,8 +236,8 @@ class C extends $C implements A { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } diff --git a/example/test/ex48_json_with_subtype_test.morphy.dart b/example/test/ex48_json_with_subtype_test.morphy.dart index a96d226..57477b2 100644 --- a/example/test/ex48_json_with_subtype_test.morphy.dart +++ b/example/test/ex48_json_with_subtype_test.morphy.dart @@ -9,7 +9,9 @@ part of 'ex48_json_with_subtype_test.dart'; /// Every subtype needs to also implement toJson & fromJson /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class A extends $A { final String id; final X x; @@ -60,8 +62,8 @@ class A extends $A { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } @@ -82,7 +84,9 @@ enum A$ { id, x, xs } /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class X extends $X { final List items; @@ -121,8 +125,8 @@ class X extends $X { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } diff --git a/example/test/ex50_json_inheritance_generic_test.morphy.dart b/example/test/ex50_json_inheritance_generic_test.morphy.dart index 7f5e15b..4fda164 100644 --- a/example/test/ex50_json_inheritance_generic_test.morphy.dart +++ b/example/test/ex50_json_inheritance_generic_test.morphy.dart @@ -8,7 +8,9 @@ part of 'ex50_json_inheritance_generic_test.dart'; /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class A extends $A { final String id; @@ -45,8 +47,8 @@ class A extends $A { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } @@ -79,7 +81,10 @@ class B_Generics_Sing { B_Generics_Sing._internal() {} } -@JsonSerializable(explicitToJson: true, genericArgumentFactories: true) +@JsonSerializable( + explicitToJson: true, + genericArgumentFactories: true, +) class B extends $B implements A { final String id; final T blah; @@ -139,8 +144,8 @@ class B extends $B implements A { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } @@ -162,7 +167,9 @@ enum B$ { id, blah } /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class X extends $X { final String xyz; @@ -199,8 +206,8 @@ class X extends $X { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } diff --git a/example/test/ex51_json_inheritance_generic_from_test.morphy.dart b/example/test/ex51_json_inheritance_generic_from_test.morphy.dart index 20bf575..f34dd4e 100644 --- a/example/test/ex51_json_inheritance_generic_from_test.morphy.dart +++ b/example/test/ex51_json_inheritance_generic_from_test.morphy.dart @@ -8,7 +8,9 @@ part of 'ex51_json_inheritance_generic_from_test.dart'; /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class A extends $A { final String id; @@ -52,8 +54,8 @@ class A extends $A { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } @@ -96,7 +98,10 @@ class B_Generics_Sing { B_Generics_Sing._internal() {} } -@JsonSerializable(explicitToJson: true, genericArgumentFactories: true) +@JsonSerializable( + explicitToJson: true, + genericArgumentFactories: true, +) class B extends $B implements A { final String id; final T blah; @@ -156,8 +161,8 @@ class B extends $B implements A { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } @@ -179,7 +184,9 @@ enum B$ { id, blah } /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class X extends $X { final String xyz; @@ -216,8 +223,8 @@ class X extends $X { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } diff --git a/example/test/ex52_json_inheritance_generic_test.morphy.dart b/example/test/ex52_json_inheritance_generic_test.morphy.dart index 6e7ea2c..3a5f007 100644 --- a/example/test/ex52_json_inheritance_generic_test.morphy.dart +++ b/example/test/ex52_json_inheritance_generic_test.morphy.dart @@ -16,7 +16,10 @@ class A_Generics_Sing { A_Generics_Sing._internal() {} } -@JsonSerializable(explicitToJson: true, genericArgumentFactories: true) +@JsonSerializable( + explicitToJson: true, + genericArgumentFactories: true, +) class A extends $A { final T1 id; @@ -71,8 +74,8 @@ class A extends $A { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } @@ -132,7 +135,10 @@ class B_Generics_Sing { B_Generics_Sing._internal() {} } -@JsonSerializable(explicitToJson: true, genericArgumentFactories: true) +@JsonSerializable( + explicitToJson: true, + genericArgumentFactories: true, +) class B extends $B implements A { final T1 id; final T1 valT1; @@ -207,8 +213,8 @@ class B extends $B implements A { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } @@ -258,7 +264,10 @@ class C_Generics_Sing { C_Generics_Sing._internal() {} } -@JsonSerializable(explicitToJson: true, genericArgumentFactories: true) +@JsonSerializable( + explicitToJson: true, + genericArgumentFactories: true, +) class C extends $C implements B { final T1 id; final T1 valT1; @@ -345,8 +354,8 @@ class C extends $C implements B { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } diff --git a/example/test/ex53_abstract_json_test.dart b/example/test/ex53_abstract_json_test.dart new file mode 100644 index 0000000..f49f1ef --- /dev/null +++ b/example/test/ex53_abstract_json_test.dart @@ -0,0 +1,44 @@ +// ignore_for_file: unnecessary_cast + +import 'package:test/test.dart'; +import 'package:morphy/morphy.dart'; + +part 'ex53_abstract_json_test.g.dart'; + +part 'ex53_abstract_json_test.morphy.dart'; + +@Morphy(generateJson: true, explicitSubTypes: [$Todo2_complete, $Todo2_incomplete]) +abstract class $$Todo2 { + String get title; + + String? get id; + + String get description; +} + +@Morphy(generateJson: true) +abstract class $Todo2_incomplete implements $$Todo2 {} + +@Morphy(generateJson: true) +abstract class $Todo2_complete implements $$Todo2 { + DateTime get completedDate; +} + +main() { + test("1 toJson as A", () { + var todoObjects = [Todo2_complete(title: "Todo2_complete", description: "description", completedDate: DateTime(2023, 11, 1)), Todo2_incomplete(title: "Todo2_incomplete", description: "description")]; + + var resultInJsonFormat = todoObjects.map((todo2) => todo2.toJson_2()).toList(); + + var expectedJson = [ + {'title': 'Todo2_complete', 'id': null, 'description': 'description', 'completedDate': '2023-11-01T00:00:00.000', '_className_': 'Todo2_complete'}, + {'title': 'Todo2_incomplete', 'id': null, 'description': 'description', '_className_': 'Todo2_incomplete'} + ]; + + expect(resultInJsonFormat, expectedJson); + + var resultXObjects = expectedJson.map((json) => Todo2.fromJson(json)).toList(); + + expect(resultXObjects, todoObjects); + }); +} diff --git a/example/test/ex54_default_constructor_json_test.dart b/example/test/ex54_default_constructor_json_test.dart new file mode 100644 index 0000000..3b0b278 --- /dev/null +++ b/example/test/ex54_default_constructor_json_test.dart @@ -0,0 +1,40 @@ +import 'package:morphy/morphy.dart'; + +part 'ex54_default_constructor_json_test.g.dart'; + +part 'ex54_default_constructor_json_test.morphy.dart'; + +@Morphy(generateJson: true, explicitSubTypes: [$Todo2_complete, $Todo2_incomplete]) +abstract class $$Todo2 { + String get title; + + String get id; + + String get description; +} + +@Morphy(generateJson: true, privateConstructor: true) +abstract class $Todo2_incomplete implements $$Todo2 {} + +@Morphy(generateJson: true) +abstract class $Todo2_complete implements $$Todo2 { + DateTime get completedDate; +} + +Todo2_incomplete todo2_incomplete_Factory({ + required String title, + String? id, + String description = '', +}) { + assert( + id == null || id.isNotEmpty, + 'id must either be null or not empty', + ); + var _id = id ?? "xxx"; + + return Todo2_incomplete._( + id: _id, + title: title, + description: description, + ); +} diff --git a/example/test/ex54_x_deleteme.dart b/example/test/ex54_x_deleteme.dart new file mode 100644 index 0000000..07c35b9 --- /dev/null +++ b/example/test/ex54_x_deleteme.dart @@ -0,0 +1,15 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'ex54_x_deleteme.g.dart'; + +@JsonSerializable(constructor: "blah") +class Person { + final String firstName, lastName; + final DateTime? dateOfBirth; + + Person.blah({required this.firstName, required this.lastName, this.dateOfBirth}); + + factory Person.fromJson(Map json) => _$PersonFromJson(json); + + Map toJson() => _$PersonToJson(this); +} diff --git a/example/test/ex8_enums_test.morphy.dart b/example/test/ex8_enums_test.morphy.dart index a8f2382..10aa1ab 100644 --- a/example/test/ex8_enums_test.morphy.dart +++ b/example/test/ex8_enums_test.morphy.dart @@ -8,7 +8,9 @@ part of 'ex8_enums_test.dart'; /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class Pet extends $Pet { final String type; final eBlim blim; @@ -52,8 +54,8 @@ class Pet extends $Pet { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } diff --git a/example/test/readme.dart b/example/test/readme.dart deleted file mode 100644 index e69de29..0000000 diff --git a/example/test/readme_test.dart b/example/test/readme_test.dart index f594e1e..f25dd90 100644 --- a/example/test/readme_test.dart +++ b/example/test/readme_test.dart @@ -209,6 +209,9 @@ main() { var resultXObjects = expectedJson.map((e) => X.fromJson(e)).toList(); + expect(resultXObjects, xObjects); }); + + } diff --git a/example/test/readme_test.morphy.dart b/example/test/readme_test.morphy.dart index 37916d5..4be698e 100644 --- a/example/test/readme_test.morphy.dart +++ b/example/test/readme_test.morphy.dart @@ -8,7 +8,9 @@ part of 'readme_test.dart'; /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class Pet extends $Pet { final String name; final int age; @@ -56,8 +58,8 @@ class Pet extends $Pet { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } @@ -98,7 +100,9 @@ enum Pet$ { name, age } /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class FrankensteinsDogCat extends $FrankensteinsDogCat implements Dog, Cat { final double whiskerLength; final String woofSound; @@ -212,8 +216,8 @@ class FrankensteinsDogCat extends $FrankensteinsDogCat implements Dog, Cat { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } @@ -238,7 +242,9 @@ enum FrankensteinsDogCat$ { whiskerLength, woofSound, name, age } /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class Cat extends $Cat implements Pet { final double whiskerLength; final String name; @@ -306,8 +312,8 @@ class Cat extends $Cat implements Pet { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } @@ -332,7 +338,9 @@ enum Cat$ { whiskerLength, name, age } /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class Dog extends $Dog implements Pet { final String woofSound; final String name; @@ -400,8 +408,8 @@ class Dog extends $Dog implements Pet { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } @@ -426,7 +434,9 @@ enum Dog$ { woofSound, name, age } /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class Fish extends $Fish implements Pet { final eFishColour fishColour; final String name; @@ -494,8 +504,8 @@ class Fish extends $Fish implements Pet { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } @@ -556,7 +566,7 @@ class A_ extends $A_ { final DateTime timestamp; /// - A_._({ + A_({ required this.val, required this.timestamp, }); @@ -573,7 +583,7 @@ class A_ extends $A_ { Opt? val, Opt? timestamp, }) { - return A_._( + return A_( val: val == null ? this.val as String : val.value as String, timestamp: timestamp == null ? this.timestamp as DateTime @@ -624,7 +634,9 @@ enum B$ { val, optional } /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class X extends $X { final String val; @@ -670,8 +682,8 @@ class X extends $X { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } @@ -718,7 +730,9 @@ enum X$ { val } /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class Y extends $Y implements X { final String val; final int valY; @@ -779,8 +793,8 @@ class Y extends $Y implements X { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } @@ -817,7 +831,9 @@ enum Y$ { val, valY } /// -@JsonSerializable(explicitToJson: true) +@JsonSerializable( + explicitToJson: true, +) class Z extends $Z implements Y { final String val; final int valY; @@ -892,8 +908,8 @@ class Z extends $Z implements Y { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns) { - this._fns = fns; + Map toJson_2([Map? fns]) { + this._fns = fns ?? {}; return toJson(); } diff --git a/morphy/CHANGELOG.md b/morphy/CHANGELOG.md index 282f44c..6e36a7a 100644 --- a/morphy/CHANGELOG.md +++ b/morphy/CHANGELOG.md @@ -1,3 +1,16 @@ +## 1.0.4 +- Relaxed dependency versions +- Fixed bug for abstract class json serialize & deserialize + +## 1.0.3 +- Relaxed analyzer requiremenst to 6.0.0 + +## 1.0.2 +- Added jsonserialization annotation dependency included in morphy + +## 1.0.1 +- Added jsonserialization dependency included in morphy + ## 1.0.0+1 - Updated documentation diff --git a/morphy/README.md b/morphy/README.md index 3867c49..f63400e 100644 --- a/morphy/README.md +++ b/morphy/README.md @@ -164,6 +164,15 @@ In order to convert the object to Json specify the `generateJson`. @Morphy(generateJson: true) abstract class $Pet { +Add the import statement, part file & the pubspec dependencies + + import 'package:json_annotation/json_annotation.dart'; + + part 'Pets.g.dart'; + + json_serializable: + json_annotation: + Then use the toJson_2 method to generate the JSON var json = flossy.toJson_2({}); @@ -241,15 +250,16 @@ We also allow multiple inheritance. ### Custom Constructors -To allow custom constructors you can simply create a function that creates a new class. -If you'd like to hide the automatic constructor end your function with an underscore. +To allow custom constructors you can simply create a factory function that creates a new class. +If you'd like to hide the automatic constructor set the `privateConstructor` on the Morphy annotation to true. If you hide the constructor the custom one should belong in the same file that you defined your class. - A_ a_Constructor(String val){ - return A_._(val: val, timestamp: DateTime(2023,11,25)); + @Morphy(privateConstructor: true) + A a_Factory(String val){ + return A._(val: val, timestamp: DateTime(2023,11,25)); } - var a = a_Constructor("my value"); + var a = a_Factory("my value"); expect(a.timestamp, DateTime(2023,11,25)); diff --git a/morphy/lib/morphy.dart b/morphy/lib/morphy.dart index 1721f44..fe21a0b 100644 --- a/morphy/lib/morphy.dart +++ b/morphy/lib/morphy.dart @@ -2,3 +2,5 @@ export 'package:morphy_annotation/morphy_annotation.dart'; export 'package:morphy_annotation/opt.dart'; export 'package:morphy_annotation/List_E.dart'; export 'package:quiver/core.dart' show hashObjects; +export 'package:json_serializable/json_serializable.dart'; +export 'package:json_annotation/json_annotation.dart'; diff --git a/morphy/lib/src/MorphyGenerator.dart b/morphy/lib/src/MorphyGenerator.dart index f75ad62..2f8826f 100644 --- a/morphy/lib/src/MorphyGenerator.dart +++ b/morphy/lib/src/MorphyGenerator.dart @@ -131,6 +131,7 @@ class MorphyGenerator extends GeneratorForAnnotationX classGenerics, bool hasConstContructor, bool generateJson, + bool hasPrivateConstructor, List explicitForJson, ) { //recursively go through otherClasses and get my fieldnames & @@ -21,13 +22,10 @@ String createMorphy( sb.write(getClassComment(interfacesFromImplements, classComment)); + //move this into a helper class! if (generateJson) { sb.writeln(createJsonSingleton(classNameTrim, classGenerics)); - // sb.writeln("Map jsonToGenericFunctions_$classNameTrim = {};"); - if (classGenerics.length > 0) // - sb.writeln("@JsonSerializable(explicitToJson: true, genericArgumentFactories: true)"); - else - sb.writeln("@JsonSerializable(explicitToJson: true)"); + sb.writeln(createJsonHeader(className, classGenerics, hasPrivateConstructor)); } sb.write(getClassDefinition(isAbstract, className)); @@ -45,13 +43,14 @@ String createMorphy( sb.write(getImplements(interfacesFromImplements, className)); } sb.writeln(" {"); - var constructorName = getConstructorName(classNameTrim); if (isAbstract) { sb.writeln(getPropertiesAbstract(allFields)); } else { sb.writeln(getProperties(allFields)); sb.write(getClassComment(interfacesFromImplements, classComment)); + //constructor + var constructorName = getConstructorName(classNameTrim, hasPrivateConstructor); if (allFields.isEmpty) { sb.writeln("${constructorName}();"); } else { @@ -59,6 +58,12 @@ String createMorphy( sb.writeln(getConstructorRows(allFields)); sb.writeln("});"); + if (hasPrivateConstructor && generateJson) { + sb.writeln("${constructorName}.forJsonDoNotUse({"); + sb.writeln(getConstructorRows(allFields)); + sb.writeln("});"); + } + if (hasConstContructor) { sb.writeln("const ${constructorName}.constant({"); sb.writeln(getConstructorRows(allFields)); @@ -90,6 +95,7 @@ String createMorphy( isClassAbstract: isAbstract, interfaceGenerics: x.typeParams, isExplicitSubType: x.isExplicitSubType, + hasPrivateConstructor: hasPrivateConstructor, ), ); }); @@ -120,6 +126,7 @@ String createMorphy( isClassAbstract: isAbstract, interfaceGenerics: x.typeParams, isExplicitSubType: x.isExplicitSubType, + hasPrivateConstructor: hasPrivateConstructor, ), ); }); diff --git a/morphy/lib/src/helpers.dart b/morphy/lib/src/helpers.dart index 6f85ac6..0e0b075 100644 --- a/morphy/lib/src/helpers.dart +++ b/morphy/lib/src/helpers.dart @@ -218,6 +218,21 @@ String getEquals(List fields, String className) { return sb.toString(); } +String createJsonHeader(String className, List classGenerics, bool privateConstructor) { + var sb = StringBuffer(); + + if (!className.startsWith("\$\$")) { + var jsonConstructorName = privateConstructor ? "constructor: 'forJsonDoNotUse'" : ""; + + if (classGenerics.length > 0) // + sb.writeln("@JsonSerializable(explicitToJson: true, genericArgumentFactories: true, $jsonConstructorName)"); + else + sb.writeln("@JsonSerializable(explicitToJson: true, $jsonConstructorName)"); + } + + return sb.toString(); +} + ///[classFields] & [interfaceFields] should be renamed /// for changeTo [classFields] and [className] is what we are copying from /// and [interfaceFields] and [interfaceName] is what we are copying to @@ -229,6 +244,7 @@ String getCopyWith({ required String className, required bool isClassAbstract, required List interfaceGenerics, + required bool hasPrivateConstructor, bool isExplicitSubType = false, //for where we specify the explicit subtypes for changeTo }) { var sb = StringBuffer(); @@ -293,7 +309,7 @@ String getCopyWith({ if (isExplicitSubType) { sb.writeln("return ${getDataTypeWithoutDollars(interfaceName)}("); } else { - if (className.endsWith("_")) { + if (hasPrivateConstructor) { sb.writeln("return $classNameTrimmed._("); } else { sb.writeln("return $classNameTrimmed("); @@ -348,8 +364,10 @@ String getCopyWith({ // toString() => "${this.type}|${this.paramNameType}"; //} -String getConstructorName(String trimmedClassName) { - return trimmedClassName[trimmedClassName.length - 1] == "_" ? "$trimmedClassName._" : trimmedClassName; +String getConstructorName(String trimmedClassName, bool hasCustomConstructor) { + return hasCustomConstructor // + ? "$trimmedClassName._" + : trimmedClassName; } String generateFromJsonHeader(String className) { @@ -359,11 +377,12 @@ String generateFromJsonHeader(String className) { } String generateFromJsonBody(String className, List generics, List interfaces) { - var _className = "${className.replaceFirst("\$", "")}"; - var _class = Interface(_className, generics.map((e) => e.type ?? "").toList(), generics.map((e) => e.name).toList(), []); + var _class = Interface(className, generics.map((e) => e.type ?? "").toList(), generics.map((e) => e.name).toList(), []); var _classes = [...interfaces, _class]; - var body = _classes.mapIndexed((i, c) { + var body = _classes // + .where((c) => !c.interfaceName.startsWith("\$\$")) + .mapIndexed((i, c) { var _interfaceName = "${c.interfaceName.replaceFirst("\$", "")}"; var start = i == 0 ? "if" : "} else if"; var genericTypes = c.typeParams.map((e) => "'_${e.name}_'").join(","); @@ -385,6 +404,8 @@ String generateFromJsonBody(String className, List generics, List generics, List generics) { + if (className.startsWith("\$\$")) { + return "Map toJson_2([Map? fns]);"; + } + var _className = "${className.replaceFirst("\$", "")}"; var getGenericFn = generics // @@ -413,8 +438,8 @@ String generateToJson(String className, List generics) { // ignore: unused_field Map _fns = {}; - Map toJson_2(Map fns){ - this._fns = fns; + Map toJson_2([Map? fns]){ + this._fns = fns ?? {}; return toJson(); } diff --git a/morphy/pubspec.yaml b/morphy/pubspec.yaml index c079d23..3405ec2 100644 --- a/morphy/pubspec.yaml +++ b/morphy/pubspec.yaml @@ -1,22 +1,24 @@ name: morphy description: Provides a clean class definition with extra functionality including; copy with, json serializable, tostring, equals that supports inheritance and polymorphism -version: 1.0.0+1 +version: 1.0.4 homepage: https://github.com/atreeon/morphy environment: sdk: ">=3.1.3 <4.0.0" -#dependency_overrides: -# morphy_annotation: -# path: ../morphy_annotation +dependency_overrides: + morphy_annotation: + path: ../morphy_annotation dependencies: - morphy_annotation: ^1.0.0 - analyzer: '>=6.3.0 <=7.0.0' + morphy_annotation: ^1.0.4 + analyzer: '>=6.0.0 <=7.0.0' build: ^2.1.0 source_gen: ^1.1.1 dartx: ^1.2.0 quiver: ^3.2.1 + json_serializable: ^6.3.2 + json_annotation: ^4.7.0 dev_dependencies: build_runner: ^2.4.6 diff --git a/morphy/test/helpers_test.dart b/morphy/test/helpers_test.dart index f14c5a4..2518a11 100644 --- a/morphy/test/helpers_test.dart +++ b/morphy/test/helpers_test.dart @@ -2,8 +2,8 @@ import 'package:morphy/src/common/NameType.dart'; import 'package:morphy/src/common/classes.dart'; import 'package:morphy/src/common/formatCodeStringForComparison.dart'; -import 'package:test/test.dart'; import 'package:morphy/src/helpers.dart'; +import 'package:test/test.dart'; var expectS = (String a, String b) => expect(formatCodeStringForComparison(a), formatCodeStringForComparison(b)); @@ -456,12 +456,12 @@ a == other.a && b == other.b && c == other.c;"""; group("getConstructorName", () { test("1n normalc", () { - var result = getConstructorName("MyClass"); + var result = getConstructorName("MyClass", false); expectS(result, "MyClass"); }); test("2n privatec", () { - var result = getConstructorName("MyClass_"); + var result = getConstructorName("MyClass_", true); expectS(result, "MyClass_._"); }); @@ -501,6 +501,7 @@ a == other.a && b == other.b && c == other.c;"""; className: "A", isClassAbstract: true, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """A copyWith_A({ Opt? a, @@ -520,6 +521,7 @@ Opt? a, className: "B", isClassAbstract: true, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """B copyWith_A({ Opt? a, @@ -538,6 +540,7 @@ Opt? a, className: "A", isClassAbstract: false, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """A copyWith_A({ Opt? a, @@ -561,6 +564,7 @@ a: a == null ? this.a as String : a.value as String, className: "B", isClassAbstract: false, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """B copyWith_A({ Opt? a, @@ -586,6 +590,7 @@ b: (this as B).b, className: "B", isClassAbstract: false, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """B copyWith_B({ Opt? a, @@ -612,6 +617,7 @@ b: b == null ? this.b as T1 : b.value as T1, className: "C", isClassAbstract: false, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """C copyWith_A({ Opt? a, @@ -639,6 +645,7 @@ c: (this as C).c, className: "C", isClassAbstract: false, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """C copyWith_B({ Opt? a, @@ -668,6 +675,7 @@ c: (this as C).c, className: "C", isClassAbstract: false, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """C copyWith_C({ Opt? a, @@ -695,6 +703,7 @@ c: c == null ? this.c as bool : c.value as bool, className: "D", isClassAbstract: false, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """D copyWith_A({ Opt? a, @@ -720,6 +729,7 @@ b: (this as D).b, className: "D", isClassAbstract: false, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """D copyWith_B({ Opt? a, @@ -746,6 +756,7 @@ b: b == null ? this.b as T1 : b.value as T1, className: "D", isClassAbstract: false, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """D copyWith_D({ Opt? a, @@ -766,6 +777,7 @@ b: b == null ? this.b as T1 : b.value as T1, className: "X", isClassAbstract: true, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """X copyWith_X( );"""); @@ -781,6 +793,7 @@ b: b == null ? this.b as T1 : b.value as T1, className: "Y", isClassAbstract: false, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """Y copyWith_X( ) { @@ -792,17 +805,17 @@ a: (this as Y).a, test("14p yy (see ex29_manual) interface with no fields", () { var result = getCopyWith( - classFields: [ - NameTypeClassComment("a", "String", null), - ], - interfaceFields: [ - NameTypeClassComment("a", "String", null), - ], - interfaceName: "Y", - className: "Y", - isClassAbstract: false, - interfaceGenerics: [], - ); + classFields: [ + NameTypeClassComment("a", "String", null), + ], + interfaceFields: [ + NameTypeClassComment("a", "String", null), + ], + interfaceName: "Y", + className: "Y", + isClassAbstract: false, + interfaceGenerics: [], + hasPrivateConstructor: false); expectS(result, """Y copyWith_Y({ Opt? a, }) { @@ -824,6 +837,7 @@ a: a == null ? this.a as String : a.value as String, className: "A", isClassAbstract: false, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """A copyWith_A({ Opt? a, @@ -836,17 +850,17 @@ a: a == null ? this.a as Person : a.value as Person, test("16p ba (see ex7_manual) where subtypes are used", () { var result = getCopyWith( - classFields: [ - NameTypeClassComment("a", "Employee", null), - ], - interfaceFields: [ - NameTypeClassComment("a", "Person", null), - ], - interfaceName: "A", - className: "B", - isClassAbstract: false, - interfaceGenerics: [], - ); + classFields: [ + NameTypeClassComment("a", "Employee", null), + ], + interfaceFields: [ + NameTypeClassComment("a", "Person", null), + ], + interfaceName: "A", + className: "B", + isClassAbstract: false, + interfaceGenerics: [], + hasPrivateConstructor: false); expectS(result, """B copyWith_A({ Opt? a, }) { @@ -868,6 +882,7 @@ a: a == null ? this.a as Employee : a.value as Employee, className: "B", isClassAbstract: false, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """B copyWith_B({ Opt? a, @@ -890,6 +905,7 @@ a: a == null ? this.a as Employee : a.value as Employee, className: "C", isClassAbstract: false, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """C copyWith_A({ Opt? a, @@ -912,6 +928,7 @@ a: a == null ? this.a as Manager : a.value as Manager, className: "C", isClassAbstract: false, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """C copyWith_B({ Opt? a, @@ -934,6 +951,7 @@ a: a == null ? this.a as Manager : a.value as Manager, className: "C", isClassAbstract: false, interfaceGenerics: [], + hasPrivateConstructor: false, ); expectS(result, """C copyWith_C({ Opt? a, @@ -959,6 +977,7 @@ a: a == null ? this.a as Manager : a.value as Manager, interfaceName: "A", className: "B", isClassAbstract: false, + hasPrivateConstructor: false, ); expectS(result, """B copyWith_A({ Opt? x, @@ -988,6 +1007,7 @@ z: (this as B).z, interfaceName: "B", className: "B", isClassAbstract: false, + hasPrivateConstructor: false, ); expectS(result, """B copyWith_B({ Opt? x, @@ -1014,6 +1034,7 @@ z: z == null ? this.z as String : z.value as String, interfaceName: "A", className: "A", isClassAbstract: true, + hasPrivateConstructor: false, ); expectS(result, """A copyWith_A({ Opt? x, @@ -1034,6 +1055,7 @@ Opt? x, interfaceName: "A", className: "B", isClassAbstract: false, + hasPrivateConstructor: false, ); expectS(result, """B copyWith_A({ Opt? x, @@ -1054,14 +1076,15 @@ y: (this as B).y, NameTypeClassComment("a", "String", null), ], interfaceGenerics: [], - interfaceName: "A_", - className: "A_", + interfaceName: "A", + className: "A", isClassAbstract: false, + hasPrivateConstructor: true, ); - expectS(result, """A_ copyWith_A_({ + expectS(result, """A copyWith_A({ Opt? a, }) { -return A_._( +return A._( a: a == null ? this.a as String : a.value as String, ); }"""); @@ -1079,6 +1102,7 @@ a: a == null ? this.a as String : a.value as String, interfaceName: "X", className: "X", isClassAbstract: false, + hasPrivateConstructor: false, ); expectS(result, """X copyWith_X({ Opt? fn, @@ -1103,6 +1127,7 @@ fn: fn == null ? this.fn as bool Function(\$X) : fn.value as bool Function(\$X), className: "A", isClassAbstract: false, isExplicitSubType: true, + hasPrivateConstructor: false, ); expectS(result, """B changeTo_B({ required String y, @@ -1130,6 +1155,7 @@ x: x == null ? this.x as String : x.value as String, className: "A", isClassAbstract: false, isExplicitSubType: true, + hasPrivateConstructor: false, ); expectS(result, """B changeTo_B({ required String y, @@ -1159,6 +1185,7 @@ x: x == null ? this.x as String : x.value as String, className: "A", isClassAbstract: false, isExplicitSubType: true, + hasPrivateConstructor: false, ); expectS(result, """B changeTo_B({ required String y, @@ -1189,6 +1216,7 @@ x: x == null ? this.x as String : x.value as String, interfaceName: "\$B", className: "\$B", isClassAbstract: false, + hasPrivateConstructor: false, ); expectS(result, """B copyWith_B({ Opt? x, @@ -1217,6 +1245,7 @@ z: z == null ? this.z as Z : z.value as Z, className: "\$\$Super", isClassAbstract: true, isExplicitSubType: true, + hasPrivateConstructor: false, ); expectS(result, """B changeTo_B({ required String y, @@ -1340,12 +1369,35 @@ x: x == null ? this.x as String : x.value as String, expectS(result, expected); }); + + test("5s abstract superclass", () { + var result = generateFromJsonBody( + "\$\$A", + [], + [ + Interface("\$B", ["", "", ""], ["T", "T2", "T3"], []), + ], + ); + + var expected = """ + if (json['_className_'] == "B") { + var fn_fromJson = getFromJsonToGenericFn( + B_Generics_Sing().fns, + json, + ['_T_','_T2_','_T3_'], + ); + return fn_fromJson(json); + } else { + throw UnsupportedError("The _className_ '\${json['_className_']}' is not supported by the A.fromJson constructor."); + } +}"""; + + expectS(result, expected); + }); }); group("generateToJson", () { //add this based on the generics - // Map toJson(Object Function(dynamic)? toJson_T) { - // final Map data = _$CToJson(this, toJson_T!); test("1u", () { var result = generateToJson("\$Pet", []); @@ -1353,8 +1405,8 @@ x: x == null ? this.x as String : x.value as String, var expected = """// ignore: unused_field\n Map _fns = {}; - Map toJson_2(Map fns){ - this._fns = fns; + Map toJson_2([Map? fns]){ + this._fns = fns ?? {}; return toJson(); } @@ -1385,8 +1437,8 @@ x: x == null ? this.x as String : x.value as String, var expected = """// ignore: unused_field\n Map _fns = {}; - Map toJson_2(Map fns){ - this._fns = fns; + Map toJson_2([Map? fns]){ + this._fns = fns ?? {}; return toJson(); } @@ -1409,6 +1461,16 @@ x: x == null ? this.x as String : x.value as String, expectS(result, expected); }); + + test("3u abstract class", () { + var result = generateToJson("\$\$Pet", []); + + var expected = """ + Map toJson_2([Map? fns]); +"""; + + expectS(result, expected); + }); }); group("createJsonSingleton", () { @@ -1470,6 +1532,29 @@ class C_Generics_Sing { }); }); + group("createJsonHeader", () { + test("1w non abstract, no generics, private constructor", () { + var result = createJsonHeader("\$Pet", [], true); + var expected = "@JsonSerializable(explicitToJson: true, constructor: 'forJsonDoNotUse')"; + + expectS(result, expected); + }); + + test("2w abstract", () { + var result = createJsonHeader("\$\$Pet", [], true); + var expected = ""; + + expectS(result, expected); + }); + + test("3w non abstract, generics, no private constructor", () { + var result = createJsonHeader("\$Pet", [NameTypeClass("name", "type", "className")], false); + var expected = "@JsonSerializable(explicitToJson: true, genericArgumentFactories: true, )"; + + expectS(result, expected); + }); + }); + // group("getCopyWithSignature", () { // test("1p", () { // var result = getCopyWithSignature( diff --git a/morphy_annotation/CHANGELOG.md b/morphy_annotation/CHANGELOG.md index 4a1b581..3acdf05 100644 --- a/morphy_annotation/CHANGELOG.md +++ b/morphy_annotation/CHANGELOG.md @@ -1,2 +1 @@ -## 1.0.0 -- First published version \ No newline at end of file +see morphy \ No newline at end of file diff --git a/morphy_annotation/lib/annotations.dart b/morphy_annotation/lib/annotations.dart index bcdd672..b235896 100644 --- a/morphy_annotation/lib/annotations.dart +++ b/morphy_annotation/lib/annotations.dart @@ -14,6 +14,8 @@ class Morphy implements MorphyX { final bool generateJson; + final bool privateConstructor; + /// {@template MorphyX} /// ### normal class; prepend class with a single dollar & make abstract /// ``` @@ -91,16 +93,19 @@ class Morphy implements MorphyX { const Morphy({ this.explicitSubTypes = null, this.generateJson = false, + this.privateConstructor = false, }); } class Morphy2 implements MorphyX { final List? explicitSubTypes; final bool generateJson; + final bool privateConstructor; const Morphy2({ this.explicitSubTypes = null, this.generateJson = false, + this.privateConstructor = false, }); } diff --git a/morphy_annotation/pubspec.yaml b/morphy_annotation/pubspec.yaml index e355b1e..d1f0451 100644 --- a/morphy_annotation/pubspec.yaml +++ b/morphy_annotation/pubspec.yaml @@ -1,6 +1,6 @@ name: morphy_annotation description: annotation for morphy which provides a clean class definition with extra functionality including; copy with, json serializable, tostring, equals that supports inheritance and polymorphism -version: 1.0.0 +version: 1.0.4 homepage: https://github.com/atreeon/morphy environment: diff --git a/release/1_dry_run_release.sh b/release/1_dry_run_release.sh index 6ee67a7..be57626 100755 --- a/release/1_dry_run_release.sh +++ b/release/1_dry_run_release.sh @@ -33,7 +33,10 @@ else fi cd ../example +rm test/*.morphy.dart +rm test/*.g.dart dart pub get +dart pub run build_runner clean dart run build_runner build --delete-conflicting-outputs dart pub run test cd ../release diff --git a/release/3_releaseMorphy.sh b/release/3_releaseMorphy.sh index 7720ee0..4a09c83 100755 --- a/release/3_releaseMorphy.sh +++ b/release/3_releaseMorphy.sh @@ -13,7 +13,21 @@ read -p "Is this correct? (y/n): " choice if [ "$choice" = "y" ]; then clear - echo "Continuing..." + echo "Checking referenced morphy_annotation" +else + exit 0 +fi + +versionMorphyAnnotation=$(grep 'morphy_annotation:' "../morphy/pubspec.yaml" | awk '{print $2}') +echo "Morphy references annotation version $versionMorphyAnnotation" +echo "morphy_annotation in pub.dev is $versionAnnotationPub" +echo "local Morphy version is $versionMorphyLocal" + +read -p "Is this correct? (y/n): " choice + +if [ "$choice" = "y" ]; then + clear + echo "publish dry run:" else exit 0 fi