# -*- coding: utf-8 -*- # # frozen_string_literal: true module Rouge module Lexers class GraphQL < RegexLexer desc 'GraphQL' tag 'graphql' filenames '*.graphql', '*.gql' mimetypes 'application/graphql' name = /[_A-Za-z][_0-9A-Za-z]*/ state :root do rule %r/\b(?:query|mutation|subscription)\b/, Keyword, :query_definition rule %r/\{/ do token Punctuation push :query_definition push :selection_set end rule %r/\bfragment\b/, Keyword, :fragment_definition rule %r/\bscalar\b/, Keyword, :value rule %r/\b(?:type|interface|enum)\b/, Keyword, :type_definition rule %r/\b(?:input|schema)\b/, Keyword, :type_definition rule %r/\bunion\b/, Keyword, :union_definition rule %r/\bextend\b/, Keyword mixin :basic # Markdown descriptions rule %r/(""")(\n)(.*?)(\n)(""")/m do |m| token Str::Double, m[1] token Text::Whitespace, m[2] delegate Markdown, m[3] token Text::Whitespace, m[4] token Str::Double, m[5] end end state :basic do rule %r/\s+/m, Text::Whitespace rule %r/#.*$/, Comment rule %r/[!,]/, Punctuation end state :has_directives do rule %r/(@#{name})(\s*)(\()/ do groups Keyword, Text::Whitespace, Punctuation push :arguments end rule %r/@#{name}\b/, Keyword end state :fragment_definition do rule %r/\bon\b/, Keyword mixin :query_definition end state :query_definition do mixin :has_directives rule %r/\b#{name}\b/, Name rule %r/\(/, Punctuation, :variable_definitions rule %r/\{/, Punctuation, :selection_set mixin :basic end state :type_definition do rule %r/\bimplements\b/, Keyword rule %r/\b#{name}\b/, Name rule %r/\(/, Punctuation, :variable_definitions rule %r/\{/, Punctuation, :type_definition_set mixin :basic end state :union_definition do rule %r/\b#{name}\b/, Name rule %r/\=/, Punctuation, :union_definition_variant mixin :basic end state :union_definition_variant do rule %r/\b#{name}\b/ do token Name pop! push :union_definition_pipe end mixin :basic end state :union_definition_pipe do rule %r/\|/ do token Punctuation pop! push :union_definition_variant end rule %r/(?!\||\s+|#[^\n]*)/ do pop! 2 end mixin :basic end state :type_definition_set do rule %r/\}/ do token Punctuation pop! 2 end rule %r/\b(#{name})(\s*)(\()/ do groups Name, Text::Whitespace, Punctuation push :variable_definitions end rule %r/\b#{name}\b/, Name rule %r/:/, Punctuation, :type_names mixin :basic end state :arguments do rule %r/\)/ do token Punctuation pop! end rule %r/\b#{name}\b/, Name rule %r/:/, Punctuation, :value mixin :basic end state :variable_definitions do rule %r/\)/ do token Punctuation pop! end rule %r/\$#{name}\b/, Name::Variable rule %r/\b#{name}\b/, Name rule %r/:/, Punctuation, :type_names rule %r/\=/, Punctuation, :value mixin :basic end state :type_names do rule %r/\b(?:Int|Float|String|Boolean|ID)\b/, Name::Builtin, :pop! rule %r/\b#{name}\b/, Name, :pop! rule %r/\[/, Punctuation, :type_name_list mixin :basic end state :type_name_list do rule %r/\b(?:Int|Float|String|Boolean|ID)\b/, Name::Builtin rule %r/\b#{name}\b/, Name rule %r/\]/ do token Punctuation pop! 2 end mixin :basic end state :selection_set do mixin :has_directives rule %r/\}/ do token Punctuation pop! pop! if state?(:query_definition) || state?(:fragment_definition) end rule %r/\b(#{name})(\s*)(\()/ do groups Name, Text::Whitespace, Punctuation push :arguments end rule %r/\b(#{name})(\s*)(:)/ do groups Name, Text::Whitespace, Punctuation end rule %r/\b#{name}\b/, Name rule %r/(\.\.\.)(\s+)(on)\b/ do groups Punctuation, Text::Whitespace, Keyword end rule %r/\.\.\./, Punctuation rule %r/\{/, Punctuation, :selection_set mixin :basic end state :list do rule %r/\]/ do token Punctuation pop! pop! if state?(:value) end mixin :value end state :object do rule %r/\}/ do token Punctuation pop! pop! if state?(:value) end rule %r/\b(#{name})(\s*)(:)/ do groups Name, Text::Whitespace, Punctuation push :value end mixin :basic end state :value do pop_unless_list = ->(t) { ->(m) { token t pop! unless state?(:list) } } # Multiline strings rule %r/""".*?"""/m, Str::Double rule %r/\$#{name}\b/, &pop_unless_list[Name::Variable] rule %r/\b(?:true|false|null)\b/, &pop_unless_list[Keyword::Constant] rule %r/[+-]?[0-9]+\.[0-9]+(?:[eE][+-]?[0-9]+)?/, &pop_unless_list[Num::Float] rule %r/[+-]?[1-9][0-9]*(?:[eE][+-]?[0-9]+)?/, &pop_unless_list[Num::Integer] rule %r/"(\\[\\"]|[^"])*"/, &pop_unless_list[Str::Double] rule %r/\b#{name}\b/, &pop_unless_list[Name] rule %r/\{/, Punctuation, :object rule %r/\[/, Punctuation, :list mixin :basic end end end end