graphql-idl-parser 0.1.1

A parser for the GraphQL IDL format.
use type_definition::*;

grammar;

// TODO: missing others types
pub schema: Vec<TypeDefinition> =
    <TypeDefinition*> => <>;

TypeDefinition: TypeDefinition = {
    ScalarTypeDefinition,
    ObjectTypeDefinition,
    EnumTypeDefinition,
    InterfaceTypeDefinition,
    UnionTypeDefinition,
    InputObjectTypeDefinition,
};

ScalarTypeDefinition: TypeDefinition = {
    <d:Description?> "scalar" <n:Name> => {
        TypeDefinition::ScalarType(GraphQLScalar::new(d, n))
    }
};

ObjectTypeDefinition: TypeDefinition = {
    <d:Description?> "type" <n:Name> <i:(ImplementsInterfaces?)> <r:(Directives?)> "{" <f:(Fields?)> "}" => {
        TypeDefinition::ObjectType(GraphQLObject::new(d, n, i, r, f))
    },
};

EnumTypeDefinition: TypeDefinition = {
    <d:Description?> "enum" <n:Name> <r:(Directives?)> "{" <f:(<EnumValueDefinition>)+> "}" => {
        TypeDefinition::EnumType(GraphQLEnum::new(d, n, r, f))
    }
};

InterfaceTypeDefinition: TypeDefinition = {
    <d:Description?> "interface" <n:Name> <r:(Directives?)> "{" <f:(Fields?)> "}" => {
        TypeDefinition::InterfaceType(GraphQLInterface::new(d, n, r, f))
    },

};

UnionTypeDefinition: TypeDefinition = {
    <d:Description?> "union" <n:Name> <r:(Directives?)> <t:DefaultValue> => {
        // This is dumb, but there seemes to be some ambiguity conflict with "="
        let res: Vec<String> = t.split("|").map(|s| s.trim().to_string()).collect();
        TypeDefinition::UnionType(GraphQLUnion::new(d, n, r, res))
    }
};

InputObjectTypeDefinition: TypeDefinition = {
    <d:Description?> "input" <n:Name> <r:(Directives?)> "{" <f:(Fields?)> "}" => {
        TypeDefinition::InputObjectType(GraphQLInputObject::new(d, n, r, f))
    },
};

ImplementsInterfaces: Vec<String> = {
    "implements" <i:Comma<Name>> => {
        i
    }
};

Fields: Vec<GraphQLField> = {
    <f:FieldDefinition+> => {
      f
    }
};

FieldDefinition: GraphQLField = {
  <d:Description?> <n:FieldName> <a:(ArgumentsDefinition?)> ":" <t:FieldType> <r:(Directives?)> => {
      GraphQLField::new(d, n, t, a, r)
  }
};

EnumValueDefinition: GraphQLValue = {
    <d:Description?> <n:Name> <r:(Directives?)> => {
        GraphQLValue::new(d, n, r)
    }
};

FieldType: FieldType = {
    <n:Name> <r:"!"?> => {
        FieldType {
            name: n,
            info: match r {
              None => TypeInfo::Nullable,
              Some(r) => TypeInfo::NonNullable,
            }
        }
    },
    "[" <n:Name> <r:"!"?> "]" <l:"!"?> => {
        FieldType {
            name: n,
            info: match r {
              None => match l {
                  None => TypeInfo::NullableListNullableElements,
                  Some(l) => TypeInfo::NonNullableListNullableElements
              },
              Some(r) => match l {
                  None => TypeInfo::NonNullableListNullableElements,
                  Some(l) => TypeInfo::NonNullableListNonNullableElements
              }
            }
        }
    }
};

ArgumentsDefinition: Vec<GraphQLArgument> = {
    "(" <i:InputValueDefinition+> ")" => {
        i
    }
};

InputValueDefinition: GraphQLArgument = {
    <d:Description?> <n:FieldName> ":" <t:FieldType> <v:DefaultValue?> <r:(Directives?)> => {
        GraphQLArgument::new(d, n, t, v, r)
    }
};

Directives: Vec<GraphQLDirective> = {
    <d:Directive+> => {
        d
    }
};

Directive: GraphQLDirective = {
    "@" <n:Name> <d:(DirectiveArgumentsDefinition)?> => {
        GraphQLDirective::new(n, d)
    }
};

DirectiveArgumentsDefinition: Vec<GraphQLDirectiveArgument> = {
    "(" <d:DirectiveArgumentDefinition+> ")" => {
        d
    }
};

DirectiveArgumentDefinition: GraphQLDirectiveArgument = {
    <n:FieldName> <q:DirectiveArgumentTypeDefinition?> => {
        GraphQLDirectiveArgument::new(n, q)
    },
};

DirectiveArgumentTypeDefinition: String = {
    ":" <q:QuotedString> => {
        q
    }
};

Comma<T>: Vec<T> = {
    Comma1<T>? => <>.unwrap_or(vec![])
};

Comma1<T>: Vec<T> = {
    <t:T> => vec![t],
    <v:Comma<T>> "," <t:T> => {
        let mut v = v;
        v.push(t);
        v
    }
};

Pipe<T>: Vec<T> = {
    Pipe1<T>? => <>.unwrap_or(vec![])
};

Pipe1<T>: Vec<T> = {
    <t:T> => vec![t],
    <v:Pipe<T>> "|" <t:T> => {
        let mut v = v;
        v.push(t);
        v
    }
};

Description: String = {
    <d:CommentedString+> => {
        d.join(" ")
    }
};

// NOTE: These are all gross, can they be improved?
Name: String = r"[_A-Za-z][_0-9A-Za-z]*" => <>.to_owned();

EQUALS_SIGN: String = => "".to_string();

DefaultValue:      String = <s:r"=\s*.+">      => s[1..s.len()].trim().to_owned();
CommentedString:  String = <s:r"#\s*.+">      => s[1..s.len()].trim().to_owned();
QuotedString: String = <s:r#""[^"]*""#>   => s[1..s.len()-1].to_owned();

FieldName: String = {
    r"[_A-Za-z][_0-9A-Za-z]*" => <>.to_owned(),
    "scalar"  => "scalar".to_owned(),
    "type"  => "type".to_owned(),
    "enum"  => "enum".to_owned(),
    "interface"  => "interface".to_owned(),
    "union"  => "union".to_owned(),
    "input"  => "input".to_owned(),
};