Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AstVisitor rework #149

Merged
merged 20 commits into from
Jan 2, 2022
Merged

AstVisitor rework #149

merged 20 commits into from
Jan 2, 2022

Conversation

sungam3r
Copy link
Member

fixes #11 , supersedes #20

Visitors API was completely rewritten, optimized, tested.

@sungam3r sungam3r requested a review from Shane32 November 13, 2021 00:19
@github-actions github-actions bot added the test Pull request that adds new or changes existing tests label Nov 13, 2021
@sungam3r sungam3r mentioned this pull request Nov 13, 2021
@Shane32
Copy link
Member

Shane32 commented Nov 13, 2021

Is this all synchronous code? Synchronous code that writes streams should be deprecated and replaced with async code, just like what was done with System.Text.Json. Certainly we should not be writing new synchronous code here in 2021. And even more certainly if we are replacing the visitor api, it should be a new async api.

This is a good candidate for using ValueTask, however, to eliminate allocations when writing to a string builder or other non-async stream. Or for any other non-async needs of the visitor api.

@sungam3r
Copy link
Member Author

TextWriter has no write methods that return ValueTask.

@sungam3r
Copy link
Member Author

Nevermind, I can change all signatures to ValueTask.

@sungam3r sungam3r added BREAKING Breaking changes in either public API or runtime behavior enhancement New feature or request spec compliance The change is intended to solve the problem of inconsistency with the official GraphQL specification labels Nov 13, 2021
@@ -19,7 +19,7 @@
<!-- https://github.com/clairernovotny/DeterministicBuilds -->
<ContinuousIntegrationBuild Condition="'$(GITHUB_ACTIONS)' == 'true'">True</ContinuousIntegrationBuild>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<NoWarn>$(NoWarn);1591</NoWarn> <!--TODO: temporary solution, remove-->
<NoWarn>$(NoWarn);1591;IDE1006</NoWarn> <!--TODO: temporary solution, remove-->
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Async suffix rule

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering why you decided to have the Visit methods not end in Async?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Year or two ago I would do so, yes. I know about all those recommendations and styles. I control several hundred repos at work unifiing code style/design and this have always been one of the permanent questions. My intuition suggests me that if the API is initially designed as (completely) asynchronous, then it makes no sense to append Async everywhere. It only creates additional noise. By the way, I remove that suppression from dir.props, see .editorconfig file.

@github-actions github-actions bot added the code style Pull request that applies code style rules label Nov 13, 2021
@@ -142,7 +143,7 @@ namespace GraphQLParser.AST
public System.Collections.Generic.List<GraphQLParser.AST.GraphQLDirective>? Directives { get; set; }
public override GraphQLParser.AST.ASTNodeKind Kind { get; }
public GraphQLParser.AST.GraphQLSelectionSet? SelectionSet { get; set; }
public GraphQLParser.AST.GraphQLNamedType? TypeCondition { get; set; }
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -1149,6 +1144,7 @@ private GraphQLVariableDefinition ParseVariableDefinition()

def.Type = ParseType();
def.DefaultValue = Skip(TokenKind.EQUALS) ? ParseValueLiteral(true) : null;
def.Directives = ParseDirectives();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VariableDefinition may have directives

Copy link
Member

@Shane32 Shane32 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking great! Here's a few comments, mostly about escaping strings and adding some cancellation token support.

