lib/graphql/language/nodes.rb in graphql-2.1.13 vs lib/graphql/language/nodes.rb in graphql-2.2.0

- old
+ new

@@ -14,34 +14,34 @@ module DefinitionNode # This AST node's {#line} returns the first line, which may be the description. # @return [Integer] The first line of the definition (not the description) attr_reader :definition_line - def initialize(options = {}) - @definition_line = options.delete(:definition_line) - super(options) + def initialize(definition_line: nil, **_rest) + @definition_line = definition_line + super(**_rest) end end - attr_reader :line, :col, :filename + attr_reader :filename - # Initialize a node by extracting its position, - # then calling the class's `initialize_node` method. - # @param options [Hash] Initial attributes for this node - def initialize(options = {}) - if options.key?(:position_source) - position_source = options.delete(:position_source) - @line = position_source[1] - @col = position_source[2] - else - @line = options.delete(:line) - @col = options.delete(:col) + def line + @line ||= (@source_string && @pos) ? @source_string[0..@pos].count("\n") + 1 : nil + end + + def col + @col ||= if @source_string && @pos + if @pos == 0 + 1 + else + @source_string[0..@pos].split("\n").last.length + end end + end - @filename = options.delete(:filename) - - initialize_node(**options) + def definition_line + @definition_line ||= (@source_string && @definition_pos) ? @source_string[0..@definition_pos].count("\n") + 1 : nil end # Value equality # @return [Boolean] True if `self` is equivalent to `other` def ==(other) @@ -194,12 +194,12 @@ if node_type # Only generate a method if we know what kind of node to make module_eval <<-RUBY, __FILE__, __LINE__ # Singular method: create a node with these options # and return a new `self` which includes that node in this list. - def merge_#{method_name.to_s.sub(/s$/, "")}(node_opts) - merge(#{method_name}: #{method_name} + [#{node_type.name}.new(node_opts)]) + def merge_#{method_name.to_s.sub(/s$/, "")}(**node_opts) + merge(#{method_name}: #{method_name} + [#{node_type.name}.new(**node_opts)]) end RUBY end end @@ -224,17 +224,18 @@ RUBY end end if defined?(@scalar_methods) - if !method_defined?(:initialize_node) - generate_initialize_node + if !@initialize_was_generated + @initialize_was_generated = true + generate_initialize else # This method was defined manually end else - raise "Can't generate_initialize_node because scalar_methods wasn't called; call it before children_methods" + raise "Can't generate_initialize because scalar_methods wasn't called; call it before children_methods" end end # These methods return a plain Ruby value, not another node # - Add reader methods @@ -259,11 +260,19 @@ end RUBY end end - def generate_initialize_node + DEFAULT_INITIALIZE_OPTIONS = [ + "line: nil", + "col: nil", + "pos: nil", + "filename: nil", + "source_string: nil", + ] + + def generate_initialize scalar_method_names = @scalar_methods # TODO: These probably should be scalar methods, but `types` returns an array [:types, :description].each do |extra_method| if method_defined?(extra_method) scalar_method_names += [extra_method] @@ -275,20 +284,31 @@ # Rather than complicating this special case, # let it be overridden (in field) return else arguments = scalar_method_names.map { |m| "#{m}: nil"} + - @children_methods.keys.map { |m| "#{m}: NO_CHILDREN" } + @children_methods.keys.map { |m| "#{m}: NO_CHILDREN" } + + DEFAULT_INITIALIZE_OPTIONS assignments = scalar_method_names.map { |m| "@#{m} = #{m}"} + @children_methods.keys.map { |m| "@#{m} = #{m}.freeze" } + if name.end_with?("Definition") && name != "FragmentDefinition" + arguments << "definition_pos: nil" + assignments << "@definition_pos = definition_pos" + end + keywords = scalar_method_names.map { |m| "#{m}: #{m}"} + @children_methods.keys.map { |m| "#{m}: #{m}" } module_eval <<-RUBY, __FILE__, __LINE__ - def initialize_node #{arguments.join(", ")} + def initialize(#{arguments.join(", ")}) + @line = line + @col = col + @pos = pos + @filename = filename + @source_string = source_string #{assignments.join("\n")} end def self.from_a(filename, line, col, #{(scalar_method_names + @children_methods.keys).join(", ")}) self.new(filename: filename, line: line, col: col, #{keywords.join(", ")}) @@ -334,11 +354,10 @@ class DirectiveLocation < NameOnlyNode end class DirectiveDefinition < AbstractNode - include DefinitionNode attr_reader :description scalar_methods :name, :repeatable children_methods( arguments: Nodes::Argument, locations: Nodes::DirectiveLocation, @@ -363,52 +382,61 @@ }) # @!attribute selections # @return [Array<Nodes::Field>] Selections on this object (or empty array if this is a scalar field) - def initialize_node(attributes) - @name = attributes[:name] - @arguments = attributes[:arguments] || NONE - @directives = attributes[:directives] || NONE - @selections = attributes[:selections] || NONE + def initialize(name: nil, arguments: NONE, directives: NONE, selections: NONE, field_alias: nil, line: nil, col: nil, pos: nil, filename: nil, source_string: nil) + @name = name + @arguments = arguments || NONE + @directives = directives || NONE + @selections = selections || NONE # oops, alias is a keyword: - @alias = attributes[:alias] + @alias = field_alias + @line = line + @col = col + @pos = pos + @filename = filename + @source_string = source_string end - def self.from_a(filename, line, col, graphql_alias, name, arguments, directives, selections) # rubocop:disable Metrics/ParameterLists - self.new(filename: filename, line: line, col: col, alias: graphql_alias, name: name, arguments: arguments, directives: directives, selections: selections) + def self.from_a(filename, line, col, field_alias, name, arguments, directives, selections) # rubocop:disable Metrics/ParameterLists + self.new(filename: filename, line: line, col: col, field_alias: field_alias, name: name, arguments: arguments, directives: directives, selections: selections) end # Override this because default is `:fields` self.children_method_name = :selections end # A reusable fragment, defined at document-level. class FragmentDefinition < AbstractNode + scalar_methods :name, :type + children_methods({ + selections: GraphQL::Language::Nodes::Field, + directives: GraphQL::Language::Nodes::Directive, + }) + + self.children_method_name = :definitions # @!attribute name # @return [String] the identifier for this fragment, which may be applied with `...#{name}` # @!attribute type # @return [String] the type condition for this fragment (name of type which it may apply to) - def initialize_node(name: nil, type: nil, directives: [], selections: []) + def initialize(name: nil, type: nil, directives: NONE, selections: NONE, filename: nil, pos: nil, source_string: nil, line: nil, col: nil) @name = name @type = type @directives = directives @selections = selections + @filename = filename + @pos = pos + @source_string = source_string + @line = line + @col = col end def self.from_a(filename, line, col, name, type, directives, selections) self.new(filename: filename, line: line, col: col, name: name, type: type, directives: directives, selections: selections) end - - scalar_methods :name, :type - children_methods({ - selections: GraphQL::Language::Nodes::Field, - directives: GraphQL::Language::Nodes::Directive, - }) - - self.children_method_name = :definitions end # Application of a named fragment in a selection class FragmentSpread < AbstractNode scalar_methods :name @@ -560,11 +588,10 @@ class VariableIdentifier < NameOnlyNode self.children_method_name = :value end class SchemaDefinition < AbstractNode - include DefinitionNode scalar_methods :query, :mutation, :subscription children_methods({ directives: GraphQL::Language::Nodes::Directive, }) self.children_method_name = :definitions @@ -577,11 +604,10 @@ }) self.children_method_name = :definitions end class ScalarTypeDefinition < AbstractNode - include DefinitionNode attr_reader :description scalar_methods :name children_methods({ directives: GraphQL::Language::Nodes::Directive, }) @@ -595,21 +621,19 @@ }) self.children_method_name = :definitions end class InputValueDefinition < AbstractNode - include DefinitionNode attr_reader :description scalar_methods :name, :type, :default_value children_methods({ directives: GraphQL::Language::Nodes::Directive, }) self.children_method_name = :fields end class FieldDefinition < AbstractNode - include DefinitionNode attr_reader :description scalar_methods :name, :type children_methods({ arguments: GraphQL::Language::Nodes::InputValueDefinition, directives: GraphQL::Language::Nodes::Directive, @@ -626,11 +650,10 @@ super end end class ObjectTypeDefinition < AbstractNode - include DefinitionNode attr_reader :description scalar_methods :name, :interfaces children_methods({ directives: GraphQL::Language::Nodes::Directive, fields: GraphQL::Language::Nodes::FieldDefinition, @@ -646,11 +669,10 @@ }) self.children_method_name = :definitions end class InterfaceTypeDefinition < AbstractNode - include DefinitionNode attr_reader :description scalar_methods :name children_methods({ interfaces: GraphQL::Language::Nodes::TypeName, directives: GraphQL::Language::Nodes::Directive, @@ -668,11 +690,10 @@ }) self.children_method_name = :definitions end class UnionTypeDefinition < AbstractNode - include DefinitionNode attr_reader :description, :types scalar_methods :name children_methods({ directives: GraphQL::Language::Nodes::Directive, }) @@ -687,21 +708,19 @@ }) self.children_method_name = :definitions end class EnumValueDefinition < AbstractNode - include DefinitionNode attr_reader :description scalar_methods :name children_methods({ directives: GraphQL::Language::Nodes::Directive, }) self.children_method_name = :values end class EnumTypeDefinition < AbstractNode - include DefinitionNode attr_reader :description scalar_methods :name children_methods({ directives: GraphQL::Language::Nodes::Directive, values: GraphQL::Language::Nodes::EnumValueDefinition, @@ -717,10 +736,9 @@ }) self.children_method_name = :definitions end class InputObjectTypeDefinition < AbstractNode - include DefinitionNode attr_reader :description scalar_methods :name children_methods({ directives: GraphQL::Language::Nodes::Directive, fields: GraphQL::Language::Nodes::InputValueDefinition,