Skip to content

Commit

Permalink
Merge branch 'main' into vscode/openapi-preview
Browse files Browse the repository at this point in the history
  • Loading branch information
archerzz authored Feb 14, 2025
2 parents e224bde + d7b17df commit 9185597
Show file tree
Hide file tree
Showing 100 changed files with 4,311 additions and 1,978 deletions.
7 changes: 7 additions & 0 deletions .chronus/changes/bum-tsp-0.65.0-2025-1-13-11-20-8.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: dependencies
packages:
- "@typespec/http-client-python"
---

Bump to tsp 0.65.0
7 changes: 7 additions & 0 deletions .chronus/changes/clean-up-and-refactor-2025-1-13-19-14-29.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: internal
packages:
- "@typespec/http-client-csharp"
---

refactor around CSharpEmitterContext and Logger
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: feature
packages:
- "@typespec/http-client-java"
---

Support clientcore 1.0.0-beta.3
54 changes: 23 additions & 31 deletions packages/http-client-csharp/emitter/src/emitter.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

import {
createSdkContext,
SdkContext,
UsageFlags,
} from "@azure-tools/typespec-client-generator-core";
import { createSdkContext, UsageFlags } from "@azure-tools/typespec-client-generator-core";
import {
EmitContext,
getDirectoryPath,
Expand All @@ -15,7 +11,6 @@ import {
Program,
resolvePath,
} from "@typespec/compiler";

import fs, { statSync } from "fs";
import { PreserveType, stringifyRefs } from "json-serialize-refs";
import { dirname } from "path";
Expand All @@ -26,18 +21,14 @@ import {
tspOutputFileName,
} from "./constants.js";
import { createModel } from "./lib/client-model-builder.js";
import { reportDiagnostic } from "./lib/lib.js";
import { LoggerLevel } from "./lib/log-level.js";
import { LoggerLevel } from "./lib/logger-level.js";
import { Logger } from "./lib/logger.js";
import { execAsync } from "./lib/utils.js";
import { _resolveOutputFolder, NetEmitterOptions, resolveOptions } from "./options.js";
import { _resolveOutputFolder, CSharpEmitterOptions, resolveOptions } from "./options.js";
import { defaultSDKContextOptions } from "./sdk-context-options.js";
import { CSharpEmitterContext } from "./sdk-context.js";
import { Configuration } from "./type/configuration.js";

export interface CSharpEmitterContext extends SdkContext<NetEmitterOptions> {
logger: Logger;
}

/**
* Look for the project root by looking up until a `package.json` is found.
* @param path Path to start looking
Expand All @@ -63,7 +54,7 @@ function findProjectRoot(path: string): string | undefined {
* @param context - The emit context
* @beta
*/
export async function $onEmit(context: EmitContext<NetEmitterOptions>) {
export async function $onEmit(context: EmitContext<CSharpEmitterOptions>) {
const program: Program = context.program;
const options = resolveOptions(context);
const outputFolder = _resolveOutputFolder(context);
Expand All @@ -73,13 +64,20 @@ export async function $onEmit(context: EmitContext<NetEmitterOptions>) {

if (!program.compilerOptions.noEmit && !program.hasError()) {
// Write out the dotnet model to the output path
const sdkContext = await createSdkContext(
context,
"@typespec/http-client-csharp",
defaultSDKContextOptions,
);
const csharpEmitterContext = { ...sdkContext, logger: logger };
const root = createModel(csharpEmitterContext);
const sdkContext = {
...(await createSdkContext(
context,
"@typespec/http-client-csharp",
defaultSDKContextOptions,
)),
logger: logger,
__typeCache: {
types: new Map(),
models: new Map(),
enums: new Map(),
},
};
const root = createModel(sdkContext);
if (
context.program.diagnostics.length > 0 &&
context.program.diagnostics.filter((digs) => digs.severity === "error").length > 0
Expand Down Expand Up @@ -152,10 +150,7 @@ export async function $onEmit(context: EmitContext<NetEmitterOptions>) {
{ stdio: "inherit" },
);
if (result.exitCode !== 0) {
const isValid = await _validateDotNetSdk(
csharpEmitterContext,
_minSupportedDotNetSdkVersion,
);
const isValid = await _validateDotNetSdk(sdkContext, _minSupportedDotNetSdkVersion);
// if the dotnet sdk is valid, the error is not dependency issue, log it as normal
if (isValid) {
if (result.stderr) logger.error(result.stderr);
Expand All @@ -164,10 +159,7 @@ export async function $onEmit(context: EmitContext<NetEmitterOptions>) {
}
}
} catch (error: any) {
const isValid = await _validateDotNetSdk(
csharpEmitterContext,
_minSupportedDotNetSdkVersion,
);
const isValid = await _validateDotNetSdk(sdkContext, _minSupportedDotNetSdkVersion);
// if the dotnet sdk is valid, the error is not dependency issue, log it as normal
if (isValid) throw new Error(error);
}
Expand Down Expand Up @@ -197,7 +189,7 @@ export async function _validateDotNetSdk(
return validateDotNetSdkVersionCore(sdkContext, result.stdout, minMajorVersion);
} catch (error: any) {
if (error && "code" in (error as {}) && error["code"] === "ENOENT") {
reportDiagnostic(sdkContext.program, {
sdkContext.logger.reportDiagnostic({
code: "invalid-dotnet-sdk-dependency",
messageId: "missing",
format: {
Expand Down Expand Up @@ -226,7 +218,7 @@ function validateDotNetSdkVersionCore(
return false;
}
if (major < minMajorVersion) {
reportDiagnostic(sdkContext.program, {
sdkContext.logger.reportDiagnostic({
code: "invalid-dotnet-sdk-dependency",
messageId: "invalidVersion",
format: {
Expand Down
6 changes: 3 additions & 3 deletions packages/http-client-csharp/emitter/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
export { configurationFileName, tspOutputFileName } from "./constants.js";
export { $onEmit } from "./emitter.js";
export { createDiagnostic, getTracer, reportDiagnostic } from "./lib/lib.js";
export { LoggerLevel } from "./lib/log-level.js";
export { LoggerLevel } from "./lib/logger-level.js";
export { Logger } from "./lib/logger.js";
export {
NetEmitterOptions,
NetEmitterOptionsSchema,
CSharpEmitterOptions,
CSharpEmitterOptionsSchema,
defaultOptions,
resolveOptions,
} from "./options.js";
Expand Down
43 changes: 17 additions & 26 deletions packages/http-client-csharp/emitter/src/lib/client-model-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,16 @@ import {
SdkEndpointType,
SdkHttpOperation,
SdkServiceMethod,
SdkType,
UsageFlags,
} from "@azure-tools/typespec-client-generator-core";
import { NoTarget } from "@typespec/compiler";
import { CSharpEmitterContext } from "../emitter.js";
import { CSharpEmitterContext } from "../sdk-context.js";
import { CodeModel } from "../type/code-model.js";
import { InputClient } from "../type/input-client.js";
import { InputOperationParameterKind } from "../type/input-operation-parameter-kind.js";
import { InputParameter } from "../type/input-parameter.js";
import { InputEnumType, InputModelType, InputType } from "../type/input-type.js";
import { InputType } from "../type/input-type.js";
import { RequestLocation } from "../type/request-location.js";
import { SdkTypeMap } from "../type/sdk-type-map.js";
import { reportDiagnostic } from "./lib.js";
import { navigateModels } from "./model.js";
import { fromSdkServiceMethod, getParameterDefaultValue } from "./operation-converter.js";
import { processServiceAuthentication } from "./service-authentication.js";
Expand All @@ -28,19 +25,17 @@ import { fromSdkType } from "./type-converter.js";
export function createModel(sdkContext: CSharpEmitterContext): CodeModel {
const sdkPackage = sdkContext.sdkPackage;

const sdkTypeMap: SdkTypeMap = {
types: new Map<SdkType, InputType>(),
models: new Map<string, InputModelType>(),
enums: new Map<string, InputEnumType>(),
};

navigateModels(sdkContext, sdkTypeMap);
navigateModels(sdkContext);

const sdkApiVersionEnums = sdkPackage.enums.filter((e) => e.usage === UsageFlags.ApiVersionEnum);

const rootClients = sdkPackage.clients.filter((c) => c.initialization.access === "public");
if (rootClients.length === 0) {
reportDiagnostic(sdkContext.program, { code: "no-root-client", format: {}, target: NoTarget });
sdkContext.logger.reportDiagnostic({
code: "no-root-client",
format: {},
target: NoTarget,
});
return {} as CodeModel;
}

Expand All @@ -49,41 +44,38 @@ export function createModel(sdkContext: CSharpEmitterContext): CodeModel {
? sdkApiVersionEnums[0].values.map((v) => v.value as string).flat()
: rootClients[0].apiVersions;

// this is a set tracking the bad namespace segments
const inputClients: InputClient[] = [];
fromSdkClients(sdkContext, rootClients, inputClients, []);
fromSdkClients(rootClients, inputClients, []);

const clientModel: CodeModel = {
Name: sdkPackage.rootNamespace,
ApiVersions: rootApiVersions,
Enums: Array.from(sdkTypeMap.enums.values()),
Models: Array.from(sdkTypeMap.models.values()),
Enums: Array.from(sdkContext.__typeCache.enums.values()),
Models: Array.from(sdkContext.__typeCache.models.values()),
Clients: inputClients,
Auth: processServiceAuthentication(sdkContext, sdkPackage),
};

return clientModel;

function fromSdkClients(
sdkContext: CSharpEmitterContext,
clients: SdkClientType<SdkHttpOperation>[],
inputClients: InputClient[],
parentClientNames: string[],
) {
for (const client of clients) {
const inputClient = fromSdkClient(sdkContext, client, parentClientNames);
const inputClient = fromSdkClient(client, parentClientNames);
inputClients.push(inputClient);
const subClients = client.methods
.filter((m) => m.kind === "clientaccessor")
.map((m) => m.response as SdkClientType<SdkHttpOperation>);
parentClientNames.push(inputClient.Name);
fromSdkClients(sdkContext, subClients, inputClients, parentClientNames);
fromSdkClients(subClients, inputClients, parentClientNames);
parentClientNames.pop();
}
}

function fromSdkClient(
sdkContext: CSharpEmitterContext,
client: SdkClientType<SdkHttpOperation>,
parentNames: string[],
): InputClient {
Expand All @@ -100,7 +92,7 @@ export function createModel(sdkContext: CSharpEmitterContext): CodeModel {
// we report diagnostics when the last segment of the namespace is the same as the client name
// because in our design, a sub namespace will be generated as a sub client with exact the same name as the namespace
// in csharp, this will cause a conflict between the namespace and the class name
reportDiagnostic(sdkContext.program, {
sdkContext.logger.reportDiagnostic({
code: "client-namespace-conflict",
format: { clientNamespace: client.clientNamespace, clientName },
target: client.__raw.type ?? NoTarget,
Expand All @@ -116,11 +108,10 @@ export function createModel(sdkContext: CSharpEmitterContext): CodeModel {
.filter((m) => m.kind !== "clientaccessor")
.map((m) =>
fromSdkServiceMethod(
sdkContext,
m as SdkServiceMethod<SdkHttpOperation>,
uri,
rootApiVersions,
sdkContext,
sdkTypeMap,
),
),
Protocol: {},
Expand Down Expand Up @@ -158,7 +149,7 @@ export function createModel(sdkContext: CSharpEmitterContext): CodeModel {
.replace("http://", "")
.split("/")[0];
if (!/^\{\w+\}$/.test(endpointExpr)) {
reportDiagnostic(sdkContext.program, {
sdkContext.logger.reportDiagnostic({
code: "unsupported-endpoint-url",
format: { endpoint: type.serverUrl },
target: NoTarget,
Expand All @@ -176,7 +167,7 @@ export function createModel(sdkContext: CSharpEmitterContext): CodeModel {
name: "url",
crossLanguageDefinitionId: "TypeSpec.url",
}
: fromSdkType(parameter.type, sdkContext, sdkTypeMap); // TODO: consolidate with converter.fromSdkEndpointType
: fromSdkType(sdkContext, parameter.type); // TODO: consolidate with converter.fromSdkEndpointType
parameters.push({
Name: parameter.name,
NameInRequest: parameter.serializedName,
Expand Down
Loading

0 comments on commit 9185597

Please sign in to comment.