platform/angel_serialize_generator/lib/build_context.dart

100 lines
3.1 KiB
Dart
Raw Normal View History

2017-09-15 00:36:28 +00:00
import 'dart:async';
2017-06-20 22:13:04 +00:00
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:angel_serialize/angel_serialize.dart';
import 'package:build/build.dart';
import 'package:path/path.dart' as p;
import 'package:recase/recase.dart';
2017-09-15 00:20:36 +00:00
import 'package:source_gen/source_gen.dart';
2017-06-20 22:13:04 +00:00
import 'context.dart';
2017-09-15 00:20:36 +00:00
const TypeChecker aliasTypeChecker = const TypeChecker.fromRuntime(Alias);
const TypeChecker excludeTypeChecker = const TypeChecker.fromRuntime(Exclude);
const TypeChecker serializableTypeChecker =
2017-09-15 00:36:28 +00:00
const TypeChecker.fromRuntime(Serializable);
2017-09-15 00:20:36 +00:00
2018-02-27 19:22:30 +00:00
/// Create a [BuildContext].
2017-09-15 00:36:28 +00:00
Future<BuildContext> buildContext(
2017-06-20 22:13:04 +00:00
ClassElement clazz,
ConstantReader annotation,
2017-06-20 22:13:04 +00:00
BuildStep buildStep,
Resolver resolver,
bool autoSnakeCaseNames,
bool autoIdAndDateFields,
2017-09-15 00:36:28 +00:00
{bool heedExclude: true}) async {
2017-06-20 22:13:04 +00:00
var ctx = new BuildContext(annotation,
originalClassName: clazz.name,
sourceFilename: p.basename(buildStep.inputId.path));
2017-09-15 00:36:28 +00:00
var lib = await resolver.libraryFor(buildStep.inputId);
2017-06-20 22:13:04 +00:00
List<String> fieldNames = [];
for (var field in clazz.fields) {
if (field.getter != null && field.setter != null) {
fieldNames.add(field.name);
// Skip if annotated with @exclude
2017-09-15 00:20:36 +00:00
var excludeAnnotation = excludeTypeChecker.firstAnnotationOf(field);
2018-02-28 00:36:53 +00:00
ctx.excluded[field.name] = excludeAnnotation != null;
2017-06-20 22:13:04 +00:00
// Check for alias
2017-09-15 00:20:36 +00:00
Alias alias;
var aliasAnn = aliasTypeChecker.firstAnnotationOf(field);
if (aliasAnn != null) {
alias = new Alias(aliasAnn.getField('name').toStringValue());
}
2017-06-20 22:13:04 +00:00
if (alias?.name?.isNotEmpty == true) {
ctx.aliases[field.name] = alias.name;
} else if (autoSnakeCaseNames != false) {
ctx.aliases[field.name] = new ReCase(field.name).snakeCase;
}
ctx.fields.add(field);
}
}
// Check for autoIdAndDateFields, autoSnakeCaseNames
autoIdAndDateFields = annotation.peek('autoIdAndDateFields')?.boolValue ?? autoIdAndDateFields;
autoSnakeCaseNames = annotation.peek('autoSnakeCaseNames')?.boolValue ?? autoSnakeCaseNames;
2017-06-20 22:13:04 +00:00
if (autoIdAndDateFields != false) {
if (!fieldNames.contains('id')) {
2018-02-27 19:42:06 +00:00
var idField =
new ShimFieldImpl('id', lib.context.typeProvider.stringType);
2017-06-20 22:13:04 +00:00
ctx.fields.insert(0, idField);
ctx.shimmed['id'] = true;
}
DartType dateTime;
2017-09-15 00:36:28 +00:00
for (var key in ['createdAt', 'updatedAt']) {
2017-06-20 22:13:04 +00:00
if (!fieldNames.contains(key)) {
if (dateTime == null) {
2017-09-15 00:36:28 +00:00
var coreLib =
await resolver.libraries.singleWhere((lib) => lib.isDartCore);
2017-06-20 22:13:04 +00:00
var dt = coreLib.getType('DateTime');
dateTime = dt.type;
}
2018-02-27 19:22:30 +00:00
var field = new ShimFieldImpl(key, dateTime);
2017-06-20 22:13:04 +00:00
ctx.aliases[key] = new ReCase(key).snakeCase;
ctx.fields.add(field);
ctx.shimmed[key] = true;
}
2017-09-15 00:36:28 +00:00
}
2017-06-20 22:13:04 +00:00
}
return ctx;
}
2018-02-27 19:22:30 +00:00
/// A manually-instantiated [FieldElement].
class ShimFieldImpl extends FieldElementImpl {
2017-06-20 22:13:04 +00:00
@override
final DartType type;
2018-02-27 19:42:06 +00:00
2018-02-27 19:22:30 +00:00
ShimFieldImpl(String name, this.type) : super(name, -1);
2017-06-20 22:13:04 +00:00
}