Skip to content
This repository was archived by the owner on Jun 30, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 6 commits
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
2 changes: 1 addition & 1 deletion packages/typespec-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"@typespec/spector": "0.1.0-alpha.24-dev.2",
"@typespec/spec-api": "0.1.0-dev.0",
"@typespec/tspd": "0.74.0",
"@azure-tools/azure-http-specs": "0.1.0-alpha.38-dev.2",
"@azure-tools/azure-http-specs": "0.1.0-alpha.38-dev.4",
"@azure-tools/typespec-autorest": "^0.65.0",
"@azure-tools/typespec-azure-core": "^0.65.0",
"@azure-tools/typespec-azure-resource-manager": "^0.65.0",
Expand Down
5 changes: 5 additions & 0 deletions packages/typespec-ts/src/modular/helpers/operationHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1951,6 +1951,11 @@ function getSerializationExpressionForFlatten(
!isReadOnly(p) &&
!isMetadata(context.program, p.__raw!)
);
// If all properties in the flattened model are read-only, omit the field entirely
// so it is not included in the serialized request body.
if (validProps.length === 0) {
return `undefined`;
}
const optionalPrefix = property.optional
? `${resolveReference(SerializationHelpers.areAllPropsUndefined)}(${propertyPath}, [${validProps
.map((p) => `"${p.name}"`)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -502,9 +502,26 @@ function buildModelTypeSerializer(
return ${serializeContent}
`);
} else {
output.push(`
return item;
`);
// For flatten properties, if all properties are readonly, return empty object
// Otherwise, return the item itself
if (options.flatten) {
// Change parameter name to _item to indicate it's intentionally unused
serializerFunction.parameters = [
{
name: "_item",
type: options.flatten
? resolveReference(refkey(options.flatten.baseModel))
: resolveReference(refkey(type))
}
];
output.push(`
return {};
`);
} else {
output.push(`
return item;
`);
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For flatten serializer, shouldn’t return item.

Image

}
serializerFunction.statements = output;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ export declare type FlattenPropertyClient = Client & {
export declare interface FlattenPropertyClientOptions extends ClientOptions {
}

export declare interface FlattenUnknownModel {
name: string;
properties?: unknown;
}

export declare interface FlattenUnknownModelOutput {
name: string;
properties?: any;
}

export declare interface NestedFlattenModel {
name: string;
properties: ChildFlattenModel;
Expand All @@ -69,6 +79,36 @@ export declare interface PutFlattenModelBodyParam {

export declare type PutFlattenModelParameters = PutFlattenModelBodyParam & RequestParameters;

export declare interface PutFlattenReadOnlyModel {
put(options: PutFlattenReadOnlyModelParameters): StreamableMethod<PutFlattenReadOnlyModel200Response>;
}

export declare interface PutFlattenReadOnlyModel200Response extends HttpResponse {
status: "200";
body: SolutionOutput;
}

export declare interface PutFlattenReadOnlyModelBodyParam {
body: Solution;
}

export declare type PutFlattenReadOnlyModelParameters = PutFlattenReadOnlyModelBodyParam & RequestParameters;

export declare interface PutFlattenUnknownModel {
put(options: PutFlattenUnknownModelParameters): StreamableMethod<PutFlattenUnknownModel200Response>;
}

export declare interface PutFlattenUnknownModel200Response extends HttpResponse {
status: "200";
body: FlattenUnknownModelOutput;
}

export declare interface PutFlattenUnknownModelBodyParam {
body: FlattenUnknownModel;
}

export declare type PutFlattenUnknownModelParameters = PutFlattenUnknownModelBodyParam & RequestParameters;

export declare interface PutNestedFlattenModel {
put(options: PutNestedFlattenModelParameters): StreamableMethod<PutNestedFlattenModel200Response>;
}
Expand All @@ -87,6 +127,29 @@ export declare type PutNestedFlattenModelParameters = PutNestedFlattenModelBodyP
export declare interface Routes {
(path: "/azure/client-generator-core/flatten-property/flattenModel"): PutFlattenModel;
(path: "/azure/client-generator-core/flatten-property/nestedFlattenModel"): PutNestedFlattenModel;
(path: "/azure/client-generator-core/flatten-property/flattenUnknownModel"): PutFlattenUnknownModel;
(path: "/azure/client-generator-core/flatten-property/flattenReadOnlyModel"): PutFlattenReadOnlyModel;
}

export declare interface Solution {
name: string;
properties: SolutionProperties;
propertiesOptional?: SolutionProperties;
}

export declare interface SolutionOutput {
name: string;
properties: SolutionPropertiesOutput;
propertiesOptional?: SolutionPropertiesOutput;
}

export declare interface SolutionProperties {
}

export declare interface SolutionPropertiesOutput {
readonly solutionId?: string;
readonly title?: string;
readonly content?: string;
}

export { }
33 changes: 33 additions & 0 deletions packages/typespec-ts/test/azureIntegration/modelFlatten.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,37 @@ describe("Flatten Property Rest Client", () => {
assert.strictEqual(result.body.properties.properties.description, "foo");
assert.strictEqual(result.body.properties.properties.age, 1);
});

it("should update and receive model with unknown flatten property", async () => {
const result = await client
.path("/azure/client-generator-core/flatten-property/flattenUnknownModel")
.put({
body: {
name: "foo"
}
});
assert.strictEqual(result.status, "200");
assert.strictEqual(result.body.name, "test");
assert.deepEqual(result.body.properties, {
key1: "value1",
key2: "value2"
});
});

it("should update and receive model with all readonly flatten properties", async () => {
const result = await client
.path(
"/azure/client-generator-core/flatten-property/flattenReadOnlyModel"
)
.put({
body: {
name: "foo"
} as any
});
assert.strictEqual(result.status, "200");
assert.strictEqual(result.body.name, "foo");
assert.strictEqual((result.body as any).solutionId, "solution1");
assert.strictEqual((result.body as any).title, "Solution Title");
assert.strictEqual((result.body as any).content, "Solution Content");
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,20 @@ export declare class FlattenPropertyClient {
private _client;
readonly pipeline: Pipeline;
constructor(options?: FlattenPropertyClientOptionalParams);
putFlattenReadOnlyModel(body: Solution, options?: PutFlattenReadOnlyModelOptionalParams): Promise<Solution>;
putFlattenUnknownModel(input: FlattenUnknownModel, options?: PutFlattenUnknownModelOptionalParams): Promise<FlattenUnknownModel>;
putNestedFlattenModel(input: NestedFlattenModel, options?: PutNestedFlattenModelOptionalParams): Promise<NestedFlattenModel>;
putFlattenModel(input: FlattenModel, options?: PutFlattenModelOptionalParams): Promise<FlattenModel>;
}

export declare interface FlattenPropertyClientOptionalParams extends ClientOptions {
}

export declare interface FlattenUnknownModel {
name: string;
properties?: any;
}

export declare interface NestedFlattenModel {
name: string;
summary: string;
Expand All @@ -39,7 +46,29 @@ export declare interface NestedFlattenModel {
export declare interface PutFlattenModelOptionalParams extends OperationOptions {
}

export declare interface PutFlattenReadOnlyModelOptionalParams extends OperationOptions {
}

export declare interface PutFlattenUnknownModelOptionalParams extends OperationOptions {
}

export declare interface PutNestedFlattenModelOptionalParams extends OperationOptions {
}

export declare interface Solution {
name: string;
readonly solutionId?: string;
readonly title?: string;
readonly content?: string;
readonly solutionIdPropertiesOptionalSolutionId?: string;
readonly titlePropertiesOptionalTitle?: string;
readonly contentPropertiesOptionalContent?: string;
}

export declare interface SolutionProperties {
readonly solutionId?: string;
readonly title?: string;
readonly content?: string;
}

export { }
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,23 @@ describe("Property Flatten Client", () => {
assert.strictEqual(result.properties.description, "foo");
assert.strictEqual(result.properties.age, 1);
});

it("Update and receive model with unknown properties flattening", async () => {
const result = await client.putFlattenUnknownModel({
name: "foo"
});
assert.strictEqual(result.name, "test");
assert.strictEqual(result.properties?.key1, "value1");
assert.strictEqual(result.properties?.key2, "value2");
});

it("Update and receive model with read-only properties flattening", async () => {
const result = await client.putFlattenReadOnlyModel({
name: "foo"
});
assert.strictEqual(result.name, "foo");
assert.strictEqual(result.solutionId, "solution1");
assert.strictEqual(result.title, "Solution Title");
assert.strictEqual(result.content, "Solution Content");
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ needTCGC: true
## Models

```ts models
import { areAllPropsUndefined } from "../static-helpers/serialization/check-prop-undefined.js";

/**
* This file contains only generated model types and their (de)serializers.
* Disable the following rules for internal models with '_' prefix and deserializers which require 'any' for raw JSON input.
Expand All @@ -54,12 +52,7 @@ export interface Solution {
}

export function solutionSerializer(item: Solution): any {
return {
properties: _solutionPropertiesSerializer(item),
propertiesOptional: areAllPropsUndefined(item, [])
? undefined
: _solutionPropertiesOptionalSerializer(item),
};
return { properties: undefined, propertiesOptional: undefined };
Comment thread
v-jiaodi marked this conversation as resolved.
Outdated
}

/** model interface SolutionProperties */
Expand All @@ -73,11 +66,11 @@ export function solutionPropertiesSerializer(item: SolutionProperties): any {
return item;
}

export function _solutionPropertiesSerializer(item: Solution): any {
return item;
export function _solutionPropertiesSerializer(_item: Solution): any {
return {};
}

export function _solutionPropertiesOptionalSerializer(item: Solution): any {
return item;
export function _solutionPropertiesOptionalSerializer(_item: Solution): any {
return {};
}
```
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

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

Loading