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

Created on 9 Feb 2020  ยท  12Comments  ยท  Source: rrousselGit/freezed

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;
}

Most helpful comment

Done ๐Ÿ‘Œ

All 12 comments

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

That's expected

It sounds more like a problem with parsing the name.

Could you give a minimalist way of reproducing the error?

When creating the demo project, I probably found the root of the issue. Code gen kicks in even for classes which don't extend _$SomeClass. While this minimal project written as a console app produces errors, they are not the same as in the case which I described with the BLoC.

UPDATE: The repository now also contains a minimal example with BLoC where Event is freezed and State is just a regular class marked as @immutable.

I'll take a look, thanks

Note that removing the @immutable on NonFreezedClass will fix the issue.

I'll think of a proper fix. The main problem is, since the interface is generated, the analyzer doesn't pick it up because it doesn't exist yet

Removing @immutable works in the example, even with BLoC. For some reason though, this doesn't work on my real code. I can't really share it as there's a lot of specifics going on and it's definitely not a minimal example.

In the meantime, I'll try to migrate the regular class to a freezed data class. That should work ๐Ÿคž

I think that instead of "don't generate if it doesn't mix-in _$MyCLass", I'll go with "don't generate if the class has a property"

Sounds reasonable. Anyway, this issue forced me to rethink my legacy approach to pure immutable classes and now I use freezed even for them. Works perfectly, thanks again!

I just have to use static methods instead of factories to have "predefined state configurations" which is a bit of an antipattern in Dart but I can live with that ๐Ÿ˜„

I just have to use static methods instead of factories to have "predefined state configurations" which is a bit of an antipattern in Dart but I can live with that ๐Ÿ˜„

What do you mean?

Well, the static method is an anti-pattern, isn't it? I even have to ignore lint.

@immutable
abstract class SignInFormState with _$SignInFormState {
  const factory SignInFormState({
    EmailAddress validatedEmailAddress,
    Password validatedPassword,
    bool autovalidate,
    bool isSubmitting,
    Either<AuthFailure, Unit> isSuccess,
  }) = _SignInFormState;

  // ignore: prefer_constructors_over_static_methods
  static SignInFormState initial() {
    return SignInFormState(
      validatedEmailAddress: EmailAddress(''),
      validatedPassword: Password(''),
      autovalidate: false,
      isSubmitting: false,
      isSuccess: null,
    );
  }
}

Yeah I forgot to test that. I'll fix it.

But to be fair, your example should be a static const instead of a static function

Kind of, but EmailAddress cannot be const anyway as there's some validation going on inside of it. Otherwise, you're correct.

Done ๐Ÿ‘Œ

Was this page helpful?
0 / 5 - 0 ratings