Skip to content

Commit a983d35

Browse files
committed
Add ability to define class name in query
updated c# template with base class/interface support templat can now be configued from json
1 parent d4d623b commit a983d35

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1813
-744
lines changed

Tocsoft.GraphQLCodeGen.Cli/AstPrinter.cs

Lines changed: 517 additions & 0 deletions
Large diffs are not rendered by default.

Tocsoft.GraphQLCodeGen.Cli/CodeGenerator.cs

Lines changed: 2 additions & 498 deletions
Large diffs are not rendered by default.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System.Collections.Generic;
2+
3+
namespace Tocsoft.GraphQLCodeGen
4+
{
5+
public class CodeGeneratorSettings
6+
{
7+
public string Namespace { get; set; }
8+
public string ClassName { get; set; }
9+
public string OutputPath { get; set; }
10+
public string Format { get; set; }
11+
public string TypeNameDirective { get; set; }
12+
public IEnumerable<NamedSource> SourceFiles { get; set; }
13+
14+
public IEnumerable<string> Templates { get; set; }
15+
public IDictionary<string, string> TemplateSettings { get; internal set; }
16+
internal SchemaSource Schema { get; set; }
17+
}
18+
}
Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
using Newtonsoft.Json;
2+
using Newtonsoft.Json.Linq;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.IO;
6+
using System.Linq;
7+
using System.Reflection;
8+
using System.Text.RegularExpressions;
9+
using Tocsoft.GraphQLCodeGen.Cli;
10+
11+
namespace Tocsoft.GraphQLCodeGen
12+
{
13+
internal class CodeGeneratorSettingsLoader
14+
{
15+
public CodeGeneratorSettingsLoader(ILogger logger)
16+
{
17+
this.logger = logger;
18+
}
19+
20+
private List<string> DefaultTemplates(string outputPath)
21+
{
22+
string type = Path.GetExtension(outputPath).Trim('.').ToLower();
23+
TypeInfo info = typeof(CodeGeneratorSettings).GetTypeInfo();
24+
string templateSet = info.Namespace + ".Templates." + type + ".";
25+
List<string> templateFiles = new List<string>();
26+
IEnumerable<string> templates = typeof(CodeGeneratorSettings).GetTypeInfo().Assembly.GetManifestResourceNames().Where(x => x.StartsWith(templateSet, StringComparison.OrdinalIgnoreCase));
27+
templateFiles.AddRange(templates);
28+
29+
return templateFiles;
30+
}
31+
32+
public IEnumerable<CodeGeneratorSettings> GenerateSettings(CodeGeneratorSettingsLoaderDefaults settings, IEnumerable<string> paths)
33+
{
34+
var root = Directory.GetCurrentDirectory();
35+
36+
// we need to multi pass the source files looking for items to load
37+
var toProcess = new Queue<string>(paths.SelectMany(x => GlobExpander.FindFiles(root, x)));
38+
List<SimpleSourceFile> sourceFiles = new List<SimpleSourceFile>();
39+
List<string> processedPaths = new List<string>();
40+
while (toProcess.Any())
41+
{
42+
var path = toProcess.Dequeue();
43+
processedPaths.Add(path);
44+
var loaded = Load(path, settings);
45+
var newPaths = loaded.Includes.Where(x => !processedPaths.Contains(x));
46+
foreach (var p in newPaths)
47+
{
48+
toProcess.Enqueue(p);
49+
}
50+
sourceFiles.Add(loaded);
51+
52+
}
53+
54+
var grouped = sourceFiles.GroupBy(x => new
55+
{
56+
hash = x.SettingsHash()
57+
}).ToList();
58+
59+
60+
return grouped.Select(x =>
61+
{
62+
var first = x.First();
63+
64+
var nspc = "";
65+
var cn = first.ClassName;
66+
var idx = first.ClassName.LastIndexOf('.');
67+
if (idx > 0)
68+
{
69+
cn = first.ClassName.Substring(idx);
70+
nspc = first.ClassName.Substring(0, idx);
71+
}
72+
cn = cn.Trim('.');
73+
nspc = nspc.Trim('.');
74+
var templates = DefaultTemplates(first.OutputPath);
75+
templates.AddRange(x.First().Templates);
76+
return new CodeGeneratorSettings
77+
{
78+
ClassName = cn,
79+
Namespace = nspc,
80+
OutputPath = first.OutputPath,
81+
TypeNameDirective = first.TypeNameDirective,
82+
SourceFiles = x.Select(p => new NamedSource
83+
{
84+
Body = p.Body,
85+
Path = p.Path
86+
}).ToList(),
87+
Schema = x.First().SchemaSource,
88+
Templates = templates,
89+
TemplateSettings = first.TemplateSettings
90+
};
91+
}).ToList();
92+
}
93+
94+
internal class SimpleSettings
95+
{
96+
public string Namespace { get; set; }
97+
98+
public string Class { get; set; }
99+
100+
public string Output { get; set; }
101+
102+
public string Format { get; set; }
103+
104+
public string TypeNameDirective { get; set; }
105+
106+
[JsonConverter(typeof(SchemaSourceJsonConverter))]
107+
public SchemaSource Schema { get; set; }
108+
109+
[JsonConverter(typeof(SingleOrArrayConverter<string>))]
110+
public List<string> Template { get; set; }
111+
112+
public Dictionary<string, string> TemplateSettings { get; set; }
113+
114+
[JsonConverter(typeof(SingleOrArrayConverter<string>))]
115+
public List<string> Include { get; set; }
116+
117+
public bool Root { get; set; } = false;
118+
}
119+
120+
public static string GenerateFullPath(string rootFolder, string path)
121+
{
122+
if (!Path.IsPathRooted(path))
123+
{
124+
path = Path.Combine(rootFolder, path);
125+
126+
}
127+
return Path.GetFullPath(path);
128+
}
129+
130+
private void LoadSettingsTree(SimpleSourceFile file)
131+
{
132+
Stack<SimpleSettings> settingsList = new Stack<SimpleSettings>();
133+
var directory = Path.GetDirectoryName(file.Path);
134+
while (directory != null)
135+
{
136+
var settingsFile = Path.Combine(directory, "gqlsettings.json");
137+
if (File.Exists(settingsFile))
138+
{
139+
if (ExpandSettings(settingsFile, file))
140+
{
141+
return;
142+
}
143+
}
144+
145+
directory = Path.GetDirectoryName(directory);
146+
}
147+
}
148+
149+
static readonly Regex regex = new Regex(@"^\s*#!\s*([a-zA-Z.]+)\s*:\s*(\"".*\""|[^ ]+?)(?:\s|$)", RegexOptions.Multiline | RegexOptions.Compiled);
150+
private readonly ILogger logger;
151+
152+
private SimpleSourceFile Load(string path, CodeGeneratorSettingsLoaderDefaults settings)
153+
{
154+
// path must be a real full path by here
155+
156+
var gql = File.ReadAllText(path);
157+
158+
// lets discover / cache all settings files from this point up the stack and root them out
159+
160+
var file = new SimpleSourceFile()
161+
{
162+
Path = path,
163+
Body = gql
164+
};
165+
var root = Path.GetDirectoryName(path);
166+
167+
var matches = regex.Matches(gql);
168+
var pairs = matches.OfType<Match>().Select(m => (key: m.Groups[1].Value.ToLower(), val: m.Groups[2].Value)).ToList();
169+
170+
foreach (var m in pairs)
171+
{
172+
// process them in order to later directives overwrite previous ones
173+
switch (m.key)
174+
{
175+
case "schema":
176+
file.SchemaSource = file.SchemaSource ?? new SchemaSource();
177+
file.SchemaSource.Location = GenerateFullPath(root, m.val);
178+
break;
179+
case "schema.querytype":
180+
file.SchemaSource = file.SchemaSource ?? new SchemaSource();
181+
file.SchemaSource.QueryType.Add(m.val);
182+
break;
183+
case "schema.mutationtype":
184+
file.SchemaSource = file.SchemaSource ?? new SchemaSource();
185+
file.SchemaSource.MutationType.Add(m.val);
186+
break;
187+
case "output":
188+
file.OutputPath = GenerateFullPath(root, m.val);
189+
break;
190+
case "class":
191+
file.ClassName = m.val;
192+
break;
193+
case "typedirective":
194+
file.TypeNameDirective = m.val;
195+
break;
196+
case "format":
197+
file.Format = m.val;
198+
break;
199+
case "settings":
200+
ExpandSettings(GenerateFullPath(root, m.val), file);
201+
break;
202+
case "template":
203+
var templateFiles = GlobExpander.FindFiles(root, m.val);
204+
file.Templates.AddRange(templateFiles);
205+
break;
206+
case "include":
207+
var includeFiles = GlobExpander.FindFiles(root, m.val);
208+
file.Includes.AddRange(includeFiles);
209+
break;
210+
default:
211+
break;
212+
}
213+
}
214+
215+
LoadSettingsTree(file);
216+
217+
218+
if (string.IsNullOrWhiteSpace(file.TypeNameDirective))
219+
{
220+
file.TypeNameDirective = "__codeGenTypeName";
221+
}
222+
223+
if (string.IsNullOrWhiteSpace(file.Format))
224+
{
225+
if (!string.IsNullOrWhiteSpace(file.OutputPath))
226+
{
227+
file.Format = Path.GetExtension(file.OutputPath).Trim('.').ToLower();
228+
}
229+
230+
if (string.IsNullOrWhiteSpace(file.Format))
231+
{
232+
file.Format = settings.Format;
233+
}
234+
}
235+
236+
if (string.IsNullOrWhiteSpace(file.OutputPath))
237+
{
238+
if (string.IsNullOrWhiteSpace(settings.OutputPath))
239+
{
240+
file.OutputPath = file.Path;
241+
}
242+
else
243+
{
244+
file.OutputPath = settings.OutputPath;
245+
}
246+
}
247+
248+
if (!Path.GetExtension(file.OutputPath).Trim('.').Equals(file.Format, StringComparison.OrdinalIgnoreCase))
249+
{
250+
file.OutputPath += "." + file.Format;
251+
}
252+
253+
if (string.IsNullOrWhiteSpace(file.ClassName))
254+
{
255+
file.ClassName = Path.GetFileNameWithoutExtension(file.Path);
256+
}
257+
258+
settings.FixFile?.Invoke(file);
259+
file.OutputPath = file.OutputPath.Replace("{classname}", file.ClassName);
260+
261+
return file;
262+
}
263+
264+
private bool ExpandSettings(string path, SimpleSourceFile file)
265+
{
266+
var root = Path.GetDirectoryName(path);
267+
var settingsJson = File.ReadAllText(path);
268+
269+
var settings = Newtonsoft.Json.JsonConvert.DeserializeObject<SimpleSettings>(settingsJson);
270+
if (!string.IsNullOrWhiteSpace(settings.Class) && string.IsNullOrWhiteSpace(file.ClassName))
271+
{
272+
file.ClassName = settings.Class;
273+
}
274+
if (!string.IsNullOrWhiteSpace(settings.TypeNameDirective) && string.IsNullOrWhiteSpace(file.TypeNameDirective))
275+
{
276+
file.TypeNameDirective = settings.TypeNameDirective;
277+
}
278+
if (!string.IsNullOrWhiteSpace(settings.Output) && string.IsNullOrWhiteSpace(file.OutputPath))
279+
{
280+
file.OutputPath = GenerateFullPath(root, settings.Output);
281+
}
282+
if (!string.IsNullOrWhiteSpace(settings.Format) && string.IsNullOrWhiteSpace(file.Format))
283+
{
284+
file.Format = settings.Format;
285+
}
286+
if (settings.Template != null)
287+
{
288+
foreach (var t in settings.Template)
289+
{
290+
var templateFiles = GlobExpander.FindFiles(root, t);
291+
file.Templates.AddRange(templateFiles);
292+
}
293+
}
294+
295+
if (settings.TemplateSettings != null)
296+
{
297+
foreach (var t in settings.TemplateSettings)
298+
{
299+
if(!file.TemplateSettings.TryGetValue(t.Key, out _))
300+
{
301+
// set if doesn't exist
302+
file.TemplateSettings[t.Key] = t.Value;
303+
}
304+
}
305+
}
306+
307+
if (settings.Include != null)
308+
{
309+
foreach (var t in settings.Include)
310+
{
311+
var files = GlobExpander.FindFiles(root, t);
312+
file.Includes.AddRange(files);
313+
}
314+
}
315+
316+
if (string.IsNullOrWhiteSpace(file.SchemaSource?.Location))
317+
{
318+
if (settings.Schema != null && !string.IsNullOrWhiteSpace(settings.Schema.Location))
319+
{
320+
file.SchemaSource = settings.Schema;
321+
if (file.SchemaSource.SchemaType() != SchemaSource.SchemaTypes.Http)
322+
{
323+
// we are not and url based location then it must be a path
324+
file.SchemaSource.Location = GlobExpander.FindFile(root, file.SchemaSource.Location);
325+
}
326+
}
327+
}
328+
329+
return settings.Root;
330+
}
331+
}
332+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
3+
namespace Tocsoft.GraphQLCodeGen
4+
{
5+
internal class CodeGeneratorSettingsLoaderDefaults
6+
{
7+
public string Format { get; set; }
8+
9+
public string OutputPath { get; set; }
10+
11+
public Action<SimpleSourceFile> FixFile { get; set; }
12+
}
13+
}

0 commit comments

Comments
 (0)