immutable_proto 0.0.5+1

  • Readme
  • Changelog
  • Installing
  • new70

This library generates immutable data classes for Protocol Buffers. Here's how to get started:

  1. Add these packages to your dependencies:
dependencies:
  immutable_proto: ^0.0.5+1

dev_dependencies:
  build_runner: ^1.0.0
  immutable_proto_generator: ^0.0.5+1
  1. Write your Protocol Buffers definition.
message User {
  string first_name = 1;

  string last_name = 2;

  repeated string email_addresses = 3;

  enum FavoriteDrink {
    UNKNOWN = 0;
    COFFEE = 1;
    COKE = 2;
    TEA = 3;
  }
  FavoriteDrink favorite_drink = 4;
}
  1. Generate the default (mutable) dart code for your Protobuf message (see the official documentation for more information).

  2. Import the generated class with prefix proto to avoid name conflicts.

import 'proto_generated/user.pb.dart' as proto;
  1. Write a blueprint class. Let the name be Mutable<Protobuf name> and annotate it with @ImmutableProto(<Protobuf class>) (Protobuf class is a reference to the generated (mutable) class):
import 'package:immutable_proto/immutable_proto.dart';

part 'main.g.dart';

@ImmutableProto(proto.User)
class MutableUser {
  String firstName;

  @required // This field must not be null
  String lastName;

  // Lists must not be null by default
  KtList<String> emailAddresses;

  // Will be replaced by the generated enum
  proto.User_FavoriteDrink favoriteDrink;
}
  1. Run pub run build_runner build in the command line (or flutter pub run build_runner build, if you're using Flutter). The implementation based on your blueprint class will automatically get generated.

The immutable class contains

  • a constructor with named parameters and assertions for required values
  • method/constructor for converting the immutable class to the mutable class (generated by Protocol Buffers) and the other way around
  • custom implementations of ==, hashCode and toString()
  • a copy method
  • enum mappers

For example, here's the generated code of our class above:

@immutable
class User {
  final String firstName;
  final String lastName;
  @required
  final KtList<String> emailAddresses;
  final UserFavoriteDrink favoriteDrink;

  User({
    this.firstName,
    this.lastName,
    @required this.emailAddresses,
    this.favoriteDrink,
  }) : assert(emailAddresses != null);

  User.fromProto(proto.User user)
      : this(
          firstName: user.firstName,
          lastName: user.lastName,
          emailAddresses: KtList.from(user.emailAddresses),
          favoriteDrink: userFavoriteDrinkFromProto(user.favoriteDrink),
        );
  proto.User toProto() {
    final user = proto.User();
    if (firstName != null) user.firstName = firstName;
    if (lastName != null) user.lastName = lastName;
    user.emailAddresses.addAll(emailAddresses.iter);
    if (favoriteDrink != null)
      user.favoriteDrink = userFavoriteDrinkToProto(favoriteDrink);
    return user;
  }

  bool operator ==(Object other) {
    return other is User &&
        firstName == other.firstName &&
        lastName == other.lastName &&
        emailAddresses == other.emailAddresses &&
        favoriteDrink == other.favoriteDrink;
  }

  int get hashCode => hashList([
        firstName,
        lastName,
        emailAddresses,
        favoriteDrink,
      ]);
  User copy({
    String firstName,
    String lastName,
    KtList<String> emailAddresses,
    UserFavoriteDrink favoriteDrink,
  }) =>
      User(
        firstName: firstName ?? this.firstName,
        lastName: lastName ?? this.lastName,
        emailAddresses: emailAddresses ?? this.emailAddresses,
        favoriteDrink: favoriteDrink ?? this.favoriteDrink,
      );

  String toString() {
    return 'User(firstName: $firstName, lastName: $lastName, emailAddresses: $emailAddresses, favoriteDrink: $favoriteDrink)';
  }

  static UserFavoriteDrink userFavoriteDrinkFromProto(
      proto.User_FavoriteDrink userFavoriteDrink) {
    switch (userFavoriteDrink) {
      case proto.User_FavoriteDrink.COFFEE:
        return UserFavoriteDrink.coffee;
      case proto.User_FavoriteDrink.COKE:
        return UserFavoriteDrink.coke;
      case proto.User_FavoriteDrink.TEA:
        return UserFavoriteDrink.tea;
      case proto.User_FavoriteDrink.UNKNOWN:
      default:
        return UserFavoriteDrink.unknown;
    }
  }

  static proto.User_FavoriteDrink userFavoriteDrinkToProto(
      UserFavoriteDrink userFavoriteDrink) {
    switch (userFavoriteDrink) {
      case UserFavoriteDrink.coffee:
        return proto.User_FavoriteDrink.COFFEE;
      case UserFavoriteDrink.coke:
        return proto.User_FavoriteDrink.COKE;
      case UserFavoriteDrink.tea:
        return proto.User_FavoriteDrink.TEA;
      case UserFavoriteDrink.unknown:
      default:
        return proto.User_FavoriteDrink.UNKNOWN;
    }
  }
}

enum UserFavoriteDrink {
  unknown,
  coffee,
  coke,
  tea,
}

Features #

  • [x] Generate basic immutable classes for a message
  • [x] Generate classes for nested messages automatically
  • [x] Generate enum + mappers for nested enums automatically
  • [ ] oneof-support
  • [ ] Commented code
  • [ ] Custom methods

License #

Copyright 2019 Jonas Wanke

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Changelog #

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog and this project adheres to Semantic Versioning.

Unreleased #

0.0.5+1 - 2019-10-06 #

Fixed #

  • generator: reduce false positives when detecting nested messages/enums

0.0.5 - 2019-10-06

Changed #

  • generator: make enum values required

Fixed #

  • generator: reduce false positives when detecting nested enums

0.0.4 - 2019-10-04

Changed #

  • generator: prefer null to empty values in fromProto

Fixed #

  • generator: reduce false positives when detecting nested messages
  • generator: generate correct mappers for fields of type message

0.0.3 - 2019-10-03

Fixed #

  • update dependencies

0.0.2 - 2019-10-02

Added #

  • generator: support references to non-nested messages

0.0.1 - 2019-10-02 #

Initial release.

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  immutable_proto: ^0.0.5+1

2. Install it

You can install packages from the command line:

with pub:


$ pub get

with Flutter:


$ flutter pub get

Alternatively, your editor might support pub get or flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:immutable_proto/immutable_proto.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
48
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
77
Overall:
Weighted score of the above. [more]
70
Learn more about scoring.

We analyzed this package on Oct 7, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.5.1
  • pana: 0.12.21

Platforms

Detected platforms: Flutter, web, other

No platform restriction found in primary library package:immutable_proto/immutable_proto.dart.

Maintenance suggestions

Maintain an example. (-10 points)

Create a short demo in the example/ directory to show how to use this package.

Common filename patterns include main.dart, example.dart, and immutable_proto.dart. Packages with multiple examples should provide example/README.md.

For more information see the pub package layout conventions.

Package is pre-v0.1 release. (-10 points)

While nothing is inherently wrong with versions of 0.0.*, it might mean that the author is still experimenting with the general direction of the API.

The package description is too short. (-3 points)

Add more detail to the description field of pubspec.yaml. Use 60 to 180 characters to describe the package, what it does, and its target use case.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.2.2 <3.0.0
meta ^1.1.7 1.1.7
Dev dependencies
pedantic ^1.0.0