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

Added FieldSelectionMap parser #7211

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .build/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ static class Helpers
Path.Combine("HotChocolate", "Raven"),
Path.Combine("HotChocolate", "Skimmed"),
Path.Combine("HotChocolate", "Fusion"),
Path.Combine("HotChocolate", "Fusion-vnext"),
Path.Combine("HotChocolate", "Spatial"),
Path.Combine("StrawberryShake", "Client"),
Path.Combine("StrawberryShake", "CodeGeneration"),
Expand Down
1 change: 1 addition & 0 deletions dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ Unsubscriber
Upsert
upvote
URQL
vnext
vsix
VXNlcjox
websockets
Expand Down
3 changes: 3 additions & 0 deletions src/HotChocolate/Fusion-vnext/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"dotnet.defaultSolution": "HotChocolate.Fusion.sln"
}
24 changes: 24 additions & 0 deletions src/HotChocolate/Fusion-vnext/.vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "shell",
"args": [
"build",
// Ask dotnet build to generate full paths for file names.
"/property:GenerateFullPaths=true",
// Do not generate summary otherwise it leads to duplicate errors in Problems panel
"/consoleloggerparameters:NoSummary"
],
"group": "build",
"presentation": {
"reveal": "silent"
},
"problemMatcher": "$msCompile"
}
]
}
14 changes: 14 additions & 0 deletions src/HotChocolate/Fusion-vnext/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project>
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)..\'))" />

<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<IsTrimmable>true</IsTrimmable>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
<IsAotCompatible>true</IsAotCompatible>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>

</Project>
36 changes: 36 additions & 0 deletions src/HotChocolate/Fusion-vnext/HotChocolate.Fusion.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B351C588-A3DE-4123-B095-B30579D7B2DE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotChocolate.Fusion.Language", "src\Language\HotChocolate.Fusion.Language.csproj", "{EB04E0CC-632B-4654-9A0C-2280E4137C2B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{DCDF83DF-1767-43FE-929D-5E0DFD2CD8F0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotChocolate.Fusion.Language.Tests", "test\Language.Tests\HotChocolate.Fusion.Language.Tests.csproj", "{115FD54C-219F-4D3E-9D35-E58C648A6447}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EB04E0CC-632B-4654-9A0C-2280E4137C2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB04E0CC-632B-4654-9A0C-2280E4137C2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB04E0CC-632B-4654-9A0C-2280E4137C2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB04E0CC-632B-4654-9A0C-2280E4137C2B}.Release|Any CPU.Build.0 = Release|Any CPU
{115FD54C-219F-4D3E-9D35-E58C648A6447}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{115FD54C-219F-4D3E-9D35-E58C648A6447}.Debug|Any CPU.Build.0 = Debug|Any CPU
{115FD54C-219F-4D3E-9D35-E58C648A6447}.Release|Any CPU.ActiveCfg = Release|Any CPU
{115FD54C-219F-4D3E-9D35-E58C648A6447}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{EB04E0CC-632B-4654-9A0C-2280E4137C2B} = {B351C588-A3DE-4123-B095-B30579D7B2DE}
{115FD54C-219F-4D3E-9D35-E58C648A6447} = {DCDF83DF-1767-43FE-929D-5E0DFD2CD8F0}
EndGlobalSection
EndGlobal
10 changes: 10 additions & 0 deletions src/HotChocolate/Fusion-vnext/src/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project>
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)..\'))" />
<Import Project="$([MSBuild]::GetPathOfFileAbove('Nullable.props', '$(MSBuildThisFileDirectory)..\'))" />

<PropertyGroup>
<NoWarn>$(NoWarn);CA1812</NoWarn>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace HotChocolate.Fusion;

