Git Product home page Git Product logo

freezed's People

Contributors

andrzejchm avatar avbk avatar byunggilchoi avatar creativecreatorormaybenot avatar dependabot[bot] avatar devnico avatar gaetschwartz avatar github-actions[bot] avatar hacker1024 avatar hadysata avatar hpoul avatar isacjunior avatar jarvanmo avatar long1eu avatar maks avatar matsue avatar mideb avatar ookami-kb avatar orestesgaolin avatar pedromassango avatar piedcipher avatar rrousselgit avatar sandromaglione avatar scopendo avatar srawlins avatar sunlightbro avatar tatsuyafujisaki avatar timwhiting avatar triallax avatar ttpho avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

freezed's Issues

[Question] Either union like from Dartz

In Dartz package we have Either<L,R> type to represent either L type or R type.
I thought that this should mimic this behavior

@immutable
abstract class Either<L, R> with _$Either<L, R> {
  const factory Either.left(L left) = Left;
  const factory Either.right(R right) = Right;
}

and usage

void run(Either<int, String> either) {
  either.when(left: (value) => print(value), right: (value) => value);
}
---
run(Left(10));

However, I am getting the following error

lib/either.dart:7:39: Error: The constructor function type 'Left<dynamic, dynamic> Function(dynamic)' isn't a subtype of 'Either<L, R> Function(L)'.
 - 'Left' is from 'package:sandbox/either.dart' ('lib/either.dart').
 - 'Either' is from 'package:sandbox/either.dart' ('lib/either.dart').
  const factory Either.left(L left) = Left;
                                      ^
lib/either.dart:8:41: Error: The constructor function type 'Right<dynamic, dynamic> Function(dynamic)' isn't a subtype of 'Either<L, R> Function(R)'.
 - 'Right' is from 'package:sandbox/either.dart' ('lib/either.dart').
 - 'Either' is from 'package:sandbox/either.dart' ('lib/either.dart').
  const factory Either.right(R right) = Right;
                                        ^

Am I doing something wrong? Or should it be possible to create this? Thanks for any help.

Using 'part of' where one file doesn't contain a "freezed class" results in errors

Dart supports the part of statement which unfortunately doesn't work with this otherwise amazing package.

I'm using the BLoC library and specify events and states as unions. I like to generate just one file instead of two, so I want to use the part of statement in the event and state files which will point to the "core" bloc file.

part of 'sign_in_form_bloc.dart';

@immutable
abstract class SignInFormEvent with _$SignInFormEvent {
  const factory SignInFormEvent.emailChanged(String emailStr) = _EmailChanged;
  const factory SignInFormEvent.passwordChanged(String passwordStr) =
      _PasswordChanged;
}

Then, the BLoC file contains the actual part '*.freezed.dart' directive.

import 'package:flutter/foundation.dart';

part 'sign_in_form_event.dart';
part 'sign_in_form_state.dart';

part 'sign_in_form_bloc.freezed.dart';

class SignInFormBloc extends Bloc<SignInFormEvent, SignInFormState> {...}

While doing the things described above worked flawlessly with sum_types, freezed outputs a [SEVERE] error upon generation looking like this:

[SEVERE] freezed:freezed on lib/application/auth/sign_in_form/sign_in_form_bloc.dart:
Error formatting generated source code for package:workout_app_prep/application/auth/sign_in_form/sign_in_form_bloc.dartwhich was output to lib/application/auth/sign_in_form/sign_in_form_bloc.freezed.dart.
This may indicate an issue in the generated code or in the formatter.
Please check the generated code and file an issue on source_gen if appropriate.
Could not format because the source could not be parsed:

line 367, column 9: Unexpected text ')'.
    ╷
