inferType function
Expression
inferType(})
Implementation
Expression inferType(
List<CustomTypes> customTypes,
Element typeElement,
String name,
DartType type, {
bool? nullable,
String? genericTypeName,
Map<String, TypeParameterElement>? generics,
bool isInput = false,
}) {
final docs = getDocumentation(typeElement);
if (docs?.typeName != null) {
return refer(docs!.typeName!);
}
// If its a Future<T>, Stream<T> or FutureOr<T>, unpack T and infer it
final genericWhenAsync = genericTypeWhenFutureOrStream(type);
if (genericWhenAsync != null) {
return inferType(
customTypes,
typeElement,
name,
genericWhenAsync,
generics: generics,
isInput: isInput,
);
}
final nonNullable = type.nullabilitySuffix == NullabilitySuffix.none;
Expression _wrapNullability(Expression exp) =>
nonNullable && nullable != true ? exp.property('nonNull').call([]) : exp;
// Check customTypes from generator config
final typeName =
type.getDisplayString(withNullability: false).split('<').first;
final customType = customTypes.firstWhereOrNull((t) => t.name == typeName);
if (customType != null) {
return _wrapNullability(refer(customType.getter, customType.import));
}
Expression _wrapExpression(Expression exp) {
if (type is InterfaceType && type.typeArguments.isNotEmpty) {
// Generics
return _wrapNullability(
exp.call([
...type.typeArguments.map((e) {
return inferType(
customTypes,
typeElement,
name,
e,
generics: generics,
isInput: isInput,
);
}),
], {
if (genericTypeName != null) 'name': literalString(genericTypeName)
}, [
...type.typeArguments.map(getReturnType).map(refer)
]),
);
}
return _wrapNullability(exp);
}
// `DartType.graphQLType` static getter or method
final element = type.element;
if (element is ClassElement) {
final ExecutableElement? e =
element.getGetter('graphQLType') ?? element.getMethod('graphQLType');
if (e != null) {
if (!e.isStatic) {
throw Exception(
'The getter or method "$typeName.graphQLType" should be static.',
);
}
final prop = refer(typeName).property(e.name);
return _wrapExpression(prop);
}
}
// Next, check to see if it's a List.
if (type is InterfaceType &&
type.typeArguments.isNotEmpty &&
const TypeChecker.fromRuntime(Iterable).isAssignableFromType(type)) {
final arg = type.typeArguments[0];
final inner = inferType(
customTypes,
typeElement,
name,
arg,
generics: generics,
isInput: isInput,
);
return _wrapNullability(inner.property('list').call([]));
}
const primitive = {
String: 'graphQLString',
int: 'graphQLInt',
double: 'graphQLFloat',
bool: 'graphQLBoolean',
DateTime: 'graphQLDate',
Uri: 'graphQLUri',
BigInt: 'graphQLBigInt',
};
// Check to see if it's a primitive type.
for (final entry in primitive.entries) {
if (type.element != null &&
TypeChecker.fromRuntime(entry.key).isAssignableFrom(type.element!)) {
// Next, check if this is the "id" field of a `Model`.
// TODO: 1G make the id configurable, maybe with @key(fields: "") directive
// if (const TypeChecker.fromRuntime(Model).isAssignableFromType(type) &&
// name == 'id') {
// return refer('graphQLId');
// }
if (entry.key == String && name == 'id') {
return _wrapNullability(refer('graphQLId'));
}
return _wrapNullability(refer(entry.value));
}
}
final externalName =
typeName.startsWith('_') ? typeName.substring(1) : typeName;
// Firstly, check if it's a GraphQL class.
if (type is! InterfaceType ||
!const TypeChecker.fromRuntime(BaseGraphQLTypeDecorator)
.hasAnnotationOf(type.element)) {
// If it is not an annotated type, then check if it is a generic
if (type is TypeParameterType && generics != null) {
final generic = generics[typeName];
if (generic != null) {
final isNonNull = nullable != true &&
type.nullabilitySuffix == NullabilitySuffix.none &&
generic.bound?.nullabilitySuffix == NullabilitySuffix.none;
final nullability = isNonNull
? '.nonNull()'
: type.nullabilitySuffix != NullabilitySuffix.none
? '.nullable()'
: '';
return refer(
'${ReCase(externalName).camelCase}$graphqlTypeSuffix$nullability',
);
}
}
final _namePrefix = typeElement.enclosingElement is ClassElement
? '${typeElement.enclosingElement!.name!}.'
: '';
log.warning(
'Cannot infer the GraphQLType for field $_namePrefix$name (type=$type).'
' Please annotate the Dart type, provide a $typeName.graphQLType'
' static getter or add the type to `build.yaml` "customTypes" property.',
);
}
final _inputSuffix = isInput &&
type.element != null &&
const TypeChecker.fromRuntime(GraphQLInput)
.hasAnnotationOf(type.element!)
? 'Input'
: '';
return _wrapExpression(
refer('${ReCase(externalName).camelCase}$graphqlTypeSuffix$_inputSuffix'),
);
// Nothing else is allowed.
// throw 'Cannot infer the GraphQL type for '
// 'field $className.$name (type=$type).';
}