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

Backmerge/release/february 2025 2025 02 20 #2238

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
32 changes: 32 additions & 0 deletions packages/typespec-client-generator-core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,37 @@
# Change Log - @azure-tools/typespec-client-generator-core

## 0.51.2

### Bug Fixes

- [#2229](https://github.com/Azure/typespec-azure/pull/2229) Fix missing result segments of anonymous paged response with header.
- [#2196](https://github.com/Azure/typespec-azure/pull/2196) Do not allow union with circular ref, change union name inside nullable type and do not take nullable type as non-body response.

### Features

- [#2206](https://github.com/Azure/typespec-azure/pull/2206) Add `pagingMetadata.continuationTokenParameterSegments` and `pagingMetadata.continuationTokenResponseSegments` to `SdkPagingServiceMetadata` to indicate the mapping of continuation token parameter and response.
- [#2206](https://github.com/Azure/typespec-azure/pull/2206) Make `SdkServiceResponseHeader` to be part of `SdkModelPropertyType`. Then it could contain the client related info.
- [#2206](https://github.com/Azure/typespec-azure/pull/2206) Add `SdkPagingServiceMetadata` type to store all paging related info.
- [#2220](https://github.com/Azure/typespec-azure/pull/2220) Add `crossLanguageDefinitionId` property for `SdkNullableType`.

### Deprecations

- [#2206](https://github.com/Azure/typespec-azure/pull/2206) Deprecate `__raw_paged_metadata`, `nextLinkPath` and `nextLinkOperation` in `SdkPagingServiceMethodOptions`. Use `pagingMetadata.__raw`, `pagingMetadata.nextLinkSegments` and `pagingMetadata.nextLinkOperation` instead.
- [#2206](https://github.com/Azure/typespec-azure/pull/2206) Deprecate `resultPath` in `SdkMethodResponse`. Use `resultSegments` instead.
- [#2219](https://github.com/Azure/typespec-azure/pull/2219) Deprecate `clientNamespace` property in `SdkClientType`, `SdkNullableType`, `SdkEnumType`, `SdkUnionType` and `SdkModelType`. Use `namespace` instead.

### Breaking Changes

- [#2217](https://github.com/Azure/typespec-azure/pull/2217) Remove `null` form union for `value` property type of `SdkConstantType`. It is a breaking change, but since no logic will come to `null` type, it shall have little impact.


## 0.51.1

### Bug Fixes

- [#2211](https://github.com/Azure/typespec-azure/pull/2211) Make sure to keep orphan models


## 0.51.0

### Bug Fixes
Expand Down
6 changes: 3 additions & 3 deletions packages/typespec-client-generator-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@azure-tools/typespec-client-generator-core",
"version": "0.51.0",
"version": "0.51.2",
"author": "Microsoft Corporation",
"description": "TypeSpec Data Plane Generation library",
"homepage": "https://azure.github.io/typespec-azure",
Expand All @@ -23,8 +23,8 @@
"exports": {
".": {
"types": "./dist/src/index.d.ts",
"default": "./dist/src/index.js",
"typespec": "./lib/main.tsp"
"typespec": "./lib/main.tsp",
"default": "./dist/src/index.js"
},
"./testing": {
"types": "./dist/src/testing/index.d.ts",
Expand Down
15 changes: 11 additions & 4 deletions packages/typespec-client-generator-core/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {
SdkEmitterOptions,
SdkEnumType,
SdkHttpOperation,
SdkHttpParameter,
SdkMethodParameter,
SdkModelPropertyType,
SdkModelType,
SdkNullableType,
Expand All @@ -35,16 +37,21 @@ export function createTCGCContext(program: Program, emitterName?: string): TCGCC
parseEmitterName(program, emitterName ?? program.emitters[0]?.metadata?.name),
),
diagnostics: diagnostics.diagnostics,
originalProgram: program,
__originalProgram: program,
__clientToParameters: new Map(),
__tspTypeToApiVersions: new Map(),
__clientToApiVersionClientDefaultValue: new Map(),
previewStringRegex: /-preview$/,
disableUsageAccessPropagationToBase: false,
__pagedResultSet: new Set(),
referencedTypeMap: new Map<Type, SdkModelType | SdkEnumType | SdkUnionType | SdkNullableType>(),
httpOperationCache: new Map<Operation, HttpOperation>(),
referencedPropertyMap: new Map<ModelProperty, SdkModelPropertyType>(),
__referencedTypeCache: new Map<
Type,
SdkModelType | SdkEnumType | SdkUnionType | SdkNullableType
>(),
__httpOperationCache: new Map<Operation, HttpOperation>(),
__modelPropertyCache: new Map<ModelProperty, SdkModelPropertyType>(),
__methodParameterCache: new Map<ModelProperty, SdkMethodParameter>(),
__httpParameterCache: new Map<ModelProperty, SdkHttpParameter>(),
};
}

Expand Down
19 changes: 3 additions & 16 deletions packages/typespec-client-generator-core/src/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ import {
AllScopes,
clientNameKey,
clientNamespaceKey,
findRootSourceProperty,
getValidApiVersion,
isAzureCoreTspModel,
negationScopesKey,
scopeKey,
} from "./internal-utils.js";
Expand Down Expand Up @@ -316,7 +316,7 @@ function serviceVersioningProjection(context: TCGCContext, client: SdkClient) {
// TODO: THIS NEED TO BE MIGRATED BY MARCH 2024 release.
// eslint-disable-next-line @typescript-eslint/no-deprecated
projectedProgram = context.program = projectProgram(
context.originalProgram,
context.__originalProgram,
projectedVersion.projections,
);
}
Expand Down Expand Up @@ -901,20 +901,7 @@ function collectParams(
if (value.type.kind === "Model") {
collectParams(value.type.properties, params);
} else {
let sourceProp = value;
while (sourceProp.sourceProperty) {
sourceProp = sourceProp.sourceProperty;
}
if (sourceProp.model && !isAzureCoreTspModel(sourceProp.model)) {
params.push(value);
} else if (!sourceProp.model) {
params.push(value);
} else {
// eslint-disable-next-line no-console
console.log(
`We are not counting "${sourceProp.name}" as part of a method parameter because it's been added by Azure.Core templates`,
);
}
params.push(findRootSourceProperty(value));
}
}
});
Expand Down
175 changes: 86 additions & 89 deletions packages/typespec-client-generator-core/src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import {
TCGCContext,
} from "./interfaces.js";
import {
findRootSourceProperty,
getAvailableApiVersions,
getHttpBodySpreadModel,
getHttpOperationResponseHeaders,
Expand Down Expand Up @@ -337,84 +338,88 @@ export function getSdkHttpParameter(
location?: "path" | "query" | "header" | "body" | "cookie",
): [SdkHttpParameter, readonly Diagnostic[]] {
const diagnostics = createDiagnosticCollector();
const base = diagnostics.pipe(getSdkModelPropertyTypeBase(context, param, operation));
const program = context.program;
const correspondingMethodParams: SdkParameter[] = []; // we set it later in the operation
if (isPathParam(context.program, param) || location === "path") {
// we don't url encode if the type can be assigned to url
const urlEncode = !ignoreDiagnostics(
program.checker.isTypeAssignableTo(
// TODO: THIS NEED TO BE MIGRATED BY MARCH 2024 release.
// eslint-disable-next-line @typescript-eslint/no-deprecated
param.type.projectionBase ?? param.type,
program.checker.getStdType("url"),
param.type,
),
);
return diagnostics.wrap({
...base,
kind: "path",
urlEncode,
explode: (httpParam as HttpOperationPathParameter)?.explode ?? false,
style: (httpParam as HttpOperationPathParameter)?.style ?? "simple",
allowReserved: (httpParam as HttpOperationPathParameter)?.allowReserved ?? false,
serializedName: getPathParamName(program, param) ?? base.name,
correspondingMethodParams,
optional: false,
});
}
if (isCookieParam(context.program, param) || location === "cookie") {
return diagnostics.wrap({
...base,
kind: "cookie",
serializedName: getCookieParamOptions(program, param)?.name ?? base.name,
correspondingMethodParams,
optional: param.optional,
});
}
if (isBody(context.program, param) || location === "body") {
return diagnostics.wrap({
...base,
kind: "body",
serializedName: param.name === "" ? "body" : getWireName(context, param),
contentTypes: ["application/json"], // will update when we get to the operation level
defaultContentType: "application/json", // will update when we get to the operation level
optional: param.optional,
correspondingMethodParams,
});
}
const headerQueryBase = {
...base,
optional: param.optional,
collectionFormat: getCollectionFormat(context, param),
correspondingMethodParams,
};
if (isQueryParam(context.program, param) || location === "query") {
return diagnostics.wrap({
...headerQueryBase,
kind: "query",
serializedName: getQueryParamName(program, param) ?? base.name,
explode: (httpParam as HttpOperationQueryParameter)?.explode,
});
}
if (!(isHeader(context.program, param) || location === "header")) {
diagnostics.add(
createDiagnostic({
code: "unexpected-http-param-type",
target: param,
format: {
paramName: param.name,
expectedType: "path, query, header, or body",
actualType: param.kind,
},
}),
);
let parameter = context.__httpParameterCache?.get(param);

if (!parameter) {
const base = diagnostics.pipe(getSdkModelPropertyTypeBase(context, param, operation));
const program = context.program;
const correspondingMethodParams: SdkParameter[] = []; // we set it later in the operation
if (isPathParam(context.program, param) || location === "path") {
// we don't url encode if the type can be assigned to url
const urlEncode = !ignoreDiagnostics(
program.checker.isTypeAssignableTo(
// TODO: THIS NEED TO BE MIGRATED BY MARCH 2024 release.
// eslint-disable-next-line @typescript-eslint/no-deprecated
param.type.projectionBase ?? param.type,
program.checker.getStdType("url"),
param.type,
),
);
parameter = {
...base,
kind: "path",
urlEncode,
explode: (httpParam as HttpOperationPathParameter)?.explode ?? false,
style: (httpParam as HttpOperationPathParameter)?.style ?? "simple",
allowReserved: (httpParam as HttpOperationPathParameter)?.allowReserved ?? false,
serializedName: getPathParamName(program, param) ?? base.name,
correspondingMethodParams,
optional: false,
};
} else if (isCookieParam(context.program, param) || location === "cookie") {
parameter = {
...base,
kind: "cookie",
serializedName: getCookieParamOptions(program, param)?.name ?? base.name,
correspondingMethodParams,
optional: param.optional,
};
} else if (isBody(context.program, param) || location === "body") {
parameter = {
...base,
kind: "body",
serializedName: param.name === "" ? "body" : getWireName(context, param),
contentTypes: ["application/json"], // will update when we get to the operation level
defaultContentType: "application/json", // will update when we get to the operation level
optional: param.optional,
correspondingMethodParams,
};
} else if (isQueryParam(context.program, param) || location === "query") {
parameter = {
...base,
optional: param.optional,
collectionFormat: getCollectionFormat(context, param),
correspondingMethodParams,
kind: "query",
serializedName: getQueryParamName(program, param) ?? base.name,
explode: (httpParam as HttpOperationQueryParameter)?.explode,
};
} else {
if (!(isHeader(context.program, param) || location === "header")) {
diagnostics.add(
createDiagnostic({
code: "unexpected-http-param-type",
target: param,
format: {
paramName: param.name,
expectedType: "path, query, header, or body",
actualType: param.kind,
},
}),
);
}
parameter = {
...base,
optional: param.optional,
collectionFormat: getCollectionFormat(context, param),
correspondingMethodParams,
kind: "header",
serializedName: getHeaderFieldName(program, param) ?? base.name,
};
}
context.__httpParameterCache.set(param, parameter);
}
return diagnostics.wrap({
...headerQueryBase,
kind: "header",
serializedName: getHeaderFieldName(program, param) ?? base.name,
});
return diagnostics.wrap(parameter);
}

function getSdkHttpResponseAndExceptions(
Expand All @@ -441,14 +446,13 @@ function getSdkHttpResponseAndExceptions(
: innerResponse.body?.contentTypes[0];
for (const header of getHttpOperationResponseHeaders(innerResponse)) {
if (isNeverOrVoidType(header.type)) continue;
const clientType = diagnostics.pipe(getClientTypeWithDiagnostics(context, header.type));
addEncodeInfo(context, header, clientType, defaultContentType);
headers.push({
...diagnostics.pipe(
getSdkModelPropertyTypeBase(context, header, httpOperation.operation),
),
__raw: header,
doc: getDoc(context.program, header),
summary: getSummary(context.program, header),
kind: "responseheader",
serializedName: getHeaderFieldName(context.program, header),
type: clientType,
});
}
if (innerResponse.body && !isNeverOrVoidType(innerResponse.body.type)) {
Expand Down Expand Up @@ -693,13 +697,6 @@ function filterOutUselessPathParameters(
}
}

function findRootSourceProperty(property: ModelProperty): ModelProperty {
while (property.sourceProperty) {
property = property.sourceProperty;
}
return property;
}

function getCollectionFormat(
context: TCGCContext,
type: ModelProperty,
Expand Down
Loading
Loading