Giter VIP home page Giter VIP logo

super_enum's Issues

How can I convert a String to a Enum Type

I would like to generate a super enum Type from a String.
I would expect something like:

MyEnum enum = MyEnum.fromString(String Name);

Actually, support for the roundtrip String conversion should be supported from and to String.

Can you please make a release?

Thanks for this great work. I'm looking forward to using the required property on DataFields, but I see that's not released on DartPub yet.

Add factory constructors for derived classes to mimic enums

eg :

abstract class LoginResponse {
  // Not necessary when case classes are public, 
  // but I usually put factories and constants on the base class.
  
  factory LoginResponse.success(authToken) = LoginSuccess;
  static const invalidCredentials = const InvalidLoginCredentials();
  static const noNetwork = const NoNetworkForLogin();
  factory LoginResponse.unexpectedException(Exception exception) = UnexpectedLoginException;
}

WhenPartial breaks when updraging from 0.3.0 to 0.4.2

so i'm getting these weird errors because i use whenPartial in my bloc's mapEventToState.

yield* event.whenPartial(
  someEvent: (_) async* {
     // some logic
     return State.someState();
  }
);

not sure why it's not working anymore

DataFields with a name including 'T' break code generation

Latest update (0.4.0, released several hours ago) has a very bad bug.

Any data field with a capital 'T' in the name appears to break code generation, yielding the standard comment header and the single line:
/*State must be annotated with @generic*/

To reproduce:

The following works properly -- exactly as you would expect:

import 'package:super_enum/super_enum.dart';

part 'super_enum_sample.g.dart';

class SomeVee {
  String data;
}

@superEnum
enum _StatesGood {
  @Data(fields: [
    DataField<SomeVee>('fieldName'),
  ])
  State
}

The following fails, and is the same other than the type of field, now being SomeTee instead of SomeVee (T in the name vs no T in the name).

import 'package:super_enum/super_enum.dart';

part 'super_enum_sample.g.dart';

class SomeTee {
  String data;
}

@superEnum
enum _StatesBad {
  @Data(fields: [
    DataField<SomeTee>('fieldName'),
  ])
  State
}

The problem stems from line 377 of class_generator.dart

    if (_classFields
        .any((e) => type_processor.dataFieldType(e).contains('T'))) {
      if (!isGeneric) {
        throw InvalidGenerationSourceError(
            '${field.name} must be annotated with @generic');
      }
    }

