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