Skip to content

Commit

Permalink
Supporting custom generators (#65)
Browse files Browse the repository at this point in the history
* Supporting custom generators

* Fixing
  • Loading branch information
Gekctek authored Apr 17, 2023
1 parent 18af528 commit 503386f
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 7 deletions.
1 change: 1 addition & 0 deletions samples/Sample.CLI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@ public static async Task Main()

Console.WriteLine("Press ENTER to exit");
Console.ReadLine();

}
}
52 changes: 52 additions & 0 deletions src/ClientGenerator/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
- [ClientFile](#P-EdjCase-ICP-ClientGenerator-ClientSyntax-ClientFile 'EdjCase.ICP.ClientGenerator.ClientSyntax.ClientFile')
- [Name](#P-EdjCase-ICP-ClientGenerator-ClientSyntax-Name 'EdjCase.ICP.ClientGenerator.ClientSyntax.Name')
- [TypeFiles](#P-EdjCase-ICP-ClientGenerator-ClientSyntax-TypeFiles 'EdjCase.ICP.ClientGenerator.ClientSyntax.TypeFiles')
- [GenerateFileContents()](#M-EdjCase-ICP-ClientGenerator-ClientSyntax-GenerateFileContents 'EdjCase.ICP.ClientGenerator.ClientSyntax.GenerateFileContents')
- [GenerateFileContents(syntax)](#M-EdjCase-ICP-ClientGenerator-ClientSyntax-GenerateFileContents-Microsoft-CodeAnalysis-CSharp-Syntax-CompilationUnitSyntax- 'EdjCase.ICP.ClientGenerator.ClientSyntax.GenerateFileContents(Microsoft.CodeAnalysis.CSharp.Syntax.CompilationUnitSyntax)')
- [Rewrite(rewriter)](#M-EdjCase-ICP-ClientGenerator-ClientSyntax-Rewrite-Microsoft-CodeAnalysis-CSharp-CSharpSyntaxRewriter- 'EdjCase.ICP.ClientGenerator.ClientSyntax.Rewrite(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter)')

<a name='T-EdjCase-ICP-ClientGenerator-ClientCodeGenerator'></a>
## ClientCodeGenerator `type`
Expand Down Expand Up @@ -178,3 +181,52 @@ The name of the client
##### Summary

The syntax of different declared types for the client

<a name='M-EdjCase-ICP-ClientGenerator-ClientSyntax-GenerateFileContents'></a>
### GenerateFileContents() `method`

##### Summary

Converts the file syntax objects into source code string values to use as a file

##### Returns

Client and type source code file contents

##### Parameters

This method has no parameters.

<a name='M-EdjCase-ICP-ClientGenerator-ClientSyntax-GenerateFileContents-Microsoft-CodeAnalysis-CSharp-Syntax-CompilationUnitSyntax-'></a>
### GenerateFileContents(syntax) `method`

##### Summary

Helper function to turn a client or type into a string of file contents

##### Returns

String source code of the specified syntax

##### Parameters

| Name | Type | Description |
| ---- | ---- | ----------- |
| syntax | [Microsoft.CodeAnalysis.CSharp.Syntax.CompilationUnitSyntax](#T-Microsoft-CodeAnalysis-CSharp-Syntax-CompilationUnitSyntax 'Microsoft.CodeAnalysis.CSharp.Syntax.CompilationUnitSyntax') | The client or type file to convert to a string |

<a name='M-EdjCase-ICP-ClientGenerator-ClientSyntax-Rewrite-Microsoft-CodeAnalysis-CSharp-CSharpSyntaxRewriter-'></a>
### Rewrite(rewriter) `method`

##### Summary

Rewrites the syntax with the specified \`CSharpSyntaxRewriter\`

##### Returns

Updated client syntax

##### Parameters

| Name | Type | Description |
| ---- | ---- | ----------- |
| rewriter | [Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter](#T-Microsoft-CodeAnalysis-CSharp-CSharpSyntaxRewriter 'Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter') | A \`CSharpSyntaxRewriter\` to rewrite the csharp syntax |
20 changes: 20 additions & 0 deletions src/ClientGenerator/API.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 57 additions & 0 deletions src/ClientGenerator/ClientSourceCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Options;
using Microsoft.VisualBasic;
using System;
using System.Collections.Generic;
using System.IO;
Expand Down Expand Up @@ -43,6 +46,60 @@ public ClientSyntax(string name, CompilationUnitSyntax clientFile, List<(string
this.ClientFile = clientFile ?? throw new ArgumentNullException(nameof(clientFile));
this.TypeFiles = typeFiles ?? throw new ArgumentNullException(nameof(typeFiles));
}

/// <summary>
/// Rewrites the syntax with the specified `CSharpSyntaxRewriter`
/// </summary>
/// <param name="rewriter">A `CSharpSyntaxRewriter` to rewrite the csharp syntax</param>
/// <returns>Updated client syntax</returns>
public ClientSyntax Rewrite(CSharpSyntaxRewriter rewriter)
{
CompilationUnitSyntax updatedClientFile = (CompilationUnitSyntax)rewriter.Visit(this.ClientFile);

List<(string Name, CompilationUnitSyntax updatedSyntax)> updatedTypeFiles = this.TypeFiles
.Select((typeFile) =>
{
CompilationUnitSyntax updatedSyntax = (CompilationUnitSyntax)rewriter.Visit(typeFile.Syntax);
return (typeFile.Name, updatedSyntax);
})
.ToList();

return new ClientSyntax(this.Name, updatedClientFile, updatedTypeFiles);
}

/// <summary>
/// Converts the file syntax objects into source code string values to use as a file
/// </summary>
/// <returns>Client and type source code file contents</returns>
public (string ClientFile, List<(string Name, string Contents)> TypeFiles) GenerateFileContents()
{
string clientFile = GenerateFileContents(this.ClientFile);

List<(string Name, string Contents)> typeFileContents = this.TypeFiles
.Select((typeFile) =>
{
string contents = GenerateFileContents(typeFile.Syntax);
return (typeFile.Name, contents);
})
.ToList();
return (clientFile, typeFileContents);
}

/// <summary>
/// Helper function to turn a client or type into a string of file contents
/// </summary>
/// <param name="syntax">The client or type file to convert to a string</param>
/// <returns>String source code of the specified syntax</returns>
public static string GenerateFileContents(CompilationUnitSyntax syntax)
{
// Setup formatting options
AdhocWorkspace workspace = new();
OptionSet options = workspace.Options
.WithChangedOption(FormattingOptions.UseTabs, LanguageNames.CSharp, value: true)
.WithChangedOption(FormattingOptions.NewLine, LanguageNames.CSharp, value: Environment.NewLine);

return Formatter.Format(syntax, workspace, options).ToFullString();
}
}

}
20 changes: 20 additions & 0 deletions src/ClientGenerator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,23 @@ candid-client-generator gen ./
- `no-folders` - (Bool) OPTIONAL. If true, no sub-folders will be generated for the client. All generated files will be in a flat structure. Defaults to false. Overrides the top level `no-folders`
- `feature-nullable` - (Bool) Optional. Sets whether to use the C# nullable feature when generating the client (like `object?`). Defaults to true. Overrides the top level `feature-nullable`
- `keep-candid-case` - (Bool) Optional. If true, the names of properties and methods will keep the raw candid name. Otherwise they will be converted to something prettier. Defaults to false. Overrides the top level `keep-candid-case`


# Custom Client Generators via Code
Due to the complexity of different use cases, custom tweaks to the output of the client generators might be helpful. This process
can be handled with calling the `ClientCodeGenerator` manually and using the .NET `CSharpSyntaxRewriter` (tutorial can be found [HERE](https://joshvarty.com/2014/08/15/learn-roslyn-now-part-5-csharpsyntaxrewriter/))

```cs
var options = new ClientGenerationOptions(
name: "MyClient",
@namespace: "My.Namespace",
noFolders: false,
featureNullable: true,
keepCandidCase: false
);
ClientSyntax syntax = await ClientCodeGenerator.GenerateClientFromCanisterAsync(canisterId, options);
var rewriter = new MyCustomCSharpSyntaxRewriter();
syntax = syntax.Rewrite(rewriter);
(string clientFile, List<(string Name, string Contents)> typeFiles) = syntax.GenerateFileContents();
// Write string contents to files...
```
8 changes: 1 addition & 7 deletions src/ClientGenerator/Tool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -223,13 +223,7 @@ CompilationUnitSyntax syntax
Directory.CreateDirectory(directory);
string filePath = Path.Combine(directory, fileName + ".cs");

// Setup formatting options
AdhocWorkspace workspace = new();
OptionSet options = workspace.Options
.WithChangedOption(FormattingOptions.UseTabs, LanguageNames.CSharp, value: true)
.WithChangedOption(FormattingOptions.NewLine, LanguageNames.CSharp, value: Environment.NewLine);

string text = Formatter.Format(syntax, workspace, options).ToFullString();
string text = ClientSyntax.GenerateFileContents(syntax);

File.WriteAllText(filePath, text);
}
Expand Down

0 comments on commit 503386f

Please sign in to comment.