(Hairy debug session to find this... 'my T' was in a complex type using built values and I had a lot of suspicions to track down before I got to "does it include a capital T' ;-)

Love all the new features, thanks for all your hard work!

emit `when` method arguments for "empty" actions

Given I have a super_enum definition like this:

@superEnum
enum _ContactUsAction {
  CallPhone,
  StartLiveChat
}

Then the generated when method looks like this:

  R when<R>(
      {@required
          FutureOr<R> Function(CallPhone) callPhone,
      @required
          FutureOr<R> Function(StartLiveChat) startLiveChat}) {

...

could this possibly be simplified to:

  R when<R>(
      {@required
          FutureOr<R> Function() callPhone,
      @required
          FutureOr<R> Function() startLiveChat}) {

...

As from my point of view, the event has no associated values and thus does not need to be passed into the when method.

use const constructor

Hey,

I really love your package ! Thanks a lot for putting so much effort into it !

I only have a super small suggestion for improvement:
You have const constructors but you don't use them in the factorys (for @object's).
For example:

@immutable
class Empty extends ExampleState {
  const Empty._() : super(ExampleState .Empty);

  factory Empty() {
    _instance ??= Empty._(); // -> _instance ??= const Empty._()
    return _instance;
  }

  static Empty _instance;
}

There is no problem in that, but my linting settings mark this as an warning :)

Use external class directly without wrapping

Sometimes I share classes between multiple superEnums. This is currently only possible by wrapping them each time I use them.

class ApiError { /*...*/ }

@superEnum
enum _ResultA {
  @Data(fields: [
    DataField('error', ApiError),
  ])
  Error,
}

@superEnum
enum _ResultB {
  @Data(fields: [
    DataField('error', ApiError),
  ])
  Error,
}

I'd prefer to use some classes directly without having them auto-generated and wrapped.

class ApiError { /*...*/ }

@superEnum
enum _ResultA {
  @UserClass(ApiError)
  Error,
}

@superEnum
enum _ResultB {
  @UserClass(ApiError)
  Error,
}

Copy comments to generated file

It would be very helpful when comments on the enum values would also be rendered to the generated source

@superEnum
enum _Result {
  /// Comment #1
  @generic
  @Data(fields: [
    DataField('data', Generic),
    DataField('message', String),
  ])
  Success,

  @object
  Error,
}
abstract class Result<T> extends Equatable {
  const Result(this._type);

   /// Comment #1
  factory Result.success({@required T data, @required String message}) =
      Success<T>;

  // ...
}

/// Comment #1
class Success<T> extends Result<T> {
  /// Comment #1
  const Success({@required this.data, @required this.message})
      : super(_Result.Success);
  

Enum as data field in another enum

I'm trying to do this:

@superEnum
enum _SelectedContact {
  @Data(fields: [DataField('user', User)])
  InternalUser,

  @Data(fields: [DataField('contact', Contact)])
  AddressBook,
}

Where Contact is another super enum defined in a different file. When building this, the generated file only contains the following comment, and no code:

/*FormatException: Not an instance of Type.*/

Is reusing enums in other enums not allowed?

Generics support?

This is more of a question than anything else.

It would be really cool if we could define generic types like so:

@superEnum
enum _Result<T> {
  @object
  NotLoaded,

  @object
  Loading,

  @object
  Error,

  @Data(fields: [
    DataField('data', T),
  ])
  Loaded,
}

This would be extremely useful as we could use the same _Result type to handle multiple model classes.

However I assume this can't be done as Dart doesn't support enums with generics?

Would this be achievable by using standard classes?

Great library btw!

Linter Warnings: DO use curly braces for all flow control structures

The generated code sometimes provokes the analyzer (under pedantic settings) to issue the warning: "DO use curly braces for all flow control structures".

It can be fixed either by generating braces when you have an if with a single line body (these single line bodies currently appear when you throw).

Or faster, you could take the approach that built_value does and just suppress warnings at the file level by generating the following line at the bottom of each .g.dart file:

// ignore_for_file: curly_braces_in_flow_control_structures

Details:
It happens sometimes where the generated code includes throws clauses that aren't surrounded by braces, e.g.:

//ignore: missing_return
  FutureOr<R> when<R>(
      {@required FutureOr<R> Function(UpdateFilter) updateFilter,
      @required FutureOr<R> Function(UpdateFeatures) updateFeatures}) {
    assert(() {
      if (updateFilter == null || updateFeatures == null)
        throw 'check for all possible cases';
      return true;
    }());
    ....

Here, it happens because throw 'check for all possible cases'; is formatted alone on a line.

It only causes linter warnings sometimes, because oddly, if the formatter keeps the throw on the same line as the if or an || as shown below, there is no linter warning.

      if (updateFilter == null || ... || ...
          || updateFeatures == null) throw 'check for all possible cases';

Why renaming enum fields?

Why does the generator rename enum fields? For example, if I define the following enum

@superEnum
enum _Result {
  @object
  Success,

  @object
  Error
}

...Success becomes success and Error becomes error. Is there a reason for this? I think it would be better to keep the original names to avoid confusion.

Optional fields

Currently the generator adds "@required" to all DataField objects.

We should have a parameter to indicate if this is really required parameter, like:

    DataField<String>("errorMessage", required: false),

This way, the library will be 100% ready for the NNBD next release of Dart language:
dart-lang/language#110

analyzer version compatibility issues when used with built_value_generator

After upgrading packages, built_value_generator ^7.0.8 and super_enum_generator ^0.3.0 are conflicting on analyzer version:

Because super_enum_generator >=0.2.0+1 depends on analyzer >=0.37.1 <0.39.1 and
built_value_generator >=7.0.8 depends on analyzer ^0.39.3, super_enum_generator >=0.2.0+1 
is incompatible with built_value_generator >=7.0.8.

pub upgrade failed (1; So, because ___ depends on both built_value_generator ^7.0.8 
and super_enum_generator ^0.3.0, version solving failed.)

Enums with Value

the "extension"s has been added since Dart 2.6 so it would be great if we have Enums with default values. for example:

enum Country {
  UnitedArabEmirates,
  Argentina,
  Austria,
  Australia,
  Belgium,
  Bulgaria,
  Brazil,
}

extension CountryExtension on Country {
  String getValue() {
    switch (this) {
      case Country.UnitedArabEmirates:
        return "ae";
      case Country.Argentina:
        return "ar";
      case Country.Austria:
        return "at";
      case Country.Australia:
        return "au";
      case Country.Belgium:
        return "be";
      case Country.Bulgaria:
        return "bg";
      case Country.Brazil:
        return "br";
      default:
        return "COUNTRY NOT FOUND";
    }
  }
}

main(){
	var au = Country.Australia;
	print('the country code of Australia is ${au}');
}

as I represented, we can do it our selves but it would be nice if we can define that like this:

@superEnum
enum Country {
  @object(value: "ae")
  UnitedArabEmirates,
  @object(value: "ar")
  Argentina,
  @object(value: "at")
  Austria,
  @object(value: "au")
  Australia,
  @object(value: "be")
  Belgium,
  @object(value: "bg")
  Bulgaria,
  @object(value: "br")
  Brazil,
}

main(){
	var au = Country.Australia;
	print('the country code of Australia is ${au.value}');
}

Thnaks,

Linter Error with super_enum_generator 0.4.2

I do get a linter error 'return_of_invalid_type' in the generated R when<R>, R whenOrElse<R> etc. methods. you are returning a FutureOr and not R.
(Flutter (Channel beta, v1.14.6, on Mac OS X 10.15.3 19D76, locale de-DE))

@UseClass generating Error

Hey guys,

I just ran into another code generation error.
When using the same Class in @useClass() the build_runner generates the wrapper twice.

For example this:

@superEnum
enum _RevenueState {
  @object
  Empty,
  @UseClass(RevenueLoaded)
  YearLoaded,
  @UseClass(RevenueLoaded)
  MonthLoaded,
  @Data(fields: [DataField<String>('message')])
  Error,
}
class RevenueLoaded {
  final Revenue revenue;
  const RevenueLoaded({
    @required this.revenue,
  });
}

Generates the RevenueLoadedwWrapper twice

Have a nice day !

Unhandled Exception when using Generics

When using generics, I am getting a type casting exceptions given the following example

@superEnum
enum _ModelState {
  @generic
  @Data(fields: [DataField('data', Generic)])
  Success,

  @object
  Error,

  @object
  Loading,

  @object
  Empty,
}

//Somewhere else in code
Stream<ModelState<int>> getSomething() {
  return Stream.fromFuture(Future.value(1))
      .publishReplay(maxSize: 1)
      .refCount()
      .map((data) => ModelState.loading());
}

The error:

Unhandled Exception: type 'Loading<dynamic>' is not a subtype of type 'Loading<int>'

Environment:

Flutter 1.12.13+hotfix.6
Framework • revision 18cd7a3601 (7 days ago) • 2019-12-11 06:35:39 -0800
Engine • revision 2994f7e1e6
Tools • Dart 2.7.0

Dependencies:

dependencies:
  super_enum: ^0.2.0

dev_dependencies:
  super_enum_generator: ^0.2.0+1
  build_runner: ^1.7.1

whenXXX methods return FutureOr

The update to 0.3 modified when() and its new sibling methods to return FutureOr.

The Effective Dart advice is to use FutureOr as a parameter, but not to return it. They advise instead to just return Future, as it will be more clear to users (who need to await the result either way).

https://dart.dev/guides/language/effective-dart/design#avoid-using-futureort-as-a-return-type

So the generator would produce

  Future<R> when<R>(
      {@required FutureOr<R> Function(Success) success,
      @required FutureOr<R> Function(Error) error}) async {
}

with Future / async instead of FutureOr

  FutureOr<R> when<R>(
      {@required FutureOr<R> Function(Success) success,
      @required FutureOr<R> Function(Error) error}) {
}

(That may also save you from having to document how to use the return types, as many of your users won't have experience dealing with a FutureOr return.)

Thanks for the new whenXXX methods, and for fixing the generation of null props for @objects!

Version compatibility issues (`analyzer`, `super_enum`, `json_serializable`)

I'm running on a project that uses super_enum, along with other codegen packages.

Relevant portion of my pubspec.yaml:

environment:
  sdk: ">=2.5.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter  
  json_annotation: any
  provider: any
  http: any
  logger: any
  intl: any
  super_enum: any
  cupertino_icons: ^0.1.2

dev_dependencies:
  flutter_test:
    sdk: flutter
  build_runner: any
  json_serializable: any
  super_enum_generator: any

Output of flutter packages get:

[weather_app_flutter] flutter packages get
Running "flutter pub get" in weather_app_flutter...             
The current Dart SDK version is 2.5.0.



Because json_serializable >=2.0.1 <2.0.2 depends on analyzer >=0.32.2 <0.35.0 and json_serializable >=1.5.1 <2.0.1 depends on analyzer >=0.32.2 <0.34.0, json_serializable >=1.5.1 <2.0.2 requires analyzer >=0.32.2 <0.35.0.

And because json_serializable >=1.0.0 <1.5.1 depends on analyzer ^0.32.2 and json_serializable >=0.5.8+1 <1.4.0 depends on build ^0.12.6, json_serializable >=0.5.8+1 <2.0.2 requires analyzer >=0.32.2 <0.35.0 or build ^0.12.6.

And because every version of super_enum_generator depends on build ^1.2.1 and json_serializable >=3.2.1 <3.2.3 depends on analyzer >=0.33.3 <0.39.0, if super_enum_generator any and json_serializable >=0.5.8+1 <2.0.2-∞ or >=3.2.1 <3.2.3-∞ then analyzer >=0.32.2 <0.39.0.

And because json_serializable >=3.1.0 <3.2.1 depends on analyzer >=0.33.3 <0.38.0 and json_serializable >=2.1.1 <3.1.0 depends on analyzer >=0.33.3 <0.37.0, if super_enum_generator any and json_serializable >=0.5.8+1 <2.0.2-∞ or >=2.1.1 <3.2.3-∞ then analyzer >=0.32.2 <0.39.0.

And because json_serializable >=2.0.2 <2.1.1 depends on analyzer >=0.33.3 <0.36.0 and json_serializable <=0.5.8 requires SDK version >=1.22.1 <2.0.0-∞, if super_enum_generator any and json_serializable <3.2.3 then analyzer >=0.32.2 <0.39.0.

And because no versions of json_serializable match >3.2.3 and every version of super_enum_generator depends on analyzer ^0.39.1, super_enum_generator is incompatible with json_serializable.

So, because weather_app_flutter depends on both json_serializable any and super_enum_generator any, version solving failed.
pub get failed (1)
exit code 1

Output of flutter doctor:

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.9.1+hotfix.4, on Mac OS X 10.14.4 18E226, locale en-GB)
 
[!] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    ! Some Android licenses not accepted.  To resolve this, run: flutter doctor --android-licenses
[✓] Xcode - develop for iOS and macOS (Xcode 11.1)
[✓] Android Studio (version 3.5)
[✓] VS Code (version 1.40.2)
[✓] Connected device (1 available)

! Doctor found issues in 1 category.

Any guidance on how to solve the incompatibilities issues?

@object enum values generated as: List get props =>null

A consequence of generating List get props => null; is that (with the current Equatable package: equatable 1.0.1), calling hashCode on a generated @object throws NoSuchMethodError.

To reproduce:

import 'package:super_enum/super_enum.dart';
part "my_state.g.dart";

@superEnum
enum _MyState {
  @object
  Success,
  @object
  Error,
}
  • flutter pub run build_runner build
...
  // any running code
  var success = MyState.success();
  success.hashCode;

BOOM!
NoSuchMethodError: The method 'fold' was called on null.
Receiver: null
Tried calling: fold(0, Closure: (int, dynamic) => i

I got bit pretty hard by this tonight, in test code checking emitsInOrder on a StreamController, but hashCode is called in plenty of situations.

The bug arises because the generator produces

List get props => null;

Instead the generator needs to produce:

List get props => const [];

I see you have an outstanding pull request on an unrelated issue that silently fixes this: #23

(small nit: that fix assigns props [] and not const []).

Not knowing the timeline for that PR, I wanted to raise this as a separate (and urgent) issue.

Ability to specify generated class names.

Would like the ability to specify the name to use when computing sealed class. This would remove collisions when creating similarly named classes. See the following example taken from sealed_unions_generator

@Seal('WeatherState')
abstract class WeatherModel {
  @Sealed()
  void initial();
  @Sealed()
  void loading();
  @Sealed()
  void loaded(int temperature);
}

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'weather_model.dart';

// **************************************************************************
// SealedUnionsGenerator
// **************************************************************************

class WeatherState extends Union3Impl<WeatherStateInitial, WeatherStateLoading,
    WeatherStateLoaded> {
  static final Triplet<WeatherStateInitial, WeatherStateLoading,
          WeatherStateLoaded> _factory =
      const Triplet<WeatherStateInitial, WeatherStateLoading,
          WeatherStateLoaded>();

  WeatherState._(
      Union3<WeatherStateInitial, WeatherStateLoading, WeatherStateLoaded>
          union)
      : super(union);

  factory WeatherState.initial() =>
      WeatherState._(_factory.first(WeatherStateInitial()));

  factory WeatherState.loading() =>
      WeatherState._(_factory.second(WeatherStateLoading()));

  factory WeatherState.loaded(int temperature) =>
      WeatherState._(_factory.third(WeatherStateLoaded(temperature)));
}

class WeatherStateInitial {
  WeatherStateInitial();
}

class WeatherStateLoading {
  WeatherStateLoading();
}

class WeatherStateLoaded {
  final int temperature;

  WeatherStateLoaded(this.temperature);
}

Create a DataField with specific type of generic type

I have trouble using a specific type of generic type in DataField. Let's take List<int> for example.

@superEnum
class _Event {
    @Data(fields: [DataField('foo', List<int>)])
    Foo,
}

The above code won't compile, with following error message:

  error • In constant expressions, operands of this operator must be of type 'num' •
  error • The operator '<' isn't defined for the class 'Type' •
  error • A comparison expression can't be an operand of another comparison expression •
  error • Arguments of a constant creation must be constant expressions •
...

Seems like dart compiler takes <> as two separate part. With some hard trying, I changed the code to

@superEnum
enum _Event {
  @Data(fields: [DataField('foo', <int>[].runtimeType)])
  Foo,
}

That was much better, with the following error message though:

  error • Arguments of a constant creation must be constant expressions •
  error • The values in a const list literal must be constants •

BTW, the following code do compile without using super_enum:

class Data {
  final List<DataField> fields;

  const Data({this.fields});
}

class DataField {
  final String name;
  final Type type;

  const DataField(this.name, this.type);
}

void main() {
  print(Data(fields: [DataField('scanResult', <String>[].runtimeType)]));
}

VS Studio can not find the build task

VS Studio for some reason is not detecting the build task runner. Could be something wrong with the library or my version of VS Studio(I updated to the latest version)?

Add more whenX clauses

For example if you have enums like [Success, Error] and you only want to do something if it is an [Error], you have to use when and leave the success empty which can get ugly when there are many enums.
I think it would be good to generate functions like whenSuccess, whenError to deal with that, instead of having to import generated files.

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.