Skip to content

Commit

Permalink
Adding no folders option for client gen
Browse files Browse the repository at this point in the history
  • Loading branch information
Gekctek committed Mar 10, 2023
1 parent 28333a9 commit b217958
Show file tree
Hide file tree
Showing 12 changed files with 81 additions and 63 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,12 +305,14 @@ Example:
```
namespace = "My.Namespace" # Base namespace used for generated files
output-directory = "./Clients" # Directory to put clients. Each client will get its own sub folder based on its name. If not specified, will use current directory
no-folders = false # If true, will put all the files in a single directory
[[clients]]
name = "Dex" # Used for the name of the folder and client class
type = "file" # Create client based on service definition file
file-path = "./ServiceDefinitionFiles/Dex.did" # Service definition file path
output-directory = "./Clients/D" # Override base output directory, but this specifies the subfolder
no-folders = false # If true, will put all the files in a single directory
# Can specify multiple clients by defining another
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using EdjCase.ICP.Candid.Mapping;
using EdjCase.ICP.Candid.Models;

namespace Sample.Shared.AddressBook.Models
namespace Sample.Shared.AddressBook
{
public class Address
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,18 @@ public AddressBookApiClient(IAgent agent, Principal canisterId, CandidConverter?
this.Converter = converter;
}

public async Task SetAddress(string name, Models.Address addr)
public async Task SetAddress(string name, Address addr)
{
CandidArg arg = CandidArg.FromCandid(CandidTypedValue.FromObject(name), CandidTypedValue.FromObject(addr));
CandidArg reply = await this.Agent.CallAndWaitAsync(this.CanisterId, "set_address", arg);
}

public async System.Threading.Tasks.Task<OptionalValue<Models.Address>> GetAddress(string name)
public async System.Threading.Tasks.Task<OptionalValue<Address>> GetAddress(string name)
{
CandidArg arg = CandidArg.FromCandid(CandidTypedValue.FromObject(name));
QueryResponse response = await this.Agent.QueryAsync(this.CanisterId, "get_address", arg);
CandidArg reply = response.ThrowOrGetReply();
return reply.ToObjects<OptionalValue<Models.Address>>(this.Converter);
return reply.ToObjects<OptionalValue<Address>>(this.Converter);
}
}
}
3 changes: 2 additions & 1 deletion samples/Sample.Shared/candid-client.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ canister-id = "rrkah-fqaaa-aaaaa-aaaaq-cai"
name = "AddressBook"
type = "file"
file-path = "../ServiceDefinitionFiles/AddressBook.did"
output-directory = "C:/Git/ICP.NET/samples/Sample.Shared/Address" # override
output-directory = "C:/Git/ICP.NET/samples/Sample.Shared/Address" # override
no-folders = true
52 changes: 26 additions & 26 deletions src/Agent/API.xml

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

15 changes: 12 additions & 3 deletions src/ClientGenerator/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
- [GenerateClientFromCanisterAsync(canisterId,options,httpBoundryNodeUrl)](#M-EdjCase-ICP-ClientGenerator-ClientCodeGenerator-GenerateClientFromCanisterAsync-EdjCase-ICP-Candid-Models-Principal,EdjCase-ICP-ClientGenerator-ClientGenerationOptions,System-Uri- 'EdjCase.ICP.ClientGenerator.ClientCodeGenerator.GenerateClientFromCanisterAsync(EdjCase.ICP.Candid.Models.Principal,EdjCase.ICP.ClientGenerator.ClientGenerationOptions,System.Uri)')
- [GenerateClientFromFile(fileText,options)](#M-EdjCase-ICP-ClientGenerator-ClientCodeGenerator-GenerateClientFromFile-System-String,EdjCase-ICP-ClientGenerator-ClientGenerationOptions- 'EdjCase.ICP.ClientGenerator.ClientCodeGenerator.GenerateClientFromFile(System.String,EdjCase.ICP.ClientGenerator.ClientGenerationOptions)')
- [ClientGenerationOptions](#T-EdjCase-ICP-ClientGenerator-ClientGenerationOptions 'EdjCase.ICP.ClientGenerator.ClientGenerationOptions')
- [#ctor(name,namespace)](#M-EdjCase-ICP-ClientGenerator-ClientGenerationOptions-#ctor-System-String,System-String- 'EdjCase.ICP.ClientGenerator.ClientGenerationOptions.#ctor(System.String,System.String)')
- [#ctor(name,namespace,noFolders)](#M-EdjCase-ICP-ClientGenerator-ClientGenerationOptions-#ctor-System-String,System-String,System-Boolean- 'EdjCase.ICP.ClientGenerator.ClientGenerationOptions.#ctor(System.String,System.String,System.Boolean)')
- [Name](#P-EdjCase-ICP-ClientGenerator-ClientGenerationOptions-Name 'EdjCase.ICP.ClientGenerator.ClientGenerationOptions.Name')
- [Namespace](#P-EdjCase-ICP-ClientGenerator-ClientGenerationOptions-Namespace 'EdjCase.ICP.ClientGenerator.ClientGenerationOptions.Namespace')
- [NoFolders](#P-EdjCase-ICP-ClientGenerator-ClientGenerationOptions-NoFolders 'EdjCase.ICP.ClientGenerator.ClientGenerationOptions.NoFolders')
- [ClientSyntax](#T-EdjCase-ICP-ClientGenerator-ClientSyntax 'EdjCase.ICP.ClientGenerator.ClientSyntax')
- [#ctor(name,clientFile,typeFiles)](#M-EdjCase-ICP-ClientGenerator-ClientSyntax-#ctor-System-String,Microsoft-CodeAnalysis-CSharp-Syntax-CompilationUnitSyntax,System-Collections-Generic-List{System-ValueTuple{System-String,Microsoft-CodeAnalysis-CSharp-Syntax-CompilationUnitSyntax}}- 'EdjCase.ICP.ClientGenerator.ClientSyntax.#ctor(System.String,Microsoft.CodeAnalysis.CSharp.Syntax.CompilationUnitSyntax,System.Collections.Generic.List{System.ValueTuple{System.String,Microsoft.CodeAnalysis.CSharp.Syntax.CompilationUnitSyntax}})')
- [ClientFile](#P-EdjCase-ICP-ClientGenerator-ClientSyntax-ClientFile 'EdjCase.ICP.ClientGenerator.ClientSyntax.ClientFile')
Expand Down Expand Up @@ -84,15 +85,16 @@ EdjCase.ICP.ClientGenerator

Options for generating a client

<a name='M-EdjCase-ICP-ClientGenerator-ClientGenerationOptions-#ctor-System-String,System-String-'></a>
### #ctor(name,namespace) `constructor`
<a name='M-EdjCase-ICP-ClientGenerator-ClientGenerationOptions-#ctor-System-String,System-String,System-Boolean-'></a>
### #ctor(name,namespace,noFolders) `constructor`

##### Parameters

| Name | Type | Description |
| ---- | ---- | ----------- |
| name | [System.String](http://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k:System.String 'System.String') | The name of the client class and file to use |
| namespace | [System.String](http://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k:System.String 'System.String') | The base namespace to use in the generated files |
| noFolders | [System.Boolean](http://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k:System.Boolean 'System.Boolean') | If true, there will be no folders, all files will be in the same directory |

<a name='P-EdjCase-ICP-ClientGenerator-ClientGenerationOptions-Name'></a>
### Name `property`
Expand All @@ -108,6 +110,13 @@ The name of the client class and file to use

The base namespace to use in the generated files

<a name='P-EdjCase-ICP-ClientGenerator-ClientGenerationOptions-NoFolders'></a>
### NoFolders `property`

##### Summary

If true, there will be no folders, all files will be in the same directory

<a name='T-EdjCase-ICP-ClientGenerator-ClientSyntax'></a>
## ClientSyntax `type`

Expand Down
8 changes: 7 additions & 1 deletion src/ClientGenerator/API.xml

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

4 changes: 3 additions & 1 deletion src/ClientGenerator/ClientCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ ClientGenerationOptions options
t => ResolveSourceCodeType(t.Value)
);

string modelNamespace = options.Namespace + ".Models";
string modelNamespace = options.NoFolders
? options.Namespace
: options.Namespace + ".Models";
HashSet<ValueName> aliases = declaredTypes
.Where(t => t.Value is CompiledTypeSourceCodeType || t.Value is ReferenceSourceCodeType)
.Select(t => t.Key)
Expand Down
8 changes: 7 additions & 1 deletion src/ClientGenerator/ClientGenerationOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@ public class ClientGenerationOptions
/// The base namespace to use in the generated files
/// </summary>
public string Namespace { get; }
/// <summary>
/// If true, there will be no folders, all files will be in the same directory
/// </summary>
public bool NoFolders { get; }

/// <param name="name">The name of the client class and file to use</param>
/// <param name="namespace">The base namespace to use in the generated files</param>
public ClientGenerationOptions(string name, string @namespace)
/// <param name="noFolders">If true, there will be no folders, all files will be in the same directory</param>
public ClientGenerationOptions(string name, string @namespace, bool noFolders)
{
if (string.IsNullOrWhiteSpace(name))
{
Expand All @@ -32,6 +37,7 @@ public ClientGenerationOptions(string name, string @namespace)
// Trim whitespace and replace spaces with underscores
this.Name = StringUtil.ToPascalCase(name.Trim().Replace(' ', '_'));
this.Namespace = @namespace ?? throw new ArgumentNullException(nameof(@namespace));
this.NoFolders = noFolders;
}
}
}
25 changes: 17 additions & 8 deletions src/ClientGenerator/Tool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,13 @@ namespace = ""My.Namespace""
# Will create a subfolder within this directory with all the files
output-directory = ""./Clients""
# Remove comment to override default boundry node url (like for local development)
# Will override default boundry node url (like for local development)
# Only useful for generating clients from a canister id
#url = ""https://localhost:8000""
# Will make generated files in a flat structure with no folders, for all clients
#no-folders = true
[[clients]]
# Defines name folder and api client class name
name = ""MyClient""
Expand All @@ -82,6 +85,9 @@ namespace = ""My.Namespace""
# Override base output directory, but this specifies the subfolder
#output-directory = ""./Clients/MyS""
# Will make generated files in a flat structure with no folders, for this client
#no-folders = true
# Can specify multiple clients by creating another [[clients]]
#[[clients]]
Expand Down Expand Up @@ -112,9 +118,10 @@ private async static Task<int> Generate(GenerateOptions options)
TomlTable config = Tomlyn.Toml.ToModel(configToml);

string baseNamespace = GetRequired<string>(config, "namespace");
string? baseUrl = GetOptional<string>(config, "url");
string? baseUrl = GetOptional<string?>(config, "url");
bool? noFolders = GetOptional<bool?>(config, "no-folders");
Uri? boundryNodeUrl = baseUrl == null ? null : new Uri(baseUrl);
string outputDirectory = Path.GetRelativePath("./", GetOptional<string>(config, "output-directory") ?? "./");
string outputDirectory = Path.GetRelativePath("./", GetOptional<string?>(config, "output-directory") ?? "./");

TomlTableArray clients = config["clients"].Cast<TomlTableArray>();

Expand All @@ -123,8 +130,10 @@ private async static Task<int> Generate(GenerateOptions options)
string name = GetRequired<string>(client, "name");
string type = GetRequired<string>(client, "type");
string @namespace = baseNamespace + "." + name;
string? clientOutputDirectory = GetOptional<string>(client, "output-directory");
ClientGenerationOptions clientOptions = new(name, @namespace);
string? clientOutputDirectory = GetOptional<string?>(client, "output-directory");
string? clientNamespace = GetOptional<string?>(client, "namespace");
bool clientNoFolders = GetOptional<bool?>(client, "no-folders") ?? noFolders ?? false;
ClientGenerationOptions clientOptions = new(name, clientNamespace ?? @namespace, clientNoFolders);
ClientSyntax source;
switch (type)
{
Expand All @@ -146,7 +155,7 @@ private async static Task<int> Generate(GenerateOptions options)
default:
throw new InvalidOperationException($"Invalid client type '{type}'");
}
WriteClient(source, Path.Combine(clientOutputDirectory ?? outputDirectory, name));
WriteClient(source, clientOutputDirectory ?? Path.Combine(outputDirectory, name), clientNoFolders);
}
return 0;
}
Expand Down Expand Up @@ -179,7 +188,7 @@ private static T GetRequired<T>(TomlTable table, string key, string? prefix = nu
return default;
}

private static void WriteClient(ClientSyntax result, string outputDirectory)
private static void WriteClient(ClientSyntax result, string outputDirectory, bool noFolders)
{
Console.WriteLine($"Writing client file to: {outputDirectory}\\{result.Name}.cs");
WriteFile(null, result.Name, result.ClientFile);
Expand All @@ -188,7 +197,7 @@ private static void WriteClient(ClientSyntax result, string outputDirectory)
Console.WriteLine($"Writing data model files to directory: {outputDirectory}\\Models\\");
foreach ((string name, CompilationUnitSyntax sourceCode) in result.TypeFiles)
{
WriteFile("Models", name, sourceCode);
WriteFile(noFolders ? null : "Models", name, sourceCode);
}
Console.WriteLine("Client successfully generated!");
Console.WriteLine();
Expand Down
17 changes: 0 additions & 17 deletions test/Candid.Tests/CRC32Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,5 @@ public void ComputeHash(string hexData, string expectedHashHex)
Assert.Equal(expectedHashHex, actualHashHex);
}

// TODO
//[Theory]
//[InlineData("0")]
//[InlineData("000")]
//[InlineData("010203040506070809101112131415161718192021222324252627282930")]
//public void ComputeHash_Error_Length(string hexData)
//{
//
//}

// TODO
//[Theory]
//[InlineData("0g")]
//public void ComputeHash_Error_InvalidCharacters(string hexData)
//{
//
//}
}
}
2 changes: 1 addition & 1 deletion test/Candid.Tests/Generators/ClientGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public void GenerateClients(string serviceName)
string fileText = GetFileText(serviceName + ".did");
string baseNamespace = "Test";
CandidServiceDescription serviceFile = CandidServiceDescription.Parse(fileText);
ClientGenerationOptions options = new(serviceName, baseNamespace);
ClientGenerationOptions options = new(serviceName, baseNamespace, false);
ClientSyntax syntax = ClientCodeGenerator.GenerateClient(serviceFile, options);

AdhocWorkspace workspace = new();
Expand Down

0 comments on commit b217958

Please sign in to comment.