From 9db9f74d3689a8b399d38af781e70cf7e3e80270 Mon Sep 17 00:00:00 2001 From: Ivan Maximov Date: Thu, 20 Apr 2023 15:26:46 +0300 Subject: [PATCH 1/2] Allow to parse more AST nodes --- src/GraphQLParser.Tests/Extensions.cs | 11 + .../ParserTests.CustomAST.cs | 316 ++++++++++++++++++ src/GraphQLParser.Tests/ParserTests.Throw.cs | 4 +- src/GraphQLParser.Tests/ParserTests.cs | 22 -- src/GraphQLParser/Parser.cs | 69 +++- src/GraphQLParser/ParserContext.Parse.cs | 100 +++--- 6 files changed, 446 insertions(+), 76 deletions(-) create mode 100644 src/GraphQLParser.Tests/ParserTests.CustomAST.cs diff --git a/src/GraphQLParser.Tests/Extensions.cs b/src/GraphQLParser.Tests/Extensions.cs index c0f9a08c..ee69a0a7 100644 --- a/src/GraphQLParser.Tests/Extensions.cs +++ b/src/GraphQLParser.Tests/Extensions.cs @@ -19,4 +19,15 @@ internal static class ParserTestExtensions /// Parser options. /// AST (Abstract Syntax Tree) for GraphQL document. public static GraphQLDocument Parse(this string source, ParserOptions options = default) => Parser.Parse(source, options); + + /// + /// Generates AST based on input text. + /// + /// Type of node to parse input text as. + /// Input data as a sequence of characters. + /// Parser options. + /// AST (Abstract Syntax Tree) for GraphQL node. + public static T Parse(this string source, ParserOptions options = default) + where T : ASTNode + => Parser.Parse(source, options); } diff --git a/src/GraphQLParser.Tests/ParserTests.CustomAST.cs b/src/GraphQLParser.Tests/ParserTests.CustomAST.cs new file mode 100644 index 00000000..fc8eb7b9 --- /dev/null +++ b/src/GraphQLParser.Tests/ParserTests.CustomAST.cs @@ -0,0 +1,316 @@ +using GraphQLParser.Exceptions; + +namespace GraphQLParser.Tests; + +public class ParserTestsCustomAST +{ + [Fact] + public void Should_Throw_On_Comment() + { + string text = "# comment"; + Should.Throw(() => text.Parse()); + } + + [Theory] + [InlineData("null", ASTNodeKind.NullValue)] + [InlineData("1", ASTNodeKind.IntValue)] + [InlineData("1.1", ASTNodeKind.FloatValue)] + [InlineData("\"abc\"", ASTNodeKind.StringValue, "abc")] + [InlineData("\"escaped \\n\\r\\b\\t\\f\"", ASTNodeKind.StringValue, "escaped \n\r\b\t\f")] + [InlineData("true", ASTNodeKind.BooleanValue)] + [InlineData("RED", ASTNodeKind.EnumValue)] + [InlineData("[ 1, 2, 3]", ASTNodeKind.ListValue)] + [InlineData("{ a: 1, b: \"abc\", c: RED}", ASTNodeKind.ObjectValue)] + [InlineData("$id", ASTNodeKind.Variable)] + public void Should_Parse_Value_Literal_But_Not_Entire_Document(string text, ASTNodeKind kind, string expected = null) + { + Should.Throw(() => Parser.Parse(text)); + + var value = Parser.Parse(text); + value.ShouldNotBeNull(); + value.Kind.ShouldBe(kind); + if (expected != null) + ((GraphQLStringValue)value).Value.ShouldBe(expected); + } + + [Fact] + public void Should_Parse_Variable() + { + string text = "$id"; + var ast = text.Parse().ShouldNotBeNull(); + ast.Name.Value.ShouldBe("id"); + } + + [Fact] + public void Should_Parse_Argument() + { + string text = "id: 5"; + var ast = text.Parse().ShouldNotBeNull(); + ast.Name.Value.ShouldBe("id"); + } + + [Fact] + public void Should_Parse_Arguments() + { + string text = "(id: 5 code: abc)"; + var ast = text.Parse().ShouldNotBeNull(); + ast.Items.Count.ShouldBe(2); + } + + [Fact] + public void Should_Parse_Description() + { + string text = "\"blablalba\""; + var ast = text.Parse().ShouldNotBeNull(); + ast.Value.ShouldBe("blablalba"); + } + + [Fact] + public void Should_Parse_Directive() + { + string text = "@my"; + var ast = text.Parse().ShouldNotBeNull(); + ast.Name.Value.ShouldBe("my"); + } + + [Fact] + public void Should_Parse_Directives() + { + string text = "@my @your"; + var ast = text.Parse().ShouldNotBeNull(); + ast.Items.Count.ShouldBe(2); + } + + [Fact] + public void Should_Parse_Field() + { + string text = "name"; + var ast = text.Parse().ShouldNotBeNull(); + ast.Name.Value.ShouldBe("name"); + } + + [Fact] + public void Should_Parse_SelectionSet() + { + string text = "{ a b }"; + var ast = text.Parse().ShouldNotBeNull(); + ast.Selections.Count.ShouldBe(2); + } + + [Fact] + public void Should_Parse_ArgumentsDefinition() + { + string text = "(size: Int)"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Items.Count.ShouldBe(1); + } + + [Fact] + public void Should_Parse_InputValueDefinition() + { + string text = "size: Int"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Name.Value.ShouldBe("size"); + } + + [Fact] + public void Should_Parse_DirectiveDefinition() + { + string text = "directive @my on FIELD"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Name.Value.ShouldBe("my"); + } + + [Fact] + public void Should_Parse_EnumTypeDefinition() + { + string text = "enum Color { RED }"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Name.Value.ShouldBe("Color"); + } + + [Fact] + public void Should_Parse_EnumValueDefinition() + { + string text = "RED"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Name.Value.ShouldBe("RED"); + } + + [Fact] + public void Should_Parse_EnumValuesDefinition() + { + string text = "{ RED GREEN }"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Items.Count.ShouldBe(2); + } + + [Fact] + public void Should_Parse_FieldDefinition() + { + string text = "name: String"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Name.Value.ShouldBe("name"); + } + + [Fact] + public void Should_Parse_FieldsDefinition() + { + string text = "{ name: String age: Int }"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Items.Count.ShouldBe(2); + } + + [Fact] + public void Should_Parse_FragmentDefinition() + { + string text = "fragment frag on Person { name }"; + var definition = text.Parse().ShouldNotBeNull(); + definition.FragmentName.Name.Value.ShouldBe("frag"); + } + + [Fact] + public void Should_Parse_InputFieldsDefinition() + { + string text = "{ name: String age: Int }"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Items.Count.ShouldBe(2); + } + + [Fact] + public void Should_Parse_InputObjectTypeDefinition() + { + string text = "input Person { name: String }"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Name.Value.ShouldBe("Person"); + } + + [Fact] + public void Should_Parse_InterfaceTypeDefinition() + { + string text = "interface Person { name: String }"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Name.Value.ShouldBe("Person"); + } + + [Fact] + public void Should_Parse_ObjectTypeDefinition() + { + string text = "type Person { name: String }"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Name.Value.ShouldBe("Person"); + } + + [Fact] + public void Should_Parse_OperationDefinition() + { + string text = "mutation x { set(value: 1) }"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Name.Value.ShouldBe("x"); + } + + [Fact] + public void Should_Parse_RootOperationTypeDefinition() + { + string text = "query: Q"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Operation.ShouldBe(OperationType.Query); + } + + [Fact] + public void Should_Parse_ScalarTypeDefinition() + { + string text = "scalar JSON"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Name.Value.ShouldBe("JSON"); + } + + [Fact] + public void Should_Parse_SchemaDefinition() + { + string text = "schema { query: Q subscription: S }"; + var definition = text.Parse().ShouldNotBeNull(); + definition.OperationTypes.Count.ShouldBe(2); + } + + [Fact] + public void Should_Parse_UnionTypeDefinition() + { + string text = "union U = A | B"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Name.Value.ShouldBe("U"); + } + + [Fact] + public void Should_Parse_VariableDefinition() + { + string text = "$id: Int"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Variable.Name.Value.ShouldBe("id"); + } + + [Fact] + public void Should_Parse_VariablesDefinition() + { + string text = "($id: Int, $amount: Float)"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Items.Count.ShouldBe(2); + } + + [Fact] + public void Should_Parse_EnumTypeExtension() + { + string text = "extend enum Color { YELLOW }"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Name.Value.ShouldBe("Color"); + } + + [Fact] + public void Should_Parse_InputObjectTypeExtension() + { + string text = "extend input Person { address: String }"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Name.Value.ShouldBe("Person"); + } + + [Fact] + public void Should_Parse_InterfaceTypeExtension() + { + string text = "extend interface Person { address: String }"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Name.Value.ShouldBe("Person"); + } + + [Fact] + public void Should_Parse_ObjectTypeExtension() + { + string text = "extend type Person { address: String }"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Name.Value.ShouldBe("Person"); + } + + [Fact] + public void Should_Parse_ScalarTypeExtension() + { + string text = "extend scalar JSON @my"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Name.Value.ShouldBe("JSON"); + } + + [Fact] + public void Should_Parse_SchemaExtension() + { + string text = "extend schema { subscription : S }"; + var definition = text.Parse().ShouldNotBeNull(); + definition.OperationTypes.Count.ShouldBe(1); + } + + [Fact] + public void Should_Parse_UnionTypeExtension() + { + string text = "extend union U @my @external"; + var definition = text.Parse().ShouldNotBeNull(); + definition.Name.Value.ShouldBe("U"); + definition.Directives.Items.Count.ShouldBe(2); + } +} diff --git a/src/GraphQLParser.Tests/ParserTests.Throw.cs b/src/GraphQLParser.Tests/ParserTests.Throw.cs index 616da69e..868e136a 100644 --- a/src/GraphQLParser.Tests/ParserTests.Throw.cs +++ b/src/GraphQLParser.Tests/ParserTests.Throw.cs @@ -322,8 +322,8 @@ public void Should_Throw_On_Unknown_Cases_From_ExpectOneOf() () => { var context = new ParserContext("extend abc", default); - context.ParseTypeExtension(new[] { "abc" }); + context.ParseTypeSystemExtension(new[] { "abc" }); }) - .Message.ShouldBe("Unexpected keyword 'abc' in ParseTypeExtension."); + .Message.ShouldBe("Unexpected keyword 'abc' in ParseTypeSystemExtension."); } } diff --git a/src/GraphQLParser.Tests/ParserTests.cs b/src/GraphQLParser.Tests/ParserTests.cs index f9de4ca6..ab9a6423 100644 --- a/src/GraphQLParser.Tests/ParserTests.cs +++ b/src/GraphQLParser.Tests/ParserTests.cs @@ -1,6 +1,5 @@ using System.Collections; using System.Runtime.InteropServices; -using GraphQLParser.Exceptions; namespace GraphQLParser.Tests; @@ -980,27 +979,6 @@ public void Should_Parse_Empty_Types(string text, ASTNodeKind kind) document.Definitions[0].Kind.ShouldBe(kind); } - [Theory] - [InlineData("null", ASTNodeKind.NullValue)] - [InlineData("1", ASTNodeKind.IntValue)] - [InlineData("1.1", ASTNodeKind.FloatValue)] - [InlineData("\"abc\"", ASTNodeKind.StringValue, "abc")] - [InlineData("\"escaped \\n\\r\\b\\t\\f\"", ASTNodeKind.StringValue, "escaped \n\r\b\t\f")] - [InlineData("true", ASTNodeKind.BooleanValue)] - [InlineData("RED", ASTNodeKind.EnumValue)] - [InlineData("[ 1, 2, 3]", ASTNodeKind.ListValue)] - [InlineData("{ a: 1, b: \"abc\", c: RED}", ASTNodeKind.ObjectValue)] - public void Should_Parse_Value_Literal_But_Not_Entire_Document(string text, ASTNodeKind kind, string expected = null) - { - Should.Throw(() => Parser.Parse(text)); - - var value = Parser.Parse(text); - value.ShouldNotBeNull(); - value.Kind.ShouldBe(kind); - if (expected != null) - ((GraphQLStringValue)value).Value.ShouldBe(expected); - } - [Theory] [InlineData(IgnoreOptions.None)] [InlineData(IgnoreOptions.Comments)] diff --git a/src/GraphQLParser/Parser.cs b/src/GraphQLParser/Parser.cs index eefafc7f..147764a7 100644 --- a/src/GraphQLParser/Parser.cs +++ b/src/GraphQLParser/Parser.cs @@ -17,7 +17,7 @@ public static class Parser /// In case when parser recursion depth exceeds . /// In case of syntax error. public static GraphQLDocument Parse(ROM source, ParserOptions options = default) - => new ParserContext(source, options).ParseDocument(); + => Parse(source, options); /// /// Generates AST based on input text. @@ -34,18 +34,81 @@ public static T Parse(ROM source, ParserOptions options = default) { var context = new ParserContext(source, options); T result; + + // main use case if (typeof(T) == typeof(GraphQLDocument)) result = (T)(object)context.ParseDocument(); + else if (typeof(T) == typeof(GraphQLValue)) - result = (T)(object)context.ParseValueLiteral(true); + result = (T)(object)context.ParseValueLiteral(null); + else if (typeof(T) == typeof(GraphQLVariable)) + result = (T)(object)context.ParseVariable(); else if (typeof(T) == typeof(GraphQLArgument)) result = (T)(object)context.ParseArgument(); else if (typeof(T) == typeof(GraphQLArguments)) result = (T)(object)context.ParseArguments(); - /* and so on */ + else if (typeof(T) == typeof(GraphQLDescription)) + result = (T)(object)context.ParseDescription(); + else if (typeof(T) == typeof(GraphQLDirective)) + result = (T)(object)context.ParseDirective(); + else if (typeof(T) == typeof(GraphQLDirectives)) + result = (T)(object)context.ParseDirectives(); + else if (typeof(T) == typeof(GraphQLField)) + result = (T)(object)context.ParseField(); + else if (typeof(T) == typeof(GraphQLSelectionSet)) + result = (T)(object)context.ParseSelectionSet(); + + // definitions + else if (typeof(T) == typeof(GraphQLArgumentsDefinition)) + result = (T)(object)context.ParseArgumentsDefinition(); + else if (typeof(T) == typeof(GraphQLDirectiveDefinition)) + result = (T)(object)context.ParseDirectiveDefinition(); + else if (typeof(T) == typeof(GraphQLEnumTypeDefinition)) + result = (T)(object)context.ParseEnumTypeDefinition(); + else if (typeof(T) == typeof(GraphQLEnumValueDefinition)) + result = (T)(object)context.ParseEnumValueDefinition(); + else if (typeof(T) == typeof(GraphQLEnumValuesDefinition)) + result = (T)(object)context.ParseEnumValuesDefinition(); + else if (typeof(T) == typeof(GraphQLFieldDefinition)) + result = (T)(object)context.ParseFieldDefinition(); + else if (typeof(T) == typeof(GraphQLFieldsDefinition)) + result = (T)(object)context.ParseFieldsDefinition(); + else if (typeof(T) == typeof(GraphQLFragmentDefinition)) + result = (T)(object)context.ParseFragmentDefinition(); + else if (typeof(T) == typeof(GraphQLInputFieldsDefinition)) + result = (T)(object)context.ParseInputFieldsDefinition(); + else if (typeof(T) == typeof(GraphQLInputObjectTypeDefinition)) + result = (T)(object)context.ParseInputObjectTypeDefinition(); + else if (typeof(T) == typeof(GraphQLInputValueDefinition)) + result = (T)(object)context.ParseInputValueDefinition(); + else if (typeof(T) == typeof(GraphQLInterfaceTypeDefinition)) + result = (T)(object)context.ParseInterfaceTypeDefinition(); + else if (typeof(T) == typeof(GraphQLObjectTypeDefinition)) + result = (T)(object)context.ParseObjectTypeDefinition(); + else if (typeof(T) == typeof(GraphQLOperationDefinition)) + result = (T)(object)context.ParseOperationDefinition(); + else if (typeof(T) == typeof(GraphQLRootOperationTypeDefinition)) + result = (T)(object)context.ParseRootOperationTypeDefinition(); + else if (typeof(T) == typeof(GraphQLScalarTypeDefinition)) + result = (T)(object)context.ParseScalarTypeDefinition(); + else if (typeof(T) == typeof(GraphQLSchemaDefinition)) + result = (T)(object)context.ParseSchemaDefinition(); + else if (typeof(T) == typeof(GraphQLUnionTypeDefinition)) + result = (T)(object)context.ParseUnionTypeDefinition(); + else if (typeof(T) == typeof(GraphQLVariableDefinition)) + result = (T)(object)context.ParseVariableDefinition(); + else if (typeof(T) == typeof(GraphQLVariablesDefinition)) + result = (T)(object)context.ParseVariablesDefinition(); + + // extensions + else if (typeof(T) == typeof(GraphQLSchemaExtension) || typeof(GraphQLTypeExtension).IsAssignableFrom(typeof(T))) + result = (T)(object)context.ParseTypeSystemExtension(); + else throw new NotSupportedException(); + context.Expect(TokenKind.EOF); + return result; } } diff --git a/src/GraphQLParser/ParserContext.Parse.cs b/src/GraphQLParser/ParserContext.Parse.cs index c34254ca..c036b4ae 100644 --- a/src/GraphQLParser/ParserContext.Parse.cs +++ b/src/GraphQLParser/ParserContext.Parse.cs @@ -52,7 +52,7 @@ public GraphQLDocument ParseDocument() } // http://spec.graphql.org/October2021/#Argument - internal GraphQLArgument ParseArgument() + public GraphQLArgument ParseArgument() { IncreaseDepth(); @@ -71,7 +71,7 @@ internal GraphQLArgument ParseArgument() } // http://spec.graphql.org/October2021/#Arguments - internal GraphQLArguments ParseArguments() + public GraphQLArguments ParseArguments() { IncreaseDepth(); @@ -88,7 +88,7 @@ internal GraphQLArguments ParseArguments() } // http://spec.graphql.org/October2021/#ArgumentsDefinition - private GraphQLArgumentsDefinition ParseArgumentsDefinition() + public GraphQLArgumentsDefinition ParseArgumentsDefinition() { IncreaseDepth(); @@ -97,7 +97,7 @@ private GraphQLArgumentsDefinition ParseArgumentsDefinition() var argsDef = NodeHelper.CreateGraphQLArgumentsDefinition(_ignoreOptions); argsDef.Comments = GetComments(); - argsDef.Items = OneOrMore(TokenKind.PAREN_L, (ref ParserContext context) => context.ParseInputValueDef(), TokenKind.PAREN_R); + argsDef.Items = OneOrMore(TokenKind.PAREN_L, (ref ParserContext context) => context.ParseInputValueDefinition(), TokenKind.PAREN_R); argsDef.Location = GetLocation(start); DecreaseDepth(); @@ -105,7 +105,7 @@ private GraphQLArgumentsDefinition ParseArgumentsDefinition() } // http://spec.graphql.org/October2021/#InputFieldsDefinition - private GraphQLInputFieldsDefinition ParseInputFieldsDefinition() + public GraphQLInputFieldsDefinition ParseInputFieldsDefinition() { IncreaseDepth(); @@ -114,7 +114,7 @@ private GraphQLInputFieldsDefinition ParseInputFieldsDefinition() var inputFieldsDef = NodeHelper.CreateGraphQLInputFieldsDefinition(_ignoreOptions); inputFieldsDef.Comments = GetComments(); - inputFieldsDef.Items = OneOrMore(TokenKind.BRACE_L, (ref ParserContext context) => context.ParseInputValueDef(), TokenKind.BRACE_R); + inputFieldsDef.Items = OneOrMore(TokenKind.BRACE_L, (ref ParserContext context) => context.ParseInputValueDefinition(), TokenKind.BRACE_R); inputFieldsDef.Location = GetLocation(start); DecreaseDepth(); @@ -122,7 +122,7 @@ private GraphQLInputFieldsDefinition ParseInputFieldsDefinition() } // http://spec.graphql.org/October2021/#FieldsDefinition - private GraphQLFieldsDefinition ParseFieldsDefinition() + public GraphQLFieldsDefinition ParseFieldsDefinition() { IncreaseDepth(); @@ -139,7 +139,7 @@ private GraphQLFieldsDefinition ParseFieldsDefinition() } // http://spec.graphql.org/October2021/#EnumValuesDefinition - private GraphQLEnumValuesDefinition ParseEnumValuesDefinition() + public GraphQLEnumValuesDefinition ParseEnumValuesDefinition() { IncreaseDepth(); @@ -156,7 +156,7 @@ private GraphQLEnumValuesDefinition ParseEnumValuesDefinition() } // http://spec.graphql.org/October2021/#VariableDefinitions - private GraphQLVariablesDefinition ParseVariablesDefinition() + public GraphQLVariablesDefinition ParseVariablesDefinition() { IncreaseDepth(); @@ -272,7 +272,7 @@ private void SetCurrentComments(List? comments) } // http://spec.graphql.org/October2021/#Directive - private GraphQLDirective ParseDirective() + public GraphQLDirective ParseDirective() { IncreaseDepth(); @@ -291,7 +291,7 @@ private GraphQLDirective ParseDirective() } // http://spec.graphql.org/October2021/#DirectiveDefinition - private GraphQLDirectiveDefinition ParseDirectiveDefinition() + public GraphQLDirectiveDefinition ParseDirectiveDefinition() { IncreaseDepth(); @@ -359,7 +359,7 @@ private GraphQLDirectiveLocations ParseDirectiveLocations() } // http://spec.graphql.org/October2021/#Directives - private GraphQLDirectives ParseDirectives() + public GraphQLDirectives ParseDirectives() { IncreaseDepth(); // Directives go one after another without any "list prefix", so it is impossible @@ -386,7 +386,7 @@ private GraphQLDirectives ParseDirectives() } // http://spec.graphql.org/October2021/#EnumTypeDefinition - private GraphQLEnumTypeDefinition ParseEnumTypeDefinition() + public GraphQLEnumTypeDefinition ParseEnumTypeDefinition() { IncreaseDepth(); @@ -452,7 +452,7 @@ private GraphQLEnumValue ParseEnumValue(bool validate) } // http://spec.graphql.org/October2021/#EnumValueDefinition - private GraphQLEnumValueDefinition ParseEnumValueDefinition() + public GraphQLEnumValueDefinition ParseEnumValueDefinition() { IncreaseDepth(); @@ -472,7 +472,7 @@ private GraphQLEnumValueDefinition ParseEnumValueDefinition() } // http://spec.graphql.org/October2021/#FieldDefinition - private GraphQLFieldDefinition ParseFieldDefinition() + public GraphQLFieldDefinition ParseFieldDefinition() { IncreaseDepth(); @@ -495,7 +495,7 @@ private GraphQLFieldDefinition ParseFieldDefinition() // http://spec.graphql.org/October2021/#Field // http://spec.graphql.org/October2021/#Alias - private GraphQLField ParseField() + public GraphQLField ParseField() { IncreaseDepth(); @@ -556,7 +556,7 @@ private GraphQLField ParseField() } // http://spec.graphql.org/October2021/#FloatValue - private GraphQLFloatValue ParseFloatValue(/*bool isConstant*/) + private GraphQLFloatValue ParseFloatValue() { IncreaseDepth(); @@ -617,7 +617,7 @@ private GraphQLInlineFragment ParseInlineFragment(int start, List constant = (ref ParserContext context) => context.ParseValueLiteral(true); ParseCallback value = (ref ParserContext context) => context.ParseValueLiteral(false); + ParseCallback notMatter = (ref ParserContext context) => context.ParseValueLiteral(null); var val = NodeHelper.CreateGraphQLListValue(_ignoreOptions); val.Comments = GetComments(); - val.Values = ZeroOrMore(TokenKind.BRACKET_L, isConstant ? constant : value, TokenKind.BRACKET_R); + val.Values = ZeroOrMore(TokenKind.BRACKET_L, isConstant.HasValue ? (isConstant.Value ? constant : value) : notMatter, TokenKind.BRACKET_R); val.Location = GetLocation(start); DecreaseDepth(); @@ -873,7 +874,7 @@ private GraphQLName ParseName(string description) "union" => ParseUnionTypeDefinition(), "enum" => ParseEnumTypeDefinition(), "input" => ParseInputObjectTypeDefinition(), - "extend" => ParseTypeExtension(), + "extend" => ParseTypeSystemExtension(), "directive" => ParseDirectiveDefinition(), _ => throw new NotSupportedException($"Unexpected keyword '{keyword}' in {nameof(ParseNamedDefinition)}.") @@ -927,7 +928,7 @@ private GraphQLNamedType ParseNamedType() return named; } - private GraphQLValue ParseNameValue(/*bool isConstant*/) + private GraphQLValue ParseNameValue() { return _currentToken.Value.Span switch { @@ -939,7 +940,7 @@ private GraphQLValue ParseNameValue(/*bool isConstant*/) } // http://spec.graphql.org/October2021/#ObjectValue - private GraphQLValue ParseObjectValue(bool isConstant) + private GraphQLValue ParseObjectValue(bool? isConstant) { IncreaseDepth(); @@ -948,11 +949,12 @@ private GraphQLValue ParseObjectValue(bool isConstant) // the compiler caches these delegates in the generated code ParseCallback constant = (ref ParserContext context) => context.ParseObjectField(true); ParseCallback value = (ref ParserContext context) => context.ParseObjectField(false); + ParseCallback notMatter = (ref ParserContext context) => context.ParseObjectField(null); var val = NodeHelper.CreateGraphQLObjectValue(_ignoreOptions); val.Comments = GetComments(); - val.Fields = ZeroOrMore(TokenKind.BRACE_L, isConstant ? constant : value, TokenKind.BRACE_R); + val.Fields = ZeroOrMore(TokenKind.BRACE_L, isConstant.HasValue ? (isConstant.Value ? constant : value) : notMatter, TokenKind.BRACE_R); val.Location = GetLocation(start); DecreaseDepth(); @@ -977,7 +979,7 @@ private GraphQLValue ParseNullValue() } // http://spec.graphql.org/October2021/#ObjectField - private GraphQLObjectField ParseObjectField(bool isConstant) + private GraphQLObjectField ParseObjectField(bool? isConstant) { IncreaseDepth(); @@ -996,7 +998,7 @@ private GraphQLObjectField ParseObjectField(bool isConstant) } // http://spec.graphql.org/October2021/#ObjectTypeDefinition - private GraphQLObjectTypeDefinition ParseObjectTypeDefinition() + public GraphQLObjectTypeDefinition ParseObjectTypeDefinition() { IncreaseDepth(); @@ -1041,7 +1043,7 @@ private GraphQLObjectTypeExtension ParseObjectTypeExtension(int start, List? comments) { IncreaseDepth(); @@ -1200,7 +1202,7 @@ private GraphQLScalarTypeExtension ParseScalarTypeExtension(int start, List ParseEnumTypeExtension(start, comments), "input" => ParseInputObjectTypeExtension(start, comments), - _ => throw new NotSupportedException($"Unexpected keyword '{keyword}' in {nameof(ParseTypeExtension)}.") + _ => throw new NotSupportedException($"Unexpected keyword '{keyword}' in {nameof(ParseTypeSystemExtension)}.") }; } @@ -1376,7 +1378,7 @@ private GraphQLUnionMemberTypes ParseUnionMemberTypes() } // http://spec.graphql.org/October2021/#UnionTypeDefinition - private GraphQLUnionTypeDefinition ParseUnionTypeDefinition() + public GraphQLUnionTypeDefinition ParseUnionTypeDefinition() { IncreaseDepth(); @@ -1418,23 +1420,23 @@ private GraphQLUnionTypeExtension ParseUnionTypeExtension(int start, List ParseListValue(isConstant), TokenKind.BRACE_L => ParseObjectValue(isConstant), - TokenKind.INT => ParseIntValue(/*isConstant*/), - TokenKind.FLOAT => ParseFloatValue(/*isConstant*/), - TokenKind.STRING => ParseStringValue(/*isConstant*/), - TokenKind.NAME => ParseNameValue(/*isConstant*/), - TokenKind.DOLLAR when !isConstant => ParseVariable(), + TokenKind.INT => ParseIntValue(), + TokenKind.FLOAT => ParseFloatValue(), + TokenKind.STRING => ParseStringValue(), + TokenKind.NAME => ParseNameValue(), + TokenKind.DOLLAR when isConstant != true => ParseVariable(), _ => (GraphQLValue)Throw_Unexpected_Token() }; } // http://spec.graphql.org/October2021/#Variable - private GraphQLVariable ParseVariable() + public GraphQLVariable ParseVariable() { IncreaseDepth(); @@ -1452,7 +1454,7 @@ private GraphQLVariable ParseVariable() } // http://spec.graphql.org/October2021/#VariableDefinition - private GraphQLVariableDefinition ParseVariableDefinition() + public GraphQLVariableDefinition ParseVariableDefinition() { IncreaseDepth(); From 844b2e31ce6f89d7d952c174f6326188ae582315 Mon Sep 17 00:00:00 2001 From: Ivan Maximov Date: Thu, 20 Apr 2023 18:09:29 +0300 Subject: [PATCH 2/2] revert bool? to bool --- src/GraphQLParser.Tests/ParserTests.CustomAST.cs | 2 +- src/GraphQLParser/Parser.cs | 2 +- src/GraphQLParser/ParserContext.Parse.cs | 16 +++++++--------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/GraphQLParser.Tests/ParserTests.CustomAST.cs b/src/GraphQLParser.Tests/ParserTests.CustomAST.cs index fc8eb7b9..7bda9cb3 100644 --- a/src/GraphQLParser.Tests/ParserTests.CustomAST.cs +++ b/src/GraphQLParser.Tests/ParserTests.CustomAST.cs @@ -20,7 +20,7 @@ public void Should_Throw_On_Comment() [InlineData("true", ASTNodeKind.BooleanValue)] [InlineData("RED", ASTNodeKind.EnumValue)] [InlineData("[ 1, 2, 3]", ASTNodeKind.ListValue)] - [InlineData("{ a: 1, b: \"abc\", c: RED}", ASTNodeKind.ObjectValue)] + [InlineData("{ a: 1, b: \"abc\", c: RED, d: $id }", ASTNodeKind.ObjectValue)] [InlineData("$id", ASTNodeKind.Variable)] public void Should_Parse_Value_Literal_But_Not_Entire_Document(string text, ASTNodeKind kind, string expected = null) { diff --git a/src/GraphQLParser/Parser.cs b/src/GraphQLParser/Parser.cs index 147764a7..e590ee25 100644 --- a/src/GraphQLParser/Parser.cs +++ b/src/GraphQLParser/Parser.cs @@ -40,7 +40,7 @@ public static T Parse(ROM source, ParserOptions options = default) result = (T)(object)context.ParseDocument(); else if (typeof(T) == typeof(GraphQLValue)) - result = (T)(object)context.ParseValueLiteral(null); + result = (T)(object)context.ParseValueLiteral(false); else if (typeof(T) == typeof(GraphQLVariable)) result = (T)(object)context.ParseVariable(); else if (typeof(T) == typeof(GraphQLArgument)) diff --git a/src/GraphQLParser/ParserContext.Parse.cs b/src/GraphQLParser/ParserContext.Parse.cs index c036b4ae..eba642e8 100644 --- a/src/GraphQLParser/ParserContext.Parse.cs +++ b/src/GraphQLParser/ParserContext.Parse.cs @@ -819,7 +819,7 @@ private GraphQLInterfaceTypeExtension ParseInterfaceTypeExtension(int start, Lis } // http://spec.graphql.org/October2021/#ListValue - private GraphQLValue ParseListValue(bool? isConstant) + private GraphQLValue ParseListValue(bool isConstant) { IncreaseDepth(); @@ -828,12 +828,11 @@ private GraphQLValue ParseListValue(bool? isConstant) // the compiler caches these delegates in the generated code ParseCallback constant = (ref ParserContext context) => context.ParseValueLiteral(true); ParseCallback value = (ref ParserContext context) => context.ParseValueLiteral(false); - ParseCallback notMatter = (ref ParserContext context) => context.ParseValueLiteral(null); var val = NodeHelper.CreateGraphQLListValue(_ignoreOptions); val.Comments = GetComments(); - val.Values = ZeroOrMore(TokenKind.BRACKET_L, isConstant.HasValue ? (isConstant.Value ? constant : value) : notMatter, TokenKind.BRACKET_R); + val.Values = ZeroOrMore(TokenKind.BRACKET_L, isConstant ? constant : value, TokenKind.BRACKET_R); val.Location = GetLocation(start); DecreaseDepth(); @@ -940,7 +939,7 @@ private GraphQLValue ParseNameValue() } // http://spec.graphql.org/October2021/#ObjectValue - private GraphQLValue ParseObjectValue(bool? isConstant) + private GraphQLValue ParseObjectValue(bool isConstant) { IncreaseDepth(); @@ -949,12 +948,11 @@ private GraphQLValue ParseObjectValue(bool? isConstant) // the compiler caches these delegates in the generated code ParseCallback constant = (ref ParserContext context) => context.ParseObjectField(true); ParseCallback value = (ref ParserContext context) => context.ParseObjectField(false); - ParseCallback notMatter = (ref ParserContext context) => context.ParseObjectField(null); var val = NodeHelper.CreateGraphQLObjectValue(_ignoreOptions); val.Comments = GetComments(); - val.Fields = ZeroOrMore(TokenKind.BRACE_L, isConstant.HasValue ? (isConstant.Value ? constant : value) : notMatter, TokenKind.BRACE_R); + val.Fields = ZeroOrMore(TokenKind.BRACE_L, isConstant ? constant : value, TokenKind.BRACE_R); val.Location = GetLocation(start); DecreaseDepth(); @@ -979,7 +977,7 @@ private GraphQLValue ParseNullValue() } // http://spec.graphql.org/October2021/#ObjectField - private GraphQLObjectField ParseObjectField(bool? isConstant) + private GraphQLObjectField ParseObjectField(bool isConstant) { IncreaseDepth(); @@ -1420,7 +1418,7 @@ private GraphQLUnionTypeExtension ParseUnionTypeExtension(int start, List ParseFloatValue(), TokenKind.STRING => ParseStringValue(), TokenKind.NAME => ParseNameValue(), - TokenKind.DOLLAR when isConstant != true => ParseVariable(), + TokenKind.DOLLAR when !isConstant => ParseVariable(), _ => (GraphQLValue)Throw_Unexpected_Token() }; }