367 │ class _$) with DiagnosticableTreeMixin implements ) {
    │         ^
    ╵
line 367, column 51: Expected a type name.

Basically it adds a DiagnosticableTreeMixin to the generated file's classes.

Using only the part statement as seen in the examples does work:

import 'package:flutter/foundation.dart';

part 'sign_in_form_event.freezed.dart';

@immutable
abstract class SignInFormEvent with _$SignInFormEvent {
  const factory SignInFormEvent.emailChanged(String emailStr) = _EmailChanged;
  const factory SignInFormEvent.passwordChanged(String passwordStr) =
      _PasswordChanged;
}

copyWith override error in generated file

Hi Remi,

maybe i am doing something wrong or i am not allowed to add 2 generics, but this class will
result in the error below

version: "0.1.3+1"

@immutable
abstract class Complete<Params, Value> with _$Complete {
  const factory Complete.success(Params params, Value value) = Success;
  const factory Complete.error(Params params, Object error) = Error;
}

will result in *

/// *.freezed.dart

'Error.copyWith' ('Error<Params, Value> Function({error: Object, params: Params})') isn't a valid override of '_$Complete.copyWith' ('Complete<dynamic, dynamic> Function({params: dynamic})').dart(invalid_override)

'Success.copyWith' ('Success<Params, Value> Function({params: Params, value: Value})') isn't a valid override of '_$Complete.copyWith' ('Complete<dynamic, dynamic> Function({params: dynamic})').dart(invalid_override)

Generate constructor tear-off

It's relatively common to have to do a one-to-one mapping between the parameters of a callback and a constructor, like:

onError: (err) => MyClass.error(err),

Freezed could, in theory, generate placeholder classes with static methods to reduce the boilerplate of such thing:

onError: $MyClass.error,

Unions inheritance

It could be nice to use Unions for the BLOC states
But states usually have inheritance:

abstract class AppState {}
abstract class AppNavigationState {}
class AppNavigateToAState extends AppState with AppNavigationState {}
class AppNavigateToBState extends AppState with AppNavigationState {}
class AppSomeOtherState extends AppState {}

so we could filter states after:

.appBloc.whereType<AppNavigationState>()

so it could befreezed freezedWith attribute for example:

abstract class AppNavigationState {}

@freezed
abstract class AppState with _$Union {
  @freezedWith(AppNavigationState)
  const factory AppState.navigateToA() = NavigateToA;
  @freezedWith(AppNavigationState)
  const factory AppState.navigateToB() = NavigateToB;
}

0.4.0: Error running FreezedGenerator: ... but freezed has nothing to generate"

File:

import 'package:freezed_annotation/freezed_annotation.dart';
part 'second_state.freezed.dart';
part 'second_state.g.dart';

@freezed
abstract class SecondState with _$SecondState {
  const factory SecondState({
    @JsonKey(ignore: true, nullable: true) String dateTime,
    @JsonKey(ignore: true, nullable: true) String uuid,
  }) = _SecondState;

  const factory SecondState.fromJson(Map<String, dynamic> json) => _$SecondStateFromJson(json);
}

Error:

[SEVERE] freezed:freezed on lib/state/second_state/second_state.dart:
Error running FreezedGenerator
Marked SecondState with @freezed, but freezed has nothing to generate
package:example/state/second_state/second_state.dart:6:16
  ╷
6 │ abstract class SecondState with _$SecondState {
  │                ^^^^^^^^^^^
  ╵

Did I forget something? All other state files fail as well (so it's not the fact that both fields have ignore: true at JsonKey)

Return Future from when

What's the reason for Result when<Result extends Object>? With the extends Object restriction it isn't possible to return Future<T> or FutureOr<T>

Screen-Shot-2020-02-09-13-57-31 54

How do you imagine to use when with Futures or FutureOr?

With Result when<Result> it simply works but I don't know if other code requires a Object somewhere.

Add assert(field != null) functionality

Hi there,
first of all: Great package!

The only thing I am missing at this point is the possibility to ensure fields to be non null.
Normally I would use assert(field != null) in the constructor to make a field non-nullable.
It would be really useful to have this feature on freezed classes to make nullability errors easier to prevent.

Thanks!

Support JsonKey

abstract class Example with _$Example {
  factory Example(@JsonKey(name: 'whatever') String value) = _Example;
}

fromJson missing

Hi,

I am using freezed for serialisation. But getting the following error Try correcting the name to the name of an existing method, or defining a method named 'fromJson', I also defined factory constructor in the model class.

  factory Model.fromJson(Map<String, dynamic> json) => _$ModelFromJson(json);

Here is reproducible example

Flutter 1.12.13+hotfix.7 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 9f5ff2306b (3 weeks ago) • 2020-01-26 22:38:26 -0800
Engine • revision a67792536c
Tools • Dart 2.7.0

Operating System: Windows10(64bit)

Support recursive classes

Edited to include a better description of the issue (@rrousselGit)

Consider:

@immutable
abstract class Foo with _$Foo {
  factory Foo(RedirectedName value) = RedirectedName; 
}

This is a recursive class, as the default constructor somehow refers to itself.
But since RedirectedName has yet to be generated, Freezed does not understand what is happening and parse RedirectedName as dynamic instead.


Original message:

Hello, Thanks for your great package.
I created a simple class with 2 constructor with the following code but when I want to use price property in PriceWithQuantity class it just return dynamic instated of Price class

@immutable
abstract class PriceExample with _$PriceExample {
  const factory PriceExample.price(
    int id,
    int price,
  ) = Price;

  const factory PriceExample.withQuantity(
    Price price,
    int quantity,
  ) = PriceWithQuantity;
}

Support getters

This will not compile, or at least, no _$Person will be created.
Is this something you don't want/or is impossible to support?

@immutable
abstract class Person with _$Person {
  const factory Person(String firstName, String lastName) = _Person;

  String get fullName => '$firstName $lastName';
}

Custom toString methods for data classes

I'd love to be able to define custom toString methods for data classes.

@immutable
abstract class ClubId with _$ClubId {
  const factory ClubId(String value) = _ClubIdDataClass;

  @override
  String toString() {
    return 'ClubId#$value';
  }
}

It should skip generation of toString in _$_ClubIdDataClass and rely on the implementation in ClubId.

Should be only possible for @immutable annotated classes with one factory constructor. Alternatively with a custom @freezedDataClass annotation which only allows one factory constructor

Non-constant default values

Thank you for the 0.7.0 update, the default values made my code a little bit simpler :)

One thing that I still have to work around are non-constant default values. My type has a String property called id that - if left empty - should have a random UUID value by default. I now work around this by adding a second factory method that redirects to the generated one without the id parameter.

It would be nice if the @Default annotation could also take in a lambda to generate the default value.

Selective equals method when generating code

First of all great package! 👍

Would it be possible to add a selective == method when generating code?

Example:

class Person{
  final String name;
  final int age;
  final double height;
  final int personId;

  const Person(this.name, this.age, this.height, this.personId);

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
          other is Person &&
              runtimeType == other.runtimeType &&
              name == other.name &&
              age == other.age &&
              height == other.height &&
              personId == other.personId;

  @override
  int get hashCode =>
      name.hashCode ^
      age.hashCode ^
      height.hashCode ^
      personId.hashCode;
  
}

Above class == method will check equality of every field in the class

In some cases, I would like to just check specific fields

class Person{
  final String name;
  final int age;
  final double height;
  final int personId;

  const Person(this.name, this.age, this.height, this.personId);

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
          other is Person &&
              runtimeType == other.runtimeType &&
              personId == other.personId;

  @override
  int get hashCode => personId.hashCode;
}

Above class == method will check equality of specified field personId;

Thanks!

All properties available on all factory methods

(great job Remi!)

I wasn't sure how to title this! It isn't possible to do the following because the properties are only available if all factory methods have that property. How is it best to overcome this?

abstract class Result with _$Result {
  const factory Result.Continue(Action action) = Result_Continue;
  const factory Result.Retry(Action action) = Result_Retry;
  const factory Result.Complete() = Result_Complete;
}

blah(Result result){
if(result is Result_Continue || result is Result_Retry){
	process(result.action);  //. <----- this is not possible because action is not on all factorys
}

I thought that composition might do it, is that the best way? Is it just a different way of thinking than my inheritance conditioned brain?

@freezed
abstract class ResultType with _$Result {
  const factory ResultType.Continue(Action action) = ResultType_Continue;
  const factory ResultType.Retry(Action action) = ResultType_RetryError;
}

@freezed
abstract class Result with _$Result {
  const factory Result.ResultType(ResultType resultType) = Result_Type;
  const factory Result.Complete(WadFile wadFile) = Result_Complete;
}

blah(Result result){
if(result is Result_Type){
	process(result.resultType.action);
}

Custom annotation instead of @immutable?

Hey!

I was wondering whether it would be better to introduce a custom annotation if one wants to add the generator to an existing project which uses @immutable already for the analyzer.

What do you think?

Generate "copyAs" methods

Sometimes we have a union with common properties between the different possibilities:

@immutable
abstract class TodoList with _$TodoList {
  factory TodoList.data(List<Todo> todos) = TodoListData;
  factory TodoList.loading(List<Todo> todos) = TodoListLoading;
  factory TodoList.error(List<Todo> todos, [String message]) = TodoListError;
}

In such a situation, it is common to want to convert from one state to another, while preserving the common properties.

Currently, we have to use do it ourselves:

var todo = TodoList.data([]);
todo = TodoList.loading(todo.todos);
todo = TodoList.error(toto.todos, 'Error');

But we could simplify that by having a copyWith that converts to a new type:

var todo = TodoList.data([]);

todo = todo.copyAsLoading();
todo = todo.copyAsError(message: 'Error');

Support methods

As mentioned in #56, it's useful to have custom methods inside a freezed class. I would argue that those methods should be able to be written manually, not just generated. Something like #11 but with methods.

I agree that copy-pasting the implementation is not the nicest solution. For now, though, I have to resort to extensions.

json_serializable warnings

Hi.

First, I'm really having fun with this package, will be very useful.

Working with json_serializable, a couple of warnings appear in the g.dart, related to the linter.

Name non-constant identifiers using lowerCamelCase. for FromJson and ToJson method.

This is my freezed class:

@freezed
abstract class Station with _$Station {
  factory Station({String description, String image, String name, String url}) =
      _Station;

  factory Station.fromJson(Map<String, dynamic> json) =>
      _$StationFromJson(json);
}

And the g.dart file have this:

_$_Station _$_$_StationFromJson(Map<String, dynamic> json) {
  return _$_Station(
    description: json['description'] as String,
    image: json['image'] as String,
    name: json['name'] as String,
    url: json['url'] as String,
  );
}

Map<String, dynamic> _$_$_StationToJson(_$_Station instance) =>
    <String, dynamic>{
      'description': instance.description,
      'image': instance.image,
      'name': instance.name,
      'url': instance.url,
    };

I think is adding an extra '_$'. 🤔

Add "isFoo" and "asFoo" getters

It would be very useful, especially if Union classes are declared privately, to have getter generated which checks if the class is of a certain type. Additionally a getter to cast an object to a nested union type would be useful.

Example:

@immutable
abstract class AuthState with _$AuthState {
    const factory AuthState.authorized(User user) = _AuthStateAuthorized;
    const factory AuthState.unauthorized() = _AuthStateUnauthorized;
}

// Some logic which needs user to be authorized
if (!authState.isAuthorized) return;

final authorizedState = authState.asAuthorized; // Returns authState as _AuthStateAuthorized

Support class level decorators

A potential solution for #49

The principle is, any decorator added on a @freezed constructor would be transposed to the generated class.

This means that if we write:

@freezed
abstract class Example with _$Example {
  @deprecated
  factory Example() = GeneratedClass;
}

This would lead to:

@deprecated
class GeneratedClass {
...
}

"Parameters can't override default values" warning in generated toString method

Hi there,
great progress so far on the project, I like the new additions!

I get a warning in all generated freezed files which says:

Parameters can't override default values, this method overrides 'DiagnosticableMixin.toString' where 'minLevel' has a different value.

It refers to the minLevel parameter of the toString method in the _$_Model class.

Nothing too serious for now, but it would be nice to get rid of this warning.
Thanks!

static getter not working since 0.4.0

It seems that static getters on @freezed classes are broken since 0.4.0.

The following file:

test.dart:

import 'package:flutter/foundation.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'test.freezed.dart';
part 'test.g.dart';

@freezed
abstract class Test with _$Test{

  const factory Test() = _Test;

  static int get value => 0;
}

works fine on 0.3.0, but on 0.4.0+ I get this error:

[SEVERE] freezed:freezed on lib/test.dart:
Error running FreezedGenerator
@freezed cannot be used on classes with unimplemented getters
package:freezed_test/test.dart:9:16
  ╷
9 │ abstract class Test with _$Test{

I don't see a reason why static getters would not be supported, I think that's a bug.

static methods still work.

Custom toString methods for Unions

It could be nice to have toString overloads, specially for the lists and complex objects to limit BLOC log for example.

We could use freezedToString attribute for example:

@freezed
abstract class Union with _$Union {
  const factory Union.loaded(@freezedToString((i) => i.length) List<Item> items) = Loaded;
  const factory Union.loading() = Loading;
}

and for the data classes it could be freezedNoToString attribute for example:

@freezedNoToString
abstract class ClubId with _$ClubId {
  const factory ClubId(String value) = _ClubIdDataClass;

  @override
  String toString() {
    return 'ClubId#$value';
  }
}

Adding dependency results in error

I have not even added any union code to my pure dart project and build_runner results in following error:

$ pub run build_runner watch
[SEVERE] Failed to snapshot build script .dart_tool/build/entrypoint/build.dart.
This is likely caused by a misconfigured builder definition.
[SEVERE] ../../../../.pub-cache/hosted/pub.dartlang.org/freezed-0.1.0/lib/src/generator.dart:97:99: Error: The method 'getDisplayString' isn't defined for the class 'DartType'. - 'DartType' is from 'package:analyzer/dart/element/type.dart' ('../../../../.pub-cache/hosted/pub.dartlang.org/analyzer-0.39.0/lib/dart/element/type.dart').Try correcting the name to the name of an existing method, or defining a method named 'getDisplayString'.        for (final property in commonProperties) Getter(name: property.name, type: property.type?.getDisplayString()),                                                                                                  ^^^^^^^^^^^^^^^^../../../../.pub-cache/hosted/pub.dartlang.org/freezed-0.1.0/lib/src/generator.dart:121:64: Error: The method 'getDisplayString' isn't defined for the class 'DartType'. - 'DartType' is from 'package:analyzer/dart/element/type.dart' ('../../../../.pub-cache/hosted/pub.dartlang.org/analyzer-0.39.0/lib/dart/element/type.dart').Try correcting the name to the name of an existing method, or defining a method named 'getDisplayString'.            Property(name: property.name, type: property.type?.getDisplayString())                                                               ^^^^^^^^^^^^^^^^../../../../.pub-cache/hosted/pub.dartlang.org/freezed-0.1.0/lib/src/generator.dart:124:55: Error: The method 'getDisplayString' isn't defined for the class 'DartType'. - 'DartType' is from 'package:analyzer/dart/element/type.dart' ('../../../../.pub-cache/hosted/pub.dartlang.org/analyzer-0.39.0/lib/dart/element/type.dart').Try correcting the name to the name of an existing method, or defining a method named 'getDisplayString'.          return Property(name: p.name, type: p.type?.getDisplayString());                                                      ^^^^^^^^^^^^^^^^../../../../.pub-cache/hosted/pub.dartlang.org/freezed-0.1.0/lib/src/templates/parameter_template.dart:43:25: Error: The method 'getDisplayString' isn't defined for the class 'DartType'. - 'DartType' is from 'package:analyzer/dart/element/type.dart' ('../../../../.pub-cache/hosted/pub.dartlang.org/analyzer-0.39.0/lib/dart/element/type.dart').Try correcting the name to the name of an existing method, or defining a method named 'getDisplayString'.          type: e.type?.getDisplayString(),                        ^^^^^^^^^^^^^^^^../../../../.pub-cache/hosted/pub.dartlang.org/freezed-0.1.0/lib/src/templates/parameter_template.dart:51:23: Error: The method 'getDisplayString' isn't defined for the class 'DartType'. - 'DartType' is from 'package:analyzer/dart/element/type.dart' ('../../../../.pub-cache/hosted/pub.dartlang.org/analyzer-0.39.0/lib/dart/element/type.dart').Try correcting the name to the name of an existing method, or defining a method named 'getDisplayString'.        type: e.type?.getDisplayString(),                      ^^^^^^^^^^^^^^^^

Same happens when I add freezed union code.

Pub 2.7.0
analyzer 0.39.0
build_runner 1.7.4
freezed 0.1.0
source_gen 0.9.4+7

missing generic type in .fromJson

after creating these model classes on version 0.2.4...

/// model.dart

import 'package:json_annotation/json_annotation.dart';
import 'package:flutter/foundation.dart';

part 'model.freezed.dart';
part 'model.g.dart';

@immutable
abstract class Parent<T> with _$Parent<T> {
  const factory Parent(@DataConverter() List<T> items) = _Parent<T>;

  factory Parent.fromJson(Map<String, dynamic> json) =>
      _$ParentFromJson<T>(json);
}

@immutable
abstract class Item with _$Item {
  const factory Item(String name) = _Item;

  factory Item.fromJson(Map<String, dynamic> json) => _$ItemFromJson(json);
}

class DataConverter<T> implements JsonConverter<T, Object> {
  const DataConverter();

  @override
  T fromJson(Object json) {
    return Item.fromJson(json) as T;
  }

  @override
  Object toJson(T object) {
    return object;
  }
}

... i am going to run the default sample project. ( flutter create ). It will result in the following error:

lib/model.freezed.dart:74:57: Error: The constructor function type '_$_Parent<dynamic> Function(Map<String, dynamic>)' isn't a subtype of '_Parent<T> Function(Map<String, dynamic>)'.
 - '_$_Parent' is from 'package:freezed_test/model.dart' ('lib/model.dart').
 - 'Map' is from 'dart:core'.
 - '_Parent' is from 'package:freezed_test/model.dart' ('lib/model.dart').
  factory _Parent.fromJson(Map<String, dynamic> json) = _$_Parent.fromJson;

I can fix the error by opening model.freezed and change

/// model.freezed.dart:74

factory _Parent.fromJson(Map<String, dynamic> json) = _$_Parent.fromJson;
to
factory _Parent.fromJson(Map<String, dynamic> json) = _$_Parent<T>.fromJson;

Support for better error messages

To make it easier for new consumer it would be great to add better error messages if things are misconfigured. So far error messages look rather cryptic.

Not using the provided @JsonKey annotation on the generated code

For example I have the following code:

@freezed
@immutable
abstract class QAccount1 with _$QAccount1 {
  factory QAccount1({
    @JsonKey(name: 'email') @required String id,
    @JsonKey(name: 'username') String name,
    @JsonKey(name: 'avatar_url') String avatarUrl,
    @JsonKey(name: 'extras', nullable: true) Map<String, dynamic> extras,
    @JsonKey(name: 'last_comment_id') int lastMessageId,
    @JsonKey(name: 'last_sync_event_id') int lastEventId,
  }) = _QAccount1;

  factory QAccount1.fromJson(Map<String, dynamic> json) =>
      _$QAccount1FromJson(json);
}

Freezed should generate:

// This is taken from json_serializable
QAccount1 _$QAccountFromJson(Map<String, dynamic> json) {
  return QAccount1(
    id: json['email'] as String,
    name: json['username'] as String,
    avatarUrl: json['avatar_url'] as String,
    extras: json['extras'] as Map<String, dynamic>,
    lastMessageId: json['last_comment_id'] as int,
    lastEventId: json['last_sync_event_id'] as int,
  );
}

but the actual generated code are:

_$_QAccount1 _$_$_QAccount1FromJson(Map<String, dynamic> json) {
  return _$_QAccount1(
    id: json['id'] as String,
    name: json['name'] as String,
    avatarUrl: json['avatarUrl'] as String,
    extras: json['extras'] as Map<String, dynamic>,
    lastMessageId: json['lastMessageId'] as String,
    lastEventId: json['lastEventId'] as String,
  );
}

As you can see, generated code still using id instead of email

inconsistant hashCode implementation

Generated classes containing Lists violate the contract of the hashCode function:

Hash codes must be the same for objects that are equal to each other according to [operator ==].

For the simple class:

@freezed
abstract class Data with _$Data {
  factory Data({
    List<String> keys,
  }) = _Data;
}

the following test fails due to different hashCode values

void main() {
  test("test", () {
    Data buildItem() {
      return Data(keys: ["VALUE"]);
    }

    final data1 = buildItem();
    final data2 = buildItem();

    expect(data1, equals(data2));
    expect(data1.hashCode, equals(data2.hashCode));
  });
}

support custom json converter for generic fields

this feature is already available in json_serializable package:

@JsonSerializable()
class Response<T>{
int status;
T data;

Response(this.status,this.data);

factory Response.fromJson(Map<String, dynamic> json) =>
 _$ResponseFromJson(json);

  Map<String, dynamic> toJson() => _$ResponseToJson(this);    
}
@JsonSerializable()
class PersonResponse {
  Person person;

  PersonResponse(this.person);

  factory PersonResponse.fromJson(Map<String, dynamic> json) =>
      _$PersonResponseFromJson(json);

  Map<String, dynamic> toJson() => _$PersonResponseToJson(this);
}
@JsonSerializable()
class PeopleResponse {
  final int count;
  final List<Person> people;

  PeopleResponse(this.count, this.people);

  factory PeopleResponse.fromJson(Map<String, dynamic> json) =>
      _$PeopleResponseFromJson(json);

  Map<String, dynamic> toJson() => _$PeopleResponseToJson(this);
}
@JsonSerializable()
class Person {
 String name ;
 int age; 

 Person(this.name,this.age);  

 factory Person.fromJson(Map<String, dynamic> json) =>
 _$PersonFromJson(json);

 Map<String, dynamic> toJson() => _$PersonToJson(this); 
}

where T could be PersonResponse or PeopleResponse

you can't run this code because the generator will raise this error

Could not generate `fromJson` code for `data`.
None of the provided `TypeHelper` instances support the defined type.

this code won't work until i provide custom converter to the generic variable:

class DataConverter<T> implements JsonConverter<T, Object>{
  const DataConverter();

  @override
  T fromJson(Object json) {
    final data = json as Map<String, dynamic>;
    if (data.containsKey('person')) {
      return PersonResponse.fromJson(data) as T;
    }
    return PeopleResponse.fromJson(data) as T;
  }

  @override
  Object toJson(T object) {
    if (object is PersonResponse) {
      return object.toJson();
    }
    return (object as PeoplePayload).toJson();
  }
}

then modify the Response class to work as expected:

@JsonSerializable()
class Response<T> {
  int status;
  @DataConverter() // <--- custom converter annotation
  T data;

  Response(this.status, this.data);

  factory Response.fromJson(Map<String, dynamic> json) =>
      _$ResponseFromJson(json);

  Map<String, dynamic> toJson() => _$ResponseToJson(this);
}

i suggest you add this annotaion to the factory constructor:

@immutable
class Response<T>{
    factory Response(
    int status,
    @DataConverter() T data, // <--- custom converter annotation
    ) = _Response;

    factory Response.fromJson(Map<String, dynamic> json) => _$ResponseFromJson(json);
}

0.2.0: copyWith not accessible when including json_serializable

Hi there! Your package looks very promising - we can't wait to replace built_value with it.

This is what I found out while trying the laaaatest version:

// main.dart
import 'package:flutter/foundation.dart';
import 'package:json_annotation/json_annotation.dart';

part 'model.freezed.dart';
part 'model.g.dart';

@immutable
abstract class Model with _$Model {
  factory Model({String a, List<Model> models}) = _Model;

  factory Model.fromJson(Map<String, dynamic> json) => _$ModelFromJson(json);
}

main() {
  var model = Model(
    a: 'hol',
    models: [
      Model(
        a: 'no',
        models: const [],
      ),
    ],
  );

  model.copyWith(a: 't'); // => no
}

In the last line copyWith is not accessible - I could, however, use _Model instead

Support actual factories

Consider:

@immutable
abstract class Example with _$Example {
  const factory Example(String a, {int b}) = Example0;

  factory Example.fixed() {
    return const Example('a', b: 42);
  }
}

This shouldn't generate code for fixed

Inheritance question

Do you have an example of how I can implement inheritance? E.g. type animal has a name and type cat has a name and a color...

Add "const" modifier for non-primitive @Default() values

consider this sample:

@freezed
abstract class DefaultList
    with _$DefaultList {
  const factory DefaultList(
      {@Default(<String>[]) List<String> values,}) = _DefaultList;
}

this will generate this code:

class _$_DefaultList with DiagnosticableTreeMixin implements _DefaultList {
  const _$_DefaultList({@Default(<String>[]) this.values = <String>[] // <- this should be const!
 }); 
...

which won't compile as the default value of values is not constant in the generated code.

Since parameters of annotations are implicitly constant, users can omit the "const" modifier there, and will get a warning if they use it in an already constant context if they use pedantic.

Expected Result:

freezed should insert the "const" modifier if the user omits it in the @Default annotation for list literals, set literals, map literals and classes with const constructors.

support for all @JsonSeriazable() paramaters

ex:

@JsonSerializable(fieldRename: FieldRename.snake)
class Person {
 // will convert camal case to snake case automatically 
//  equivelant to JsonKey(name:"first_name")
  String firstName;
}

suggestion:

@SerializableFreezed(fieldRename: FieldRename.snake)
class Person {
  factory Person(String firstName) = _Person;
}

Support default values

While factory constructors using factory Class() = Something; can't define default values, we could have:

abstract class Example with _$Example {
  factory Example(@Default(42) int value) = _Example;
}

This would also be added to @JsonKey if none are specified:

@JsonKey(defaultValue: 42)

Conflicting factory and parameter name

Hey,

I currently get a build error due to an error that the argument type can't be assigned to the parameter type:

@immutable
abstract class Example with _$Example {
  factory Example.something() = Something;
  factory Example.error(Error error) = SomeError;
}

This happens in the generated when and maybeWhen in _$SomeError when the passed error function will be called with the field error. All parameters should be references with e.g. this.error instead.

list arguments break the code generation

If you use the code from the example with generics and try to change the default factory putting a list as a parameter, you will encounter an error during the code generation:

part 'union.freezed.dart';

@immutable
abstract class Union<T> with _$Union<T> {
  const factory Union(List<T> value) = Data<T>;
  const factory Union.apiError(WebException webException) = ApiErrorDetails<T>;
  const factory Union.connectionError() = ConnectionErrorDetails<T>;
}
Error formatting generated source code for [...] which was output to [...].
This may indicate an issue in the generated code or in the formatter.
Please check the generated code and file an issue on source_gen if appropriate.
Could not format because the source could not be parsed:

line 24, column 1: Expected to find ')'.
   ╷
24 │ }
   │ ^
   ╵
line 24, column 1: Expected to find ')'.
   ╷
24 │ }
   │ ^
   ╵
line 45, column 1: Expected to find ')'.
   ╷
45 │ }
   │ ^
   ╵
line 57, column 1: Expected to find ')'.
   ╷
57 │ }
   │ ^
   ╵
line 91, column 1: Expected to find ')'.
   ╷
91 │ }
   │ ^
   ╵
line 91, column 1: Expected to find ')'.
   ╷
91 │ }
   │ ^
   ╵
