lib/graph_ql/parser.rb in graphql-0.3.0 vs lib/graph_ql/parser.rb in graphql-0.4.0

- old
+ new

@@ -1,9 +1,110 @@ -require 'graph_ql/parser/nodes' -require 'graph_ql/parser/parser' -require 'graph_ql/parser/transform' -require 'graph_ql/parser/visitor' - module GraphQL + # Parser is a [parslet](http://kschiess.github.io/parslet/) parser for parsing queries. + # + class Parser < Parslet::Parser + root(:document) + rule(:document) { ( + space | + operation_definition | + fragment_definition + ).repeat(1).as(:document_parts) + } + + # TODO: whitespace sensitive regarding `on`, eg `onFood`, see lookahead note in spec + rule(:fragment_definition) { + str("fragment").as(:fragment_keyword) >> + space? >> name.as(:fragment_name) >> + space? >> str("on") >> space? >> name.as(:type_condition) >> + space? >> directives.maybe.as(:optional_directives).as(:directives) >> + space? >> selections.as(:selections) + } + + rule(:fragment_spread) { + spread.as(:fragment_spread_keyword) >> space? >> + name.as(:fragment_spread_name) >> space? >> + directives.maybe.as(:optional_directives).as(:directives) + } + rule(:spread) { str("...") } + # TODO: `on` bug, see spec + rule(:inline_fragment) { + spread.as(:fragment_spread_keyword) >> space? >> + str("on ") >> name.as(:inline_fragment_type) >> space? >> + directives.maybe.as(:optional_directives).as(:directives) >> space? >> + selections.as(:selections) + } + + rule(:operation_definition) { (unnamed_selections | named_operation_definition) } + rule(:unnamed_selections) { selections.as(:unnamed_selections)} + rule(:named_operation_definition) { + operation_type.as(:operation_type) >> space? >> + name.as(:name) >> space? >> + operation_variable_definitions.maybe.as(:optional_variables).as(:variables) >> space? >> + directives.maybe.as(:optional_directives).as(:directives) >> space? >> + selections.as(:selections) + } + rule(:operation_type) { (str("query") | str("mutation")) } + rule(:operation_variable_definitions) { str("(") >> space? >> (operation_variable_definition >> separator?).repeat(1) >> space? >> str(")") } + rule(:operation_variable_definition) { + value_variable.as(:variable_name) >> space? >> + str(":") >> space? >> + type.as(:variable_type) >> space? >> + (str("=") >> space? >> value.as(:variable_default_value)).maybe.as(:variable_optional_default_value)} + + rule(:selection) { (inline_fragment | fragment_spread | field) >> space? >> separator? } + rule(:selections) { str("{") >> space? >> selection.repeat(1) >> space? >> str("}")} + + rule(:field) { + field_alias.maybe.as(:alias) >> + name.as(:field_name) >> + field_arguments.maybe.as(:optional_field_arguments).as(:field_arguments) >> space? >> + directives.maybe.as(:optional_directives).as(:directives) >> space? >> + selections.maybe.as(:optional_selections).as(:selections) + } + + rule(:field_alias) { name.as(:alias_name) >> space? >> str(":") >> space? } + rule(:field_arguments) { str("(") >> field_argument.repeat(1) >> str(")") } + rule(:field_argument) { name.as(:field_argument_name) >> str(":") >> space? >> value.as(:field_argument_value) >> separator? } + + rule(:directives) { (directive >> separator?).repeat(1) } + rule(:directive) { + str("@") >> name.as(:directive_name) >> + directive_arguments.maybe.as(:optional_directive_arguments).as(:directive_arguments) + } + rule(:directive_arguments) { str("(") >> directive_argument.repeat(1) >> str(")") } + rule(:directive_argument) { name.as(:directive_argument_name) >> str(":") >> space? >> value.as(:directive_argument_value) >> separator? } + + rule(:type) { (non_null_type | list_type | type_name)} + rule(:list_type) { str("[") >> type.as(:list_type) >> str("]")} + rule(:non_null_type) { (list_type | type_name).as(:non_null_type) >> str("!") } + rule(:type_name) { name.as(:type_name) } + + rule(:value) {( + value_input_object | + value_float | + value_int | + value_string | + value_boolean | + value_array | + value_variable | + value_enum + )} + rule(:value_sign?) { match('[\-\+]').maybe } + rule(:value_array) { (str("[") >> (value >> separator?).repeat(0) >> str("]")).as(:array) } + rule(:value_boolean) { (str("true") | str("false")).as(:boolean) } + rule(:value_float) { (value_sign? >> match('\d').repeat(1) >> str(".") >> match('\d').repeat(1) >> (match("[eE]") >> value_sign? >> match('\d').repeat(1)).maybe).as(:float) } + rule(:value_input_object) { str("{") >> value_input_object_pair.repeat(1).as(:input_object) >> str("}") } + rule(:value_input_object_pair) { space? >> name.as(:input_object_name) >> space? >> str(":") >> space? >> value.as(:input_object_value) >> separator? } + rule(:value_int) { (value_sign? >> match('\d').repeat(1)).as(:int) } + # TODO: support unicode, escaped chars (match the spec) + rule(:value_string) { str('"') >> match('[^\"]').repeat(1).as(:string) >> str('"')} + rule(:value_enum) { name.as(:enum) } + rule(:value_variable) { str("$") >> name.as(:variable) } + + rule(:separator?) { (space? >> str(",") >> space?).maybe } + rule(:name) { match('[_A-Za-z]') >> match('[_0-9A-Za-z]').repeat(0) } + rule(:comment) { str("#") >> match('[^\r\n]').repeat(0) } + rule(:space) { (match('[\s\n]+') | comment).repeat(1) } + rule(:space?) { space.maybe } + end PARSER = GraphQL::Parser.new - TRANSFORM = GraphQL::Transform.new end