2.0.9 - add enums
This commit is contained in:
parent
403e2e600e
commit
bdb7b30bc4
14 changed files with 217 additions and 36 deletions
7
.idea/runConfigurations/tests_in_enum_test_dart.xml
Normal file
7
.idea/runConfigurations/tests_in_enum_test_dart.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="tests in enum_test.dart" type="DartTestRunConfigurationType" factoryName="Dart Test" singleton="true" nameIsGenerated="true">
|
||||
<option name="filePath" value="$PROJECT_DIR$/angel_serialize_generator/test/enum_test.dart" />
|
||||
<option name="testRunnerOptions" value="-j4" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
11
README.md
11
README.md
|
@ -61,9 +61,20 @@ part 'book.g.dart';
|
|||
@serializable
|
||||
abstract class _Book extends Model {
|
||||
String get author;
|
||||
|
||||
String get title;
|
||||
|
||||
String get description;
|
||||
|
||||
int get pageCount;
|
||||
|
||||
BookType get type;
|
||||
}
|
||||
|
||||
/// It even supports enums!
|
||||
enum BookType {
|
||||
fiction,
|
||||
nonFiction
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
# 2.0.9
|
||||
* Now supports de/serialization of `enum` types.
|
||||
* Generate `const` constructors when possible.
|
||||
* Remove `whereType`, perform manual coercion.
|
||||
|
||||
# 2.0.8
|
||||
* Generate a `fromMap` with typecasting, for Dart 2's sake.
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ targets:
|
|||
_book:
|
||||
sources:
|
||||
- "test/models/book.dart"
|
||||
- "test/models/with_enum.dart"
|
||||
_typescript_definition:
|
||||
sources:
|
||||
- "lib/*.dart"
|
||||
|
|
|
@ -3,6 +3,7 @@ library angel_serialize_generator;
|
|||
import 'dart:async';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:angel_model/angel_model.dart';
|
||||
import 'package:angel_serialize/angel_serialize.dart';
|
||||
import 'package:build/build.dart';
|
||||
import 'package:code_buffer/code_buffer.dart';
|
||||
|
@ -66,6 +67,14 @@ bool isListOrMapType(DartType t) {
|
|||
const TypeChecker.fromRuntime(Map).isAssignableFromType(t);
|
||||
}
|
||||
|
||||
bool isEnumType(DartType t) {
|
||||
if (t is InterfaceType) {
|
||||
return t.element.isEnum;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Determines if a [DartType] is a `List` with the first type argument being a `Model`.
|
||||
bool isListModelType(InterfaceType t) {
|
||||
return const TypeChecker.fromRuntime(List).isAssignableFromType(t) &&
|
||||
|
@ -80,6 +89,8 @@ bool isMapToModelType(InterfaceType t) {
|
|||
isModelClass(t.typeArguments[1]);
|
||||
}
|
||||
|
||||
bool isAssignableToModel(DartType type) => const TypeChecker.fromRuntime(Model).isAssignableFromType(type);
|
||||
|
||||
/// Compute a [String] representation of a [type].
|
||||
String typeToString(DartType type) {
|
||||
if (type is InterfaceType) {
|
||||
|
|
|
@ -26,9 +26,13 @@ class JsonModelGenerator extends GeneratorForAnnotation<Serializable> {
|
|||
void generateClass(
|
||||
BuildContext ctx, LibraryBuilder file, ConstantReader annotation) {
|
||||
file.body.add(new Class((clazz) {
|
||||
clazz
|
||||
..name = ctx.modelClassNameRecase.pascalCase
|
||||
..extend = new Reference(ctx.originalClassName);
|
||||
clazz..name = ctx.modelClassNameRecase.pascalCase;
|
||||
|
||||
if (shouldBeConstant(ctx)) {
|
||||
clazz.implements.add(new Reference(ctx.originalClassName));
|
||||
} else {
|
||||
clazz.extend = new Reference(ctx.originalClassName);
|
||||
}
|
||||
|
||||
//if (ctx.importsPackageMeta)
|
||||
// clazz.annotations.add(new CodeExpression(new Code('immutable')));
|
||||
|
@ -61,11 +65,19 @@ class JsonModelGenerator extends GeneratorForAnnotation<Serializable> {
|
|||
}));
|
||||
}
|
||||
|
||||
bool shouldBeConstant(BuildContext ctx) {
|
||||
// Check if all fields are without a getter
|
||||
return !isAssignableToModel(ctx.clazz.type) &&
|
||||
ctx.clazz.fields.every((f) => f.getter == null || f.setter == null);
|
||||
}
|
||||
|
||||
/// Generate a constructor with named parameters.
|
||||
void generateConstructor(
|
||||
BuildContext ctx, ClassBuilder clazz, LibraryBuilder file) {
|
||||
clazz.constructors.add(new Constructor((constructor) {
|
||||
// Add all `super` params
|
||||
constructor.constant = ctx.clazz.unnamedConstructor?.isConst == true ||
|
||||
shouldBeConstant(ctx);
|
||||
|
||||
for (var param in ctx.constructorParameters) {
|
||||
constructor.requiredParameters.add(new Parameter((b) => b
|
||||
|
@ -156,7 +168,7 @@ class JsonModelGenerator extends GeneratorForAnnotation<Serializable> {
|
|||
}
|
||||
|
||||
static String generateEquality(DartType type, [bool nullable = false]) {
|
||||
//if (type is! InterfaceType) return 'const DefaultEquality()';
|
||||
//if (type is! InterfaceType) return 'const DefaultEquality()';
|
||||
var it = type as InterfaceType;
|
||||
if (const TypeChecker.fromRuntime(List).isAssignableFromType(type)) {
|
||||
if (it.typeParameters.length == 1) {
|
||||
|
|
|
@ -112,6 +112,12 @@ class SerializerGenerator extends GeneratorForAnnotation<Serializable> {
|
|||
return map..[key] = ${rc.pascalCase}Serializer.toMap(model.${field
|
||||
.name}[key]);
|
||||
})''';
|
||||
} else if (t.element.isEnum) {
|
||||
serializedRepresentation = '''
|
||||
model.${field.name} == null ?
|
||||
null
|
||||
: ${t.name}.values.indexOf(model.${field.name})
|
||||
''';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -193,19 +199,31 @@ class SerializerGenerator extends GeneratorForAnnotation<Serializable> {
|
|||
if (isListModelType(t)) {
|
||||
var rc = new ReCase(t.typeArguments[0].name);
|
||||
deserializedRepresentation = "map['$alias'] is Iterable"
|
||||
" ? new List.unmodifiable((map['$alias'] as Iterable).whereType<Map>().map(${rc
|
||||
.pascalCase}Serializer.fromMap))"
|
||||
" ? new List.unmodifiable(((map['$alias'] as Iterable)"
|
||||
".where((x) => x is Map) as Iterable<Map>)"
|
||||
".map(${rc.pascalCase}Serializer.fromMap))"
|
||||
" : null";
|
||||
} else if (isMapToModelType(t)) {
|
||||
var rc = new ReCase(t.typeArguments[1].name);
|
||||
deserializedRepresentation = '''
|
||||
map['$alias'] is Map
|
||||
? new Map.unmodifiable((map['$alias'] as Map).keys.fold({}, (out, key) {
|
||||
return out..[key] = ${rc
|
||||
.pascalCase}Serializer.fromMap((map['$alias'] as Map)[key]);
|
||||
return out..[key] = ${rc.pascalCase}Serializer
|
||||
.fromMap((map['$alias'] as Map)[key]);
|
||||
}))
|
||||
: null
|
||||
''';
|
||||
} else if (t.element.isEnum) {
|
||||
deserializedRepresentation = '''
|
||||
map['$alias'] is ${t.name}
|
||||
? map['$alias']
|
||||
:
|
||||
(
|
||||
map['$alias'] is int
|
||||
? ${t.name}.values[map['$alias']]
|
||||
: null
|
||||
)
|
||||
''';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,5 +16,5 @@ dependencies:
|
|||
recase: ^1.0.0
|
||||
source_gen: ^0.7.0
|
||||
dev_dependencies:
|
||||
build_runner: ^0.9.0
|
||||
build_runner: ^0.8.0
|
||||
test: ^1.0.0
|
48
angel_serialize_generator/test/enum_test.dart
Normal file
48
angel_serialize_generator/test/enum_test.dart
Normal file
|
@ -0,0 +1,48 @@
|
|||
import 'package:test/test.dart';
|
||||
import 'models/with_enum.dart';
|
||||
|
||||
const WithEnum aWithEnum = const WithEnum(type: WithEnumType.a);
|
||||
const WithEnum aWithEnum2 = const WithEnum(type: WithEnumType.a);
|
||||
|
||||
void main() {
|
||||
test('enum serializes to int', () {
|
||||
var w = new WithEnum(type: WithEnumType.b).toJson();
|
||||
expect(w[WithEnumFields.type], WithEnumType.values.indexOf(WithEnumType.b));
|
||||
});
|
||||
|
||||
test('enum serializes null if null', () {
|
||||
var w = new WithEnum(type: null).toJson();
|
||||
expect(w[WithEnumFields.type], null);
|
||||
});
|
||||
|
||||
test('enum deserializes to null from null', () {
|
||||
var map = {WithEnumFields.type: null};
|
||||
var w = WithEnumSerializer.fromMap(map);
|
||||
expect(w.type, isNull);
|
||||
});
|
||||
|
||||
test('enum deserializes from int', () {
|
||||
var map = {
|
||||
WithEnumFields.type: WithEnumType.values.indexOf(WithEnumType.b)
|
||||
};
|
||||
var w = WithEnumSerializer.fromMap(map);
|
||||
expect(w.type, WithEnumType.b);
|
||||
});
|
||||
|
||||
test('enum deserializes from value', () {
|
||||
var map = {WithEnumFields.type: WithEnumType.c};
|
||||
var w = WithEnumSerializer.fromMap(map);
|
||||
expect(w.type, WithEnumType.c);
|
||||
});
|
||||
|
||||
test('equality', () {
|
||||
expect(
|
||||
new WithEnum(type: WithEnumType.a), new WithEnum(type: WithEnumType.a));
|
||||
expect(new WithEnum(type: WithEnumType.a),
|
||||
isNot(new WithEnum(type: WithEnumType.b)));
|
||||
});
|
||||
|
||||
test('const', () {
|
||||
expect(identical(aWithEnum, aWithEnum2), true);
|
||||
});
|
||||
}
|
|
@ -17,24 +17,26 @@ abstract class AuthorSerializer {
|
|||
}
|
||||
|
||||
return new Author(
|
||||
id: map['id'],
|
||||
name: map['name'],
|
||||
age: map['age'],
|
||||
id: map['id'] as String,
|
||||
name: map['name'] as String,
|
||||
age: map['age'] as int,
|
||||
books: map['books'] is Iterable
|
||||
? new List.unmodifiable(map['books'].map(BookSerializer.fromMap))
|
||||
? new List.unmodifiable(((map['books'] as Iterable)
|
||||
.where((x) => x is Map) as Iterable<Map>)
|
||||
.map(BookSerializer.fromMap))
|
||||
: null,
|
||||
newestBook: map['newest_book'] != null
|
||||
? BookSerializer.fromMap(map['newest_book'])
|
||||
: null,
|
||||
obscured: map['obscured'],
|
||||
obscured: map['obscured'] as String,
|
||||
createdAt: map['created_at'] != null
|
||||
? (map['created_at'] is DateTime
|
||||
? map['created_at']
|
||||
? (map['created_at'] as DateTime)
|
||||
: DateTime.parse(map['created_at']))
|
||||
: null,
|
||||
updatedAt: map['updated_at'] != null
|
||||
? (map['updated_at'] is DateTime
|
||||
? map['updated_at']
|
||||
? (map['updated_at'] as DateTime)
|
||||
: DateTime.parse(map['updated_at']))
|
||||
: null);
|
||||
}
|
||||
|
@ -83,21 +85,23 @@ abstract class AuthorFields {
|
|||
abstract class LibrarySerializer {
|
||||
static Library fromMap(Map map) {
|
||||
return new Library(
|
||||
id: map['id'],
|
||||
id: map['id'] as String,
|
||||
collection: map['collection'] is Map
|
||||
? new Map.unmodifiable(map['collection'].keys.fold({}, (out, key) {
|
||||
? new Map.unmodifiable(
|
||||
(map['collection'] as Map).keys.fold({}, (out, key) {
|
||||
return out
|
||||
..[key] = BookSerializer.fromMap(map['collection'][key]);
|
||||
..[key] =
|
||||
BookSerializer.fromMap((map['collection'] as Map)[key]);
|
||||
}))
|
||||
: null,
|
||||
createdAt: map['created_at'] != null
|
||||
? (map['created_at'] is DateTime
|
||||
? map['created_at']
|
||||
? (map['created_at'] as DateTime)
|
||||
: DateTime.parse(map['created_at']))
|
||||
: null,
|
||||
updatedAt: map['updated_at'] != null
|
||||
? (map['updated_at'] is DateTime
|
||||
? map['updated_at']
|
||||
? (map['updated_at'] as DateTime)
|
||||
: DateTime.parse(map['updated_at']))
|
||||
: null);
|
||||
}
|
||||
|
@ -131,18 +135,18 @@ abstract class BookmarkSerializer {
|
|||
}
|
||||
|
||||
return new Bookmark(book,
|
||||
id: map['id'],
|
||||
history: map['history'],
|
||||
page: map['page'],
|
||||
comment: map['comment'],
|
||||
id: map['id'] as String,
|
||||
history: map['history'] as List<int>,
|
||||
page: map['page'] as int,
|
||||
comment: map['comment'] as String,
|
||||
createdAt: map['created_at'] != null
|
||||
? (map['created_at'] is DateTime
|
||||
? map['created_at']
|
||||
? (map['created_at'] as DateTime)
|
||||
: DateTime.parse(map['created_at']))
|
||||
: null,
|
||||
updatedAt: map['updated_at'] != null
|
||||
? (map['updated_at'] is DateTime
|
||||
? map['updated_at']
|
||||
? (map['updated_at'] as DateTime)
|
||||
: DateTime.parse(map['updated_at']))
|
||||
: null);
|
||||
}
|
||||
|
|
|
@ -9,21 +9,21 @@ part of angel_serialize.test.models.book;
|
|||
abstract class BookSerializer {
|
||||
static Book fromMap(Map map) {
|
||||
return new Book(
|
||||
id: map['id'],
|
||||
author: map['author'],
|
||||
title: map['title'],
|
||||
description: map['description'],
|
||||
pageCount: map['page_count'],
|
||||
notModels: map['not_models'],
|
||||
camelCaseString: map['camelCase'],
|
||||
id: map['id'] as String,
|
||||
author: map['author'] as String,
|
||||
title: map['title'] as String,
|
||||
description: map['description'] as String,
|
||||
pageCount: map['page_count'] as int,
|
||||
notModels: map['not_models'] as List<double>,
|
||||
camelCaseString: map['camelCase'] as String,
|
||||
createdAt: map['created_at'] != null
|
||||
? (map['created_at'] is DateTime
|
||||
? map['created_at']
|
||||
? (map['created_at'] as DateTime)
|
||||
: DateTime.parse(map['created_at']))
|
||||
: null,
|
||||
updatedAt: map['updated_at'] != null
|
||||
? (map['updated_at'] is DateTime
|
||||
? map['updated_at']
|
||||
? (map['updated_at'] as DateTime)
|
||||
: DateTime.parse(map['updated_at']))
|
||||
: null);
|
||||
}
|
||||
|
|
11
angel_serialize_generator/test/models/with_enum.dart
Normal file
11
angel_serialize_generator/test/models/with_enum.dart
Normal file
|
@ -0,0 +1,11 @@
|
|||
import 'package:angel_model/angel_model.dart';
|
||||
import 'package:angel_serialize/angel_serialize.dart';
|
||||
part 'with_enum.g.dart';
|
||||
part 'with_enum.serializer.g.dart';
|
||||
|
||||
@Serializable(autoIdAndDateFields: false)
|
||||
abstract class _WithEnum {
|
||||
WithEnumType get type;
|
||||
}
|
||||
|
||||
enum WithEnumType { a, b, c }
|
26
angel_serialize_generator/test/models/with_enum.g.dart
Normal file
26
angel_serialize_generator/test/models/with_enum.g.dart
Normal file
|
@ -0,0 +1,26 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'with_enum.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// Generator: JsonModelGenerator
|
||||
// **************************************************************************
|
||||
|
||||
class WithEnum implements _WithEnum {
|
||||
const WithEnum({this.type});
|
||||
|
||||
@override
|
||||
final WithEnumType type;
|
||||
|
||||
WithEnum copyWith({WithEnumType type}) {
|
||||
return new WithEnum(type: type ?? this.type);
|
||||
}
|
||||
|
||||
bool operator ==(other) {
|
||||
return other is _WithEnum && other.type == type;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return WithEnumSerializer.toMap(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'with_enum.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// Generator: SerializerGenerator
|
||||
// **************************************************************************
|
||||
|
||||
abstract class WithEnumSerializer {
|
||||
static WithEnum fromMap(Map map) {
|
||||
return new WithEnum(
|
||||
type: map['type'] is WithEnumType
|
||||
? map['type']
|
||||
: (map['type'] is int ? WithEnumType.values[map['type']] : null));
|
||||
}
|
||||
|
||||
static Map<String, dynamic> toMap(WithEnum model) {
|
||||
return {
|
||||
'type':
|
||||
model.type == null ? null : WithEnumType.values.indexOf(model.type)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
abstract class WithEnumFields {
|
||||
static const String type = 'type';
|
||||
}
|
Loading…
Reference in a new issue