buildContext function
Create a BuildContext.
Implementation
Future<BuildContext?> buildContext(
InterfaceElement clazz,
ConstantReader annotation,
BuildStep buildStep,
Resolver resolver,
bool autoSnakeCaseNames,
{bool heedExclude = true}) async {
var id = clazz.location?.components.join('-');
if (_cache.containsKey(id)) {
return _cache[id];
}
// Check for autoIdAndDateFields, autoSnakeCaseNames
autoSnakeCaseNames =
annotation.peek('autoSnakeCaseNames')?.boolValue ?? autoSnakeCaseNames;
var ctx = BuildContext(
annotation,
clazz,
originalClassName: clazz.name,
sourceFilename: p.basename(buildStep.inputId.path),
autoSnakeCaseNames: autoSnakeCaseNames,
includeAnnotations:
annotation.peek('includeAnnotations')?.listValue ?? <DartObject>[],
);
// var lib = await resolver.libraryFor(buildStep.inputId);
var fields = <FieldElement>[];
var fieldNames = <String>[];
for (var field in fields) {
fieldNames.add(field.name);
}
// Crawl for classes from parent classes.
void crawlClass(InterfaceType? t) {
while (t != null) {
// Check and skip fields with same name
var parentClassFields = <FieldElement>[];
for (var el in t.element.fields) {
if (fieldNames.contains(el.name)) {
continue;
}
parentClassFields.add(el);
fieldNames.add(el.name);
}
fields.insertAll(0, parentClassFields);
t.interfaces.forEach(crawlClass);
t = t.superclass;
}
// Move id field to the front if exist
var item = fields.firstWhereOrNull((el) => el.name == 'id');
if (item != null) {
fields.removeWhere((el) => el.name == 'id');
fields.insert(0, item);
}
}
crawlClass(clazz.thisType);
for (var field in fields) {
// Skip private fields
if (field.name.startsWith('_')) {
continue;
}
if (field.getter != null &&
(field.setter != null || field.getter!.isAbstract)) {
var el = field.setter == null ? field.getter! : field;
//fieldNames.add(field.name);
// Check for @SerializableField
var fieldAnn = serializableFieldTypeChecker.firstAnnotationOf(el);
void handleSerializableField(SerializableFieldMirror sField) {
ctx.fieldInfo[field.name] = sField;
if (sField.defaultValue != null) {
ctx.defaults[field.name] = sField.defaultValue!;
}
if (sField.alias != null) {
ctx.aliases[field.name] = sField.alias!;
} else if (autoSnakeCaseNames != false) {
ctx.aliases[field.name] = ReCase(field.name).snakeCase;
}
if (sField.isNullable == false) {
var reason = sField.errorMessage ??
"Missing required field '${ctx.resolveFieldName(field.name)}' on ${ctx.modelClassName}.";
ctx.requiredFields[field.name] = reason;
}
if (sField.exclude) {
// ignore: deprecated_member_use
ctx.excluded[field.name] = Exclude(
canSerialize: sField.canSerialize,
canDeserialize: sField.canDeserialize,
);
}
}
if (fieldAnn != null) {
var cr = ConstantReader(fieldAnn);
var excluded = cr.peek('exclude')?.boolValue ?? false;
var sField = SerializableFieldMirror(
alias: cr.peek('alias')?.stringValue,
defaultValue: cr.peek('defaultValue')?.objectValue,
serializer: cr.peek('serializer')?.symbolValue,
deserializer: cr.peek('deserializer')?.symbolValue,
errorMessage: cr.peek('errorMessage')?.stringValue,
isNullable: cr.peek('isNullable')?.boolValue ?? !excluded,
canDeserialize: cr.peek('canDeserialize')?.boolValue ?? false,
canSerialize: cr.peek('canSerialize')?.boolValue ?? false,
exclude: excluded,
serializesTo: cr.peek('serializesTo')?.typeValue,
);
handleSerializableField(sField);
// Apply
} else {
var foundNone = true;
// Skip if annotated with @exclude
var excludeAnnotation = excludeTypeChecker.firstAnnotationOf(el);
if (excludeAnnotation != null) {
var cr = ConstantReader(excludeAnnotation);
foundNone = false;
// ignore: deprecated_member_use
ctx.excluded[field.name] = Exclude(
canSerialize: cr.read('canSerialize').boolValue,
canDeserialize: cr.read('canDeserialize').boolValue,
);
}
// Check for @DefaultValue()
/*
var defAnn =
// ignore: deprecated_member_use
const TypeChecker.fromRuntime(DefaultValue).firstAnnotationOf(el);
if (defAnn != null) {
var rev = ConstantReader(defAnn).revive().positionalArguments[0];
ctx.defaults[field.name] = rev;
foundNone = false;
}
*/
// Check for alias
// ignore: deprecated_member_use
/*
Alias? alias;
var aliasAnn = aliasTypeChecker.firstAnnotationOf(el);
if (aliasAnn != null) {
// ignore: deprecated_member_use
alias = Alias(aliasAnn.getField('name')!.toStringValue()!);
foundNone = false;
}
if (alias?.name.isNotEmpty == true) {
ctx.aliases[field.name] = alias!.name;
} else if (autoSnakeCaseNames != false) {
ctx.aliases[field.name] = ReCase(field.name).snakeCase;
}
*/
// Check for @required
var required =
const TypeChecker.fromRuntime(Required).firstAnnotationOf(el);
if (required != null) {
log.warning(
'Using @required on fields (like ${clazz.name}.${field.name}) is now deprecated; use @SerializableField(isNullable: false) instead.');
var cr = ConstantReader(required);
var reason = cr.peek('reason')?.stringValue ??
"Missing required field '${ctx.resolveFieldName(field.name)}' on ${ctx.modelClassName}.";
ctx.requiredFields[field.name] = reason;
foundNone = false;
}
if (foundNone) {
var f = SerializableField();
var sField = SerializableFieldMirror(
alias: f.alias,
defaultValue: null,
serializer: f.serializer,
deserializer: f.deserializer,
errorMessage: f.errorMessage,
isNullable: f.isNullable,
canDeserialize: f.canDeserialize,
canSerialize: f.canSerialize,
exclude: f.exclude,
serializesTo: null,
);
handleSerializableField(sField);
}
}
ctx.fields.add(field);
}
}
// Get constructor params, if any
ctx.constructorParameters.addAll(clazz.unnamedConstructor!.parameters);
return ctx;
}