valueFromAst function

Object? valueFromAst(
  1. GraphQLType? type,
  2. ValueNode node,
  3. Map<String, Object?>? variables, {
  4. FileSpan? span,
  5. String key = 'value',
})

Returns a Dart value from a GraphQL Ast node, given the value's type

throws GraphQLError if there is an error in validation or parsing.

Implementation

Object? valueFromAst(
  GraphQLType? type,
  ast.ValueNode node,
  Map<String, Object?>? variables, {
  FileSpan? span,
  String key = 'value',
}) {
  final _span = node.span ?? span;
  final value = node.when(
    string: (string) => string.value,
    int_: (int_) => int.parse(int_.value),
    float: (float) => double.parse(float.value),
    boolean: (boolean) => boolean.value,
    object: (object) {
      GraphQLType<Object?, Object?>? _type = type;
      if (_type is GraphQLNonNullType) _type = _type.ofType;
      if (_type is GraphQLScalarType) _type = null;
      if (_type != null && _type is! GraphQLInputObjectType) {
        throw GraphQLError(
          'Expected value to be a $_type. Got: ${printAST(object)}.',
          locations: GraphQLErrorLocation.listFromSource(_span?.start),
        );
      }
      final _objType = _type as GraphQLInputObjectType?;
      return Map.fromEntries(
        object.fields.map(
          (e) {
            final fieldName = e.name.value;
            final _fieldSpan = e.span ?? e.value.span ?? e.name.span ?? _span;
            final _type =
                _objType?.fields.firstWhereOrNull((f) => f.name == fieldName);

            return MapEntry(
              fieldName,
              valueFromAst(
                _type?.type,
                e.value,
                variables,
                span: _fieldSpan,
                key: '$key["$fieldName"]',
              ),
            );
          },
        ),
      );
    },
    list: (list) {
      GraphQLType<Object?, Object?>? _type = type;
      if (_type is GraphQLNonNullType) _type = _type.ofType;
      if (_type is GraphQLScalarType) _type = null;
      if (_type != null && _type is! GraphQLListType) {
        throw GraphQLError(
          'Expected value to be a $_type. Got: ${printAST(list)}.',
          locations: GraphQLErrorLocation.listFromSource(_span?.start),
        );
      }
      return List.of(
        list.values.mapIndexed(
          (index, v) => valueFromAst(
            (_type as GraphQLListType?)?.ofType,
            v,
            variables,
            span: _span,
            key: '$key[$index]',
          ),
        ),
      );
    },
    enum_: (enum_) => EnumValue(enum_.name.value),
    null_: (null_) => null,
    variable: (variable) => variables?[variable.name.value],
  );

  if (type != null) {
    if (value == null) {
      if (type.isNonNullable) {
        throw GraphQLError(
          'Expected a non-null value of type $type int $key.',
          locations: GraphQLErrorLocation.listFromSource(_span?.start),
        );
      }
      return null;
    }
    // TODO: 3I validate shallow (not nested properties, since they where already validated)
    final result = type.validate(key, value);
    if (result.successful) {
      return result.value;
    } else {
      throw GraphQLError(
        result.errors.first,
        locations: GraphQLErrorLocation.listFromSource(_span?.start),
      );
    }
  }
  return value;
}