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

Align the client type shape from TCGC in our emitter #6179

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
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
Prev Previous commit
Next Next commit
update around parent client
  • Loading branch information
ArcturusZhang committed Mar 3, 2025
commit 086a72028ba024cca9bdbe5ad83a5b487c92d4b2
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

import { SdkClientType as SdkClientTypeOfT, SdkHttpOperation } from "@azure-tools/typespec-client-generator-core";
import {
SdkClientType as SdkClientTypeOfT,
SdkHttpOperation,
} from "@azure-tools/typespec-client-generator-core";
import { CSharpEmitterContext } from "../sdk-context.js";
import { InputClientType } from "../type/input-type.js";

Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

import {
UsageFlags,
} from "@azure-tools/typespec-client-generator-core";
import { UsageFlags } from "@azure-tools/typespec-client-generator-core";
import { NoTarget } from "@typespec/compiler";
import { CSharpEmitterContext } from "../sdk-context.js";
import { CodeModel } from "../type/code-model.js";
import { fromSdkClients } from "./client-converter.js";
import { navigateModels } from "./model.js";
import { processServiceAuthentication } from "./service-authentication.js";
import { fromSdkClients } from "./client-converter.js";

/**
* Creates the code model from the SDK context.
7 changes: 6 additions & 1 deletion packages/http-client-csharp/emitter/src/sdk-context.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

import { SdkClientType, SdkContext, SdkHttpOperation, SdkType } from "@azure-tools/typespec-client-generator-core";
import {
SdkClientType,
SdkContext,
SdkHttpOperation,
SdkType,
} from "@azure-tools/typespec-client-generator-core";
import { Type } from "@typespec/compiler";
import { Logger } from "./lib/logger.js";
import { CSharpEmitterOptions } from "./options.js";
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.TypeSpec.Generator.ClientModel.Primitives;
using Microsoft.TypeSpec.Generator.EmitterRpc;
@@ -36,6 +37,9 @@ private record OAuth2Fields(FieldProvider AuthField, FieldProvider Authorization
private readonly InputClient _inputClient;
private readonly InputAuth? _inputAuth;
private readonly ParameterProvider _endpointParameter;
/// <summary>
/// This field is not one of the fields in this client, but the field in my parent client to get myself.
/// </summary>
private readonly FieldProvider? _clientCachingField;

private readonly ApiKeyFields? _apiKeyAuthFields;
@@ -232,7 +236,45 @@ private IReadOnlyList<ParameterProvider> GetClientParameters()

protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", $"{Name}.cs");

protected override string BuildName() => _inputClient.Name.ToCleanName();
protected override string BuildName()
{
var myName = _inputClient.Name.ToCleanName();
if (_inputClient.Parent == null)
{
// if this client does not have a parent, it is a toplevel client
return myName;
}

var parents = new List<InputClient>();
var parent = _inputClient.Parent;
while (parent != null)
{
parents.Add(parent);
parent = parent.Parent;
}

// General rule for client name:
// We alaways concat all its parents' name together as the prefix of the client name, but we exclude the root client's name.
// Therefore:
// for the first level children, its client name is its original name
// for deeper children, we add its parents' name as the prefix until the root (excluded)

if (parents.Count >= 2)
{
// when this client is more than second level client (its parent is not the root client),
// we concat all its parents' name together as the client name prefix, but exclude the root client's name.
var clientName = new StringBuilder();
for (int i = parents.Count - 2; i >= 0; i--)
{
clientName.Append(parents[i].Name.ToCleanName());
}
clientName.Append(myName);
return clientName.ToString();
}

// when this client is the first level client (its parent is the root client), we just use its name
return myName;
}

protected override FieldProvider[] BuildFields()
{
@@ -597,19 +639,14 @@ private ParameterProvider BuildClientEndpointParameter()

private IReadOnlyList<ClientProvider> GetSubClients()
{
var inputClients = ScmCodeModelPlugin.Instance.InputLibrary.InputNamespace.Clients;
var subClients = new List<ClientProvider>(inputClients.Count);
var subClients = new List<ClientProvider>(_inputClient.Children.Count);

foreach (var client in inputClients)
foreach (var client in _inputClient.Children)
{
// add direct child clients
if (client.Parent != null && client.Parent == _inputClient.Key)
var subClient = ScmCodeModelPlugin.Instance.TypeFactory.CreateClient(client);
if (subClient != null)
{
var subClient = ScmCodeModelPlugin.Instance.TypeFactory.CreateClient(client);
if (subClient != null)
{
subClients.Add(subClient);
}
subClients.Add(subClient);
}
}

Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@

using System.Collections.Generic;
using Microsoft.TypeSpec.Generator.ClientModel.Providers;
using Microsoft.TypeSpec.Generator.Input;
using Microsoft.TypeSpec.Generator.Providers;

namespace Microsoft.TypeSpec.Generator.ClientModel
@@ -15,23 +16,33 @@ private static TypeProvider[] BuildClients()
var clients = new List<TypeProvider>(inputClients.Count * 3);
foreach (var inputClient in inputClients)
{
var client = ScmCodeModelPlugin.Instance.TypeFactory.CreateClient(inputClient);
if (client == null)
{
continue;
}
clients.Add(client);
clients.Add(client.RestClient);
var clientOptions = client.ClientOptions.Value;
if (clientOptions != null)
{
clients.Add(clientOptions);
}
BuildClient(inputClient, clients);
}

return [.. clients];
}

private static void BuildClient(InputClient inputClient, IList<TypeProvider> clients)
{
var client = ScmCodeModelPlugin.Instance.TypeFactory.CreateClient(inputClient);
if (client == null)
{
return;
}
clients.Add(client);
clients.Add(client.RestClient);
var clientOptions = client.ClientOptions.Value;
if (clientOptions != null)
{
clients.Add(clientOptions);
}

foreach (var child in inputClient.Children)
{
BuildClient(child, clients);
}
}

protected override TypeProvider[] BuildTypeProviders()
{
var baseTypes = base.BuildTypeProviders();
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ public class InputClient
private readonly string? _key;
private IReadOnlyDictionary<string, InputClientExample>? _examples;

public InputClient(string name, string @namespace, string crossLanguageDefinitionId, string? summary, string? doc, IReadOnlyList<InputOperation> operations, IReadOnlyList<InputParameter> parameters, string? parent)
public InputClient(string name, string @namespace, string crossLanguageDefinitionId, string? summary, string? doc, IReadOnlyList<InputOperation> operations, IReadOnlyList<InputParameter> parameters, InputClient? parent, IReadOnlyList<InputClient>? children)
{
Name = name;
Namespace = @namespace;
@@ -21,9 +21,10 @@ public InputClient(string name, string @namespace, string crossLanguageDefinitio
Operations = operations;
Parameters = parameters;
Parent = parent;
Children = children ?? [];
}

public InputClient() : this(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, Array.Empty<InputOperation>(), Array.Empty<InputParameter>(), null) { }
public InputClient() : this(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, Array.Empty<InputOperation>(), Array.Empty<InputParameter>(), null, null) { }

public string Name { get; internal set; }
public string Namespace { get; internal set; }
@@ -32,7 +33,8 @@ public InputClient() : this(string.Empty, string.Empty, string.Empty, string.Emp
public string? Doc { get; internal set; }
public IReadOnlyList<InputOperation> Operations { get; internal set; }
public IReadOnlyList<InputParameter> Parameters { get; internal set; }
public string? Parent { get; internal set; }
public InputClient? Parent { get; internal set; }
public IReadOnlyList<InputClient> Children { get; internal set; }
public IReadOnlyList<InputDecoratorInfo> Decorators { get; internal set; } = new List<InputDecoratorInfo>();

public string Key
Original file line number Diff line number Diff line change
@@ -41,8 +41,9 @@ public override void Write(Utf8JsonWriter writer, InputClient value, JsonSeriali
IReadOnlyList<InputOperation>? operations = null;
IReadOnlyList<InputParameter>? parameters = null;
IReadOnlyList<InputDecoratorInfo>? decorators = null;
string? parent = null;
string? crossLanguageDefinitionId = null;
InputClient? parent = null;
IReadOnlyList<InputClient>? children = null;

while (reader.TokenType != JsonTokenType.EndObject)
{
@@ -53,9 +54,9 @@ public override void Write(Utf8JsonWriter writer, InputClient value, JsonSeriali
|| reader.TryReadWithConverter("operations", options, ref operations)
|| reader.TryReadWithConverter("parameters", options, ref parameters)
|| reader.TryReadWithConverter("decorators", options, ref decorators)
|| reader.TryReadString("crossLanguageDefinitionId", ref crossLanguageDefinitionId);
//|| reader.TryReadWithConverter("parent", options, ref parent)
//|| reader.TryReadWithConverter("children", options, ref children)
|| reader.TryReadString("crossLanguageDefinitionId", ref crossLanguageDefinitionId)
|| reader.TryReadWithConverter("parent", options, ref parent)
|| reader.TryReadWithConverter("children", options, ref children);

if (!isKnownProperty)
{
@@ -70,8 +71,9 @@ public override void Write(Utf8JsonWriter writer, InputClient value, JsonSeriali
client.Doc = doc;
client.Operations = operations ?? [];
client.Parameters = parameters ?? [];
client.Parent = parent;
client.Decorators = decorators ?? [];
client.Parent = parent;
client.Children = children ?? [];

var lastSegment = GetLastSegment(client.Namespace);
if (lastSegment == client.Name)
Loading
Oops, something went wrong.
Loading
Oops, something went wrong.