Skip to content

Commit b166149

Browse files
tadeleshCopilottadeleshCopilot
authored
Backmerge release/may-2026 (tcgc@0.68.2 hotfix) (#4489)
Backmerge of hotfix release tcgc@0.69.0 from `release/may-2026` into `main`. This ensures the version bump and fixes are reflected in main. ⚠️ **Rebase merge** this PR (do not squash). --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: tadelesh <1726438+tadelesh@users.noreply.github.com> Co-authored-by: tadelesh <chenjieshi@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 7181847 commit b166149

14 files changed

Lines changed: 318 additions & 9 deletions

File tree

packages/typespec-client-generator-core/CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# Change Log - @azure-tools/typespec-client-generator-core
22

3+
## 0.68.2
4+
5+
### Features
6+
7+
- [#4480](https://github.com/Azure/typespec-azure/pull/4480) Extend `isExactName` to additional SDK types whose names can be changed by `@clientName`: `SdkClientType`, `SdkServiceMethodBase` (and its derived method kinds), and `SdkEnumValueType`. Also fixed `SdkClientType.name` to strip the internal `exact()` marker.
8+
9+
### Bug Fixes
10+
11+
- [#4477](https://github.com/Azure/typespec-azure/pull/4477) Fix `reorderParameters`, `addParameter`, `removeParameter`, and `replaceParameter` so that decorators copied to cloned model properties and cloned operations are applied (by calling `finishType` after cloning). This fixes scenarios such as parameters with `@typeChangedFrom` under a `@versioned` service.
12+
- [#4487](https://github.com/Azure/typespec-azure/pull/4487) Fix example value matching for `decimal` and `decimal128` typed properties. JSON `number` values in example files are now correctly recognized as matching `decimal` / `decimal128` typed properties.
13+
- [#4484](https://github.com/Azure/typespec-azure/pull/4484) Fix example values being dropped on subtypes added via `@hierarchyBuilding` by propagating serialization options from the nearest ancestor to the newly added subtype
14+
15+
316
## 0.68.1
417

518
### Bug Fixes

packages/typespec-client-generator-core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@azure-tools/typespec-client-generator-core",
3-
"version": "0.68.1",
3+
"version": "0.68.2",
44
"author": "Microsoft Corporation",
55
"description": "TypeSpec Data Plane Generation library",
66
"homepage": "https://azure.github.io/typespec-azure",

packages/typespec-client-generator-core/src/clients.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import {
3333
} from "./internal-utils.js";
3434
import { createDiagnostic } from "./lib.js";
3535
import { createSdkMethods, getSdkMethodParameter } from "./methods.js";
36-
import { getCrossLanguageDefinitionId } from "./public-utils.js";
36+
import { getCrossLanguageDefinitionId, getLibraryName, isExactClientName } from "./public-utils.js";
3737
import { getSdkBuiltInType, getSdkCredentialParameter, getTypeSpecBuiltInType } from "./types.js";
3838

3939
function getEndpointTypeFromSingleServer<
@@ -190,17 +190,15 @@ export function createSdkClientType<TServiceOperation extends SdkServiceOperatio
190190
): [SdkClientType<TServiceOperation>, readonly Diagnostic[]] {
191191
const diagnostics = createDiagnosticCollector();
192192
let name = client.name;
193-
if (client.type) {
194-
const override = getClientNameOverride(context, client.type);
195-
if (override) {
196-
name = override;
197-
}
193+
if (client.type && getClientNameOverride(context, client.type)) {
194+
name = getLibraryName(context, client.type);
198195
}
199196
const clientType = getActualClientType(client);
200197
const sdkClientType: SdkClientType<TServiceOperation> = {
201198
__raw: client,
202199
kind: "client",
203200
name,
201+
isExactName: client.type ? isExactClientName(context, client.type) : false,
204202
doc: client.type ? getClientDoc(context, client.type) : undefined,
205203
summary: client.type ? getSummary(context.program, client.type) : undefined,
206204
methods: [],

packages/typespec-client-generator-core/src/example.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
SdkServiceOperation,
3232
SdkType,
3333
TCGCContext,
34+
isSdkFixedPointKind,
3435
isSdkFloatKind,
3536
isSdkIntKind,
3637
} from "./interfaces.js";
@@ -446,7 +447,7 @@ function getSdkTypeExample(
446447
return diagnostics.wrap(undefined);
447448
}
448449

449-
if (isSdkIntKind(type.kind) || isSdkFloatKind(type.kind)) {
450+
if (isSdkIntKind(type.kind) || isSdkFloatKind(type.kind) || isSdkFixedPointKind(type.kind)) {
450451
return getSdkBaseTypeExample("number", type as SdkType, example, relativePath);
451452
} else {
452453
switch (type.kind) {

packages/typespec-client-generator-core/src/functions.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ function cloneOperation(
2020
// Copy decorators from the original operation
2121
if (operation.decorators) {
2222
newOp.decorators = [...operation.decorators];
23+
// Re-finish the type so the copied decorators are applied
24+
tk.type.finishType(newOp);
2325
}
2426

2527
// Set the source operation for tracing
@@ -40,6 +42,8 @@ function cloneModelProperty(tk: ReturnType<typeof $>, prop: ModelProperty): Mode
4042
if (prop.decorators) {
4143
clonedProp.decorators = [...prop.decorators];
4244
}
45+
// Finish the type so decorators are applied
46+
tk.type.finishType(clonedProp);
4347
return clonedProp;
4448
}
4549

packages/typespec-client-generator-core/src/interfaces.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ export interface SdkClientType<
208208
kind: "client";
209209
/** Name of the client. */
210210
name: string;
211+
/** Whether name should be used exactly as-is, without casing transformations. */
212+
isExactName: boolean;
211213
/** Full qualified namespace. */
212214
namespace: string;
213215
/** Document for the type. */
@@ -373,7 +375,7 @@ export function isSdkFloatKind(kind: string): kind is keyof typeof SdkFloatingPo
373375
return kind in SdkFloatingPointKindsEnum;
374376
}
375377

376-
function isSdkFixedPointKind(kind: string): kind is keyof typeof SdkFixedPointKindsEnum {
378+
export function isSdkFixedPointKind(kind: string): kind is keyof typeof SdkFixedPointKindsEnum {
377379
return kind in SdkFixedPointKindsEnum;
378380
}
379381

@@ -480,6 +482,8 @@ export interface SdkEnumValueType<
480482
> extends SdkTypeBase {
481483
kind: "enumvalue";
482484
name: string;
485+
/** Whether name should be used exactly as-is, without casing transformations. */
486+
isExactName: boolean;
483487
value: string | number;
484488
enumType: SdkEnumType;
485489
valueType: TValueType;
@@ -1000,6 +1004,8 @@ interface SdkServiceMethodBase<
10001004
> extends DecoratedType {
10011005
__raw?: Operation;
10021006
name: string;
1007+
/** Whether name should be used exactly as-is, without casing transformations. */
1008+
isExactName: boolean;
10031009
/** Whether the type has public or private accessibility */
10041010
access: AccessFlags;
10051011
/** API versions supported for current type. */

packages/typespec-client-generator-core/src/methods.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ import {
8080
getCrossLanguageDefinitionId,
8181
getHttpOperationWithCache,
8282
getLibraryName,
83+
isExactClientName,
8384
} from "./public-utils.js";
8485
import {
8586
getClientTypeWithDiagnostics,
@@ -736,6 +737,7 @@ export function getSdkBasicServiceMethod<TServiceOperation extends SdkServiceOpe
736737
__raw: operation,
737738
kind: "basic",
738739
name,
740+
isExactName: isExactClientName(context, operation),
739741
access: getAccess(context, operation) ?? "public",
740742
parameters: methodParameters,
741743
doc: getClientDoc(context, operation),

packages/typespec-client-generator-core/src/types.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,7 @@ function getSdkEnumValueWithDiagnostics(
10181018
return diagnostics.wrap({
10191019
...diagnostics.pipe(getSdkTypeBaseHelper(context, type, "enumvalue")),
10201020
name: getLibraryName(context, type),
1021+
isExactName: isExactClientName(context, type),
10211022
value: type.value ?? type.name,
10221023
enumType,
10231024
valueType: enumType.valueType,
@@ -1081,6 +1082,7 @@ function getSdkUnionEnumValues(
10811082
values.push({
10821083
...diagnostics.pipe(getSdkTypeBaseHelper(context, member.type, "enumvalue")),
10831084
name: name ? name : `${member.value}`,
1085+
isExactName: isExactClientName(context, member.type),
10841086
value: member.value,
10851087
valueType: enumType.valueType,
10861088
enumType,
@@ -2110,6 +2112,11 @@ function handleLegacyHierarchyBuilding(context: TCGCContext): [void, readonly Di
21102112
currBaseModel = currBaseModel.baseModel;
21112113
}
21122114

2115+
// Propagate serialization options to the newly added subtype.
2116+
// This is needed because updateSerializationOptions may have already run
2117+
// on the parent model before this subtype was added to discriminatedSubtypes.
2118+
propagateSerializationToSubtype(context, sdkType);
2119+
21132120
// Filter out legacy hierarchy building properties
21142121
sdkType.properties = sdkType.properties.filter((property) => {
21152122
return (
@@ -2121,6 +2128,31 @@ function handleLegacyHierarchyBuilding(context: TCGCContext): [void, readonly Di
21212128
return diagnostics.wrap(undefined);
21222129
}
21232130

2131+
/**
2132+
* Propagate serialization options from a parent model to a newly added subtype.
2133+
* This handles the case where updateSerializationOptions already ran on the parent
2134+
* before the subtype was added via @hierarchyBuilding.
2135+
*/
2136+
function propagateSerializationToSubtype(context: TCGCContext, sdkType: SdkModelType): void {
2137+
// Find the nearest ancestor with serialization options to determine content types
2138+
let ancestor: SdkModelType | undefined = sdkType.baseModel;
2139+
const contentTypes: string[] = [];
2140+
while (ancestor) {
2141+
if (ancestor.serializationOptions.json) {
2142+
contentTypes.push("application/json");
2143+
}
2144+
if (ancestor.serializationOptions.xml) {
2145+
contentTypes.push("application/xml");
2146+
}
2147+
if (contentTypes.length > 0) break;
2148+
ancestor = ancestor.baseModel;
2149+
}
2150+
2151+
if (contentTypes.length > 0) {
2152+
updateSerializationOptions(context, sdkType, contentTypes);
2153+
}
2154+
}
2155+
21242156
/**
21252157
* Reconcile properties on a rebased model after `@hierarchyBuilding(oldBase, newBase)`.
21262158
*
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"operationId": "getDecimal",
3+
"title": "getDecimal",
4+
"parameters": {},
5+
"responses": {
6+
"200": {
7+
"body": 123.45
8+
}
9+
}
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"operationId": "getDecimal128",
3+
"title": "getDecimal128",
4+
"parameters": {},
5+
"responses": {
6+
"200": {
7+
"body": 80
8+
}
9+
}
10+
}

0 commit comments

Comments
 (0)