{
await Visit(stringValue.Comment, context);
await context.Writer.WriteAsync('\"');
await Write(context, stringValue.Value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs escaping of various characters; please add test.

Optional: detect if the string is multi-line, and can be formatted as a blockstring without loss of data, and if both are true, print it that way.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and can be formatted as a blockstring without loss of data

Example ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took test data from lexer tests. This is your test with 30 cases. I changed some values. Honestly, work with escape symbols is very tired. I would like to finish with this PR and go on. I could be mistaken somewhere, further use will show. We will add tests. Or you can add additional test cases yourself where you think right.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree to finish the PR and go on. The API will not change if we improve these methods in a later PR, either to fix an issue or enhance performance.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm OK to wait 1-2-3 days for your review. At least until I start a new branch working on type extensions. I am 80% sure that I have errors in formatting/edge cases.

src/GraphQLParser/Visitors/SDLWriter.cs Outdated Show resolved Hide resolved
}

/// <inheritdoc/>
public override async ValueTask VisitDescription(GraphQLDescription description, TContext context)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not all strings can be written in the blockstring format. For example, a string that starts with a newline. This method should ideally check to be sure the input string can be formatted as a blockstring without loss of information, and if not, be formatted as a string.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and if not, be formatted as a string.

One-line string? Or are you talking about change description node into comment ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #149 (comment)

Please show an example here or add a test case yourself. I'm a little confused with all this escaping stuff.

src/GraphQLParser/Visitors/IWriteContext.cs Outdated Show resolved Hide resolved
src/GraphQLParser/Visitors/IWriteContext.cs Show resolved Hide resolved
src/GraphQLParser/Visitors/SDLWriter.cs Outdated Show resolved Hide resolved
src/GraphQLParser/Visitors/StructureWriter.cs Outdated Show resolved Hide resolved
Comment on lines 90 to 91
case '\r':
break;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: with this logic, description strings encoded with CRLF will result in strings being encoded as LF after being decoded. I suggest adding a comment within the method that this change may take place -- or better yet, encode strings containing CRs as strings instead of blockstrings. Tests should be added either way.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strings instead of blockstrings

I'm still confused about string vs blockstring, can you give an example?

By the way I want to rewrite both methods for comment and description node. Now I added the Slice call to get around the problem:

CS4012	Parameters or locals of type 'ReadOnlySpan<char>' cannot be declared in async methods or async lambda expressions.

In addition, I do not really like this char-by-char transmission. At first I wrote a method that finds the chain of non-\r\n chars and writes those spans into writer, but it was rather complicated so I swiched to char-by-char.

src/GraphQLParser/Visitors/SDLWriter.cs Outdated Show resolved Hide resolved
@Shane32
Copy link
Member

Shane32 commented Nov 13, 2021

By the way, should we be adding .ConfigureAwait(false) everywhere?

https://devblogs.microsoft.com/dotnet/configureawait-faq/

@sungam3r
Copy link
Member Author

By the way, should we be adding .ConfigureAwait(false) everywhere?

Of course.

@sungam3r
Copy link
Member Author

@Shane32 I have left to solve the issues with strings/blockstrings encoding. I'll do it tomorrow or in the coming days.

@sungam3r
Copy link
Member Author

What is done for now:

  1. General design for visitors, naming
  2. Full-async (for netstandard2.1 100%)
  3. Cancellation support
  4. Some bugs were fixed, some new nodes/properties were added

@sungam3r
Copy link
Member Author

@Shane32 Waiting for examples.

@github-actions github-actions bot added the documentation An issue or pull request regarding documentation improvements label Nov 14, 2021
Copy link
Member

@Shane32 Shane32 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only major issue I see is that string values are not escaped. You already wrote code within VisitDescription to encode strings; just copy or reuse the code block and it should be fine. I can do a detailed review of the encoding for strings and blockstrings at a later time and add another PR if I see any other suggestions. Ok?

src/GraphQLParser/Visitors/SDLWriter.cs Outdated Show resolved Hide resolved
@sungam3r
Copy link
Member Author

ping @Shane32 , any suggestions/comments/test cases?

@Shane32
Copy link
Member

Shane32 commented Nov 19, 2021

Not at this time.

@codecov-commenter
Copy link

Codecov Report

Merging #149 (d310867) into master (ebb76f3) will decrease coverage by 2.30%.
The diff coverage is 81.21%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #149      +/-   ##
==========================================
- Coverage   91.91%   89.61%   -2.31%     
==========================================
  Files          50       55       +5     
  Lines        2498     3263     +765     
  Branches      278      333      +55     
==========================================
+ Hits         2296     2924     +628     
- Misses        180      300     +120     
- Partials       22       39      +17     
Impacted Files Coverage Δ
src/GraphQLParser/AST/GraphQLArgument.cs 72.72% <ø> (+9.09%) ⬆️
src/GraphQLParser/AST/GraphQLComment.cs 50.00% <ø> (ø)
src/GraphQLParser/AST/GraphQLDescription.cs 50.00% <ø> (ø)
src/GraphQLParser/AST/GraphQLFragmentDefinition.cs 70.00% <ø> (+10.00%) ⬆️
src/GraphQLParser/AST/GraphQLListType.cs 63.63% <ø> (ø)
src/GraphQLParser/AST/GraphQLListValue.cs 66.66% <0.00%> (-17.34%) ⬇️
src/GraphQLParser/AST/GraphQLName.cs 100.00% <ø> (+20.00%) ⬆️
src/GraphQLParser/AST/GraphQLNamedType.cs 63.63% <ø> (-9.10%) ⬇️
src/GraphQLParser/AST/GraphQLNonNullType.cs 63.63% <ø> (ø)
src/GraphQLParser/AST/GraphQLObjectField.cs 63.63% <ø> (+9.09%) ⬆️
... and 40 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ebb76f3...d310867. Read the comment docs.

@sungam3r sungam3r added this to the 8.0 milestone Jan 2, 2022
@sungam3r sungam3r self-assigned this Jan 2, 2022
@sungam3r sungam3r merged commit 4a55a62 into master Jan 2, 2022
@sungam3r sungam3r deleted the visitor branch January 2, 2022 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BREAKING Breaking changes in either public API or runtime behavior code style Pull request that applies code style rules documentation An issue or pull request regarding documentation improvements enhancement New feature or request spec compliance The change is intended to solve the problem of inconsistency with the official GraphQL specification test Pull request that adds new or changes existing tests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Is there a way to turn the AST back into a graphql query string?
3 participants