line 91, column 1: Expected to find ')'.
   ╷
91 │ }
   │ ^
   ╵
line 91, column 1: Expected to find ')'.
   ╷
91 │ }
   │ ^
   ╵
line 104, column 1: Expected to find ')'.
    ╷
104 │ }
    │ ^
    ╵
line 104, column 1: Expected to find ')'.
    ╷
104 │ }
    │ ^
    ╵
(8 more errors...)
[INFO] Running build completed, took 749ms

[INFO] Caching finalized dependency graph...
[INFO] Caching finalized dependency graph completed, took 34ms

[SEVERE] Failed after 790ms

Prefer mixin lint rule

Generated _$Union is abstract class. With lint rule 'prefer_mixin' link enabled there is warning.

Is there a special reason to have it as an abstract class?
Of course, this issue does not have any negative impact, just reason

Generate custom fromWhatever/toWhatever

Right now Freezed only support fromJson.
But as showcased by Brian Egan's sample app, sometimes we may want to convert to and from a different class.

For example, instead of:

@freezed
abstract class Todo with _$Todo {
  factory Todo(String task, {bool complete, String note, String id}) = _Todo;

  factory Todo fromEntity(TodoEntity entity) {
    return Todo(
      entity.task,
      complete: entity.complete ?? false,
      note: entity.note,
      id: entity.id,
    );
  }
}

