Skip to content

Commit 69fe0e7

Browse files
committed
comment based type name generation
1 parent d0f3952 commit 69fe0e7

File tree

5 files changed

+108
-7
lines changed

5 files changed

+108
-7
lines changed

Tocsoft.GraphQLCodeGen.Cli/IntrospectedSchemeParser.cs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Collections.Generic;
44
using System.Linq;
55
using System.Text;
6+
using System.IO;
67

78
namespace Tocsoft.GraphQLCodeGen
89
{
@@ -81,8 +82,48 @@ public class LocatedNamedSource
8182
public string Path { get; set; }
8283
public string Body { get; set; }
8384
public int LineStartAt { get; internal set; }
84-
}
8585

86+
private string[] lines;
87+
88+
public string Line(int line)
89+
{
90+
line = line - 1;
91+
if (lines == null)
92+
{
93+
94+
lines = GetLines(Body).ToArray();
95+
}
96+
97+
if (line < 0)
98+
{
99+
return null;
100+
}
101+
102+
if (line >= lines.Length)
103+
{
104+
105+
return null;
106+
}
107+
108+
return lines[line];
109+
}
110+
111+
private static IEnumerable<string> GetLines(string str, bool removeEmptyLines = false)
112+
{
113+
using (var sr = new StringReader(str))
114+
{
115+
string line;
116+
while ((line = sr.ReadLine()) != null)
117+
{
118+
if (removeEmptyLines && String.IsNullOrWhiteSpace(line))
119+
{
120+
continue;
121+
}
122+
yield return line;
123+
}
124+
}
125+
}
126+
}
86127
}
87128

88129
public class NamedSource

Tocsoft.GraphQLCodeGen.Cli/ObjectModel/GraphQLDocument.cs

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public GraphQLDocument(DocumentNode ast, IEnumerable<LocatedNamedSource> queryPa
6868
this.settings = settings;
6969
List<object> items = ast.Definitions.Select(this.Visit).ToList();
7070
this.Operations = items.OfType<Operation>().ToList();
71-
this.types = items.OfType<IGraphQLType>().GroupBy(x=>x.Name).Select(x=>x.First()).ToList();
71+
this.types = items.OfType<IGraphQLType>().GroupBy(x => x.Name).Select(x => x.First()).ToList();
7272
this.astPrinter = new AstPrinter(settings.TypeNameDirective);
7373
foreach (IGraphQLInitter i in items.OfType<IGraphQLInitter>().Where(x => !(x is Operation)))
7474
{
@@ -80,9 +80,45 @@ public GraphQLDocument(DocumentNode ast, IEnumerable<LocatedNamedSource> queryPa
8080
}
8181
}
8282

83-
internal IValueNode<string> ResolveSpecifiedTypeName(IEnumerable<DirectiveNode> directives)
83+
internal IValueNode<string> ResolveSpecifiedTypeName(FieldNode field)
8484
{
85-
var directive = directives.SingleOrDefault(x => x.Name.Value == this.settings.TypeNameDirective);
85+
(LocatedNamedSource part, int offsetStart, int length) = ResolveNode(field.Location);
86+
87+
var allTextBeforeError = part.Body.Substring(0, offsetStart);
88+
var lines = allTextBeforeError.Split('\n');
89+
var line = lines.Count();
90+
91+
for (var i = line - 1; i > 0; i--)
92+
{
93+
// walk back looking to comment lines with a type name flag on it
94+
var lineText = part.Line(i);
95+
if (lineText == null)
96+
{
97+
break;
98+
}
99+
100+
lineText = lineText.Trim();
101+
if (lineText.StartsWith("#!"))
102+
{
103+
lineText = lineText.Substring(2);
104+
var p = lineText.Trim().Split(':').Select(x => x.Trim()).ToList();
105+
if (p[0].Equals("typename", StringComparison.OrdinalIgnoreCase) && p.Count > 1)
106+
{
107+
return new StringValueNode(p[1]);
108+
}
109+
}
110+
else if (lineText.StartsWith("\""))
111+
{
112+
// skip as this is a description line
113+
}
114+
else if (lineText.Length != 0)
115+
{
116+
// other lines stop looking as we have reached something else
117+
break;
118+
}
119+
}
120+
121+
var directive = field.Directives.SingleOrDefault(x => x.Name.Value == this.settings.TypeNameDirective);
86122
var value = directive?.Arguments.SingleOrDefault(x => x.Name.Value == "type")?.Value;
87123
var scalar = value as IValueNode<string>;
88124
return scalar;
@@ -244,12 +280,12 @@ private void UnPackType(ITypeNode type, ValueTypeReference target)
244280
throw;
245281
}
246282
}
247-
283+
248284
private object Visit(ISyntaxNode node)
249285
{
250286
switch (node)
251287
{
252-
288+
253289
case OperationDefinitionNode op:
254290
return new Operation(op);
255291
case InterfaceTypeDefinitionNode op:

Tocsoft.GraphQLCodeGen.Cli/ObjectModel/Selections/FieldSelection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ internal bool Resolve(GraphQLDocument doc, IGraphQLFieldCollection rootType)
6060
{
6161
IGraphQLType root = this.Type.Type.Type as IGraphQLType;
6262

63-
var specifiedTypeName = doc.ResolveSpecifiedTypeName(this.op.Directives);
63+
var specifiedTypeName = doc.ResolveSpecifiedTypeName(this.op);
6464
this.Selection.Resolve(doc, root, specifiedTypeName);
6565
}
6666

Tocsoft.GraphQLCodeGen.Tests/ClientOnlyDirectives.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,21 @@ public async Task TypeDirectiveCanChangeExportedTypeName()
5858
Assert.Single(generator.Model.Types.Select(x => x.Name), "TestResultABCD");
5959
}
6060

61+
[Fact]
62+
public async Task CommentCanChangeExportedTypeName()
63+
{
64+
var settings = settingsLoader.GenerateSettings(new CodeGeneratorSettingsLoaderDefaults(), new[] { "./Files/ClientOnlyDirectives/QueryComment.gql" });
65+
66+
CodeGenerator generator = new CodeGenerator(logger, settings.Single());
67+
68+
await generator.LoadSource();
69+
generator.Parse();
70+
71+
Assert.Empty(generator.Document.Errors);
72+
73+
Assert.Single(generator.Model.Types.Select(x => x.Name), "TestResultABCD");
74+
}
75+
6176
[Fact]
6277
public async Task ShouldRecieveErrorAboutTwoClassesWithSameName()
6378
{
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
query q{
2+
3+
#! typename: TestResultABCD
4+
test(id: "safsa")
5+
{
6+
nullable,
7+
nonnullable
8+
}
9+
}

0 commit comments

Comments
 (0)