internal static class CharConstants
{
public const char Colon = ':';
public const char Comma = ',';
public const char HorizontalTab = '\t';
public const char LeftAngleBracket = '<';
public const char LeftBrace = '{';
public const char LineFeed = '\n';
public const char Period = '.';
public const char Pipe = '|';
public const char Return = '\r';
public const char RightAngleBracket = '>';
public const char RightBrace = '}';
public const char Space = ' ';
public const char Underscore = '_';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace HotChocolate.Fusion;

[Serializable]
public sealed class SyntaxException : Exception
{
internal SyntaxException(FieldSelectionMapReader reader, string message) : base(message)
{
Position = reader.Position;
Line = reader.Line;
Column = reader.Column;
}

internal SyntaxException(FieldSelectionMapReader reader, string message, params object[] args)
: this(reader, string.Format(message, args))
{
}

public int Position { get; }

public int Line { get; }

public int Column { get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System.Runtime.CompilerServices;
using static HotChocolate.Fusion.CharConstants;

namespace HotChocolate.Fusion;

internal static class CharExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsLetterOrDigitOrUnderscore(this char c)
{
return char.IsAsciiLetter(c) || char.IsAsciiDigit(c) || c == Underscore;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsLetterOrUnderscore(this char c)
{
return char.IsAsciiLetter(c) || c == Underscore;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsPunctuator(this char c)
{
switch (c)
{
case Colon:
case LeftAngleBracket:
case LeftBrace:
case Period:
case Pipe:
case RightAngleBracket:
case RightBrace:
return true;

default:
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<AssemblyName>HotChocolate.Fusion.Language</AssemblyName>
<RootNamespace>HotChocolate.Fusion</RootNamespace>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<InternalsVisibleTo Include="HotChocolate.Fusion.Language.Tests" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="8.0.0" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Update="Properties\FusionLanguageResources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>FusionLanguageResources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>

<ItemGroup>
<Compile Update="Properties\FusionLanguageResources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>FusionLanguageResources.resx</DependentUpon>
</Compile>
</ItemGroup>

</Project>
10 changes: 10 additions & 0 deletions src/HotChocolate/Fusion-vnext/src/Language/Location.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace HotChocolate.Fusion;

/// <summary>
/// The location of a syntax node.
/// </summary>
/// <param name="Start">The start position of the syntax node.</param>
/// <param name="End">The end position of the syntax node.</param>
/// <param name="Line">The line in which the syntax node is located.</param>
/// <param name="Column">The column in which the syntax node is located.</param>
internal sealed record Location(int Start, int End, int Line, int Column);
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
namespace HotChocolate.Fusion;

/// <summary>
/// Represents a non-terminal node in the <c>FieldSelectionMap</c> syntax tree.
/// </summary>
internal interface IFieldSelectionMapSyntaxNode
{
/// <summary>
/// Returns the <see cref="FieldSelectionMapSyntaxKind"/> of the node.
/// </summary>
FieldSelectionMapSyntaxKind Kind { get; }

/// <summary>
/// Gets the <see cref="Location"/> of this node in the parsed source text, when provided by the
/// parser.
/// </summary>
Location? Location { get; }

/// <summary>
/// Gets the children of this node.
/// </summary>
/// <returns>
/// Returns the children of this node.
/// </returns>
IEnumerable<IFieldSelectionMapSyntaxNode> GetNodes();

/// <summary>
/// Returns the syntax representation of this <see cref="IFieldSelectionMapSyntaxNode"/>.
/// </summary>
/// <returns>
/// Returns the syntax representation of this <see cref="IFieldSelectionMapSyntaxNode"/>.
/// </returns>
string ToString();

/// <summary>
/// Returns the syntax representation of this <see cref="IFieldSelectionMapSyntaxNode"/>.
/// </summary>
/// <param name="indented">
/// A value that indicates whether the output should be formatted, which includes indenting
/// nested tokens and adding new lines.
/// </param>
/// <returns>
/// Returns the syntax representation of this <see cref="IFieldSelectionMapSyntaxNode"/>.
/// </returns>
string ToString(bool indented);

/// <summary>
/// Returns the syntax representation of this <see cref="IFieldSelectionMapSyntaxNode"/>.
/// </summary>
/// <param name="options">
/// Specifies the options used when writing this syntax node.
/// </param>
/// <returns>
/// Returns the syntax representation of this <see cref="IFieldSelectionMapSyntaxNode"/>.
/// </returns>
string ToString(StringSyntaxWriterOptions options);
}
33 changes: 33 additions & 0 deletions src/HotChocolate/Fusion-vnext/src/Language/Nodes/NameNode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
namespace HotChocolate.Fusion;

/// <summary>
/// Equivalent to the <c>Name</c> defined in the GraphQL specification.
/// </summary>
internal sealed class NameNode : IFieldSelectionMapSyntaxNode
{
public NameNode(string value)
{
ArgumentException.ThrowIfNullOrEmpty(value);

Value = value;
}

public NameNode(Location? location, string value) : this(value)
{
Location = location;
}

public FieldSelectionMapSyntaxKind Kind => FieldSelectionMapSyntaxKind.Name;

public Location? Location { get; }

public string Value { get; }

public IEnumerable<IFieldSelectionMapSyntaxNode> GetNodes() => [];

public override string ToString() => this.Print();

public string ToString(bool indented) => this.Print(indented);

public string ToString(StringSyntaxWriterOptions options) => this.Print(true, options);
}
48 changes: 48 additions & 0 deletions src/HotChocolate/Fusion-vnext/src/Language/Nodes/PathNode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
namespace HotChocolate.Fusion;

/// <summary>
/// The <c>Path</c> literal is a string used to select a single output value from the return type by
/// specifying a path to that value. This path is defined as a sequence of field names, each
/// separated by a period (<c>.</c>) to create segments.
/// </summary>
internal sealed class PathNode(NameNode fieldName, NameNode? typeName = null, PathNode? path = null)
: IFieldSelectionMapSyntaxNode
{
public PathNode(Location? location, NameNode fieldName, NameNode? typeName, PathNode? path)
: this(fieldName, typeName, path)
{
Location = location;
}

public FieldSelectionMapSyntaxKind Kind => FieldSelectionMapSyntaxKind.Path;

public Location? Location { get; }

public NameNode FieldName { get; } = fieldName
?? throw new ArgumentNullException(nameof(fieldName));

public NameNode? TypeName { get; } = typeName;

public PathNode? Path { get; } = path;

public IEnumerable<IFieldSelectionMapSyntaxNode> GetNodes()
{
yield return FieldName;

if (TypeName is not null)
{
yield return TypeName;
}

if (Path is not null)
{
yield return Path;
}
}

public override string ToString() => this.Print();

public string ToString(bool indented) => this.Print(indented);

public string ToString(StringSyntaxWriterOptions options) => this.Print(true, options);
}
Loading