extension TodoToEntity on Todo {
  TodoEntity toEntity() {
    return TodoEntity(task, id, note, complete);
  }
}

We could write:

@freezed
abstract class Todo with _$Todo {
  factory Todo(String task, {bool complete, String note, String id}) = _Todo;

  factory Todo.fromEntity(TodoEntity entity) => _$TodoFromEntity(entity);
}

Minor warnings "Use generic function type syntax for parameters."

I did this little class:

@freezed
abstract class NumberTriviaEvent2 with _$NumberTriviaEvent2 {
  const factory NumberTriviaEvent2.getTriviaForConcreteNumber2(
      String numberString) = GetTriviaForConcreteNumber2;

  const factory NumberTriviaEvent2.getTriviaForRandomNumber2() =
      GetTriviaForRandomNumber2;
}

In the generated file I have:

mixin _$NumberTriviaEvent2 {
  @optionalTypeArgs
  Result when<Result extends Object>({
    @required Result getTriviaForConcreteNumber2(String numberString),
    @required Result getTriviaForRandomNumber2(),
  }); . . .
. . .

But flutter complains:
... @required Result getTriviaForConcreteNumber2(String numberString), ...
and suggests this way:
... Result Function(String numberString) getTriviaForConcreteNumber2, ...

FromJson(json)

Hi Remi,

great work, again :)
FromJson(json) will generate code that requires a property called runtimeType in my map.

Planets _$PlanetsFromJson(Map<String, dynamic> json) {
  assert(json['runtimeType'] is String);
  switch (json['runtimeType'] as String) {
    case 'default':
      return _Planets.fromJson(json);

    default:
      throw FallThroughError();
  }
}

Am i supposed to add runtimeType to every Map ?
Imagine the following response:

{
	"count": 1,
	"results": [
		{
			"name": "Alderaan"
                }
         ]
}

2 Maps, 2 Models.

Planets {
  List<Planet> planets
}

Planet {
 String name
}

Annoying json_serializable bug

On my production project freezed is not generating g.dart file, the problem is that I could not reproduce this bug on a test project.

Creating a test project everything works fine, copying the working fine class of test to production and the .g.dart is not generated.

I tried do add all pubspec dependencies of production project at test project, and test still working.
json_serializable classes is working well when not generated by freezed.

I dont know what to do to find this bug, any idea?

Supporting List of non primitive types in toJson

Hi,

There's a problem when using property List of generated items, toJson method works incorrect.

@immutable
abstract class VideoModel with _$VideoModel {
  const factory VideoModel({@JsonKey(name: 'id') String id,
    @JsonKey(name: 'iso_639_1') String iso639,
    @JsonKey(name: 'iso_3166_1') String iso3166,
    @JsonKey(name: 'key') String key,
    @JsonKey(name: 'name') String name,
    @JsonKey(name: 'site') String site,
    @JsonKey(name: 'size') int size,
    @JsonKey(name: 'type') String type}) = _VideoModel;

  factory VideoModel.fromJson(Map<String, dynamic> json) =>
      _$VideoModelFromJson(json);
}

@immutable
abstract class DataVideosModel with _$DataVideosModel {
  const factory DataVideosModel(
      {@JsonKey(name: 'results') List<VideoModel> results,
        @JsonKey(name: 'id') int id}) = _DataVideosModel;

  factory DataVideosModel.fromJson(Map<String, dynamic> json) =>
      _$DataVideosModelFromJson(json);
}

Currently toJson method is generated like:

Map<String, dynamic> _$_$_DataVideosModelToJson(_$_DataVideosModel instance) =>
    <String, dynamic>{
      'results': instance.results,
      'id': instance.id,
    };

Could you make supporting List in toJson method like this: (in that cases when List isn't List of primivite types)

Map<String, dynamic> _$_$_DataVideosModelToJson(_$_DataVideosModel instance) =>
    <String, dynamic>{
      'results': instance.results.map((result) => result.toJson()),
      'id': instance.id,
    };

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.