Skip to content

Commit 081681a

Browse files
fix: multi-level @Legacy.flattenProperty generates incorrect sample code (Azure#3831)
When multiple @Legacy.flattenProperty decorators are applied at different nesting levels connected through non-flatten properties, the sample generator only applied the outer-level flatten. The inner flatten remained as a nested object, causing TS2353 compile errors. Root cause: enableFlatten:false set when processing a flattened property leaked through the else branch (non-flatten properties) to all deeper levels, blocking independent inner flatten operations. Fix: In the else branch, strip enableFlatten:false from options before recursing deeper. This keeps consecutive/transition flatten blocked at the direct child level while allowing independent multi-level flattens to work. Fixes Azure#3828 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a0ba72b commit 081681a

2 files changed

Lines changed: 114 additions & 1 deletion

File tree

packages/typespec-ts/src/modular/emitSamples.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,9 +627,15 @@ function getParameterValue(
627627
propRetValue =
628628
paramValue.length > 2 ? paramValue.slice(1, -1) : undefined;
629629
} else {
630+
// Don't propagate enableFlatten:false to deeper levels — it's only
631+
// meant to block consecutive (transition) flatten at the direct child
632+
// level. Non-flatten properties should recurse with default behavior
633+
// so that independent inner flattens at deeper levels still work.
634+
const childOptions =
635+
options?.overrides?.enableFlatten === false ? undefined : options;
630636
propRetValue =
631637
`"${mapper.get(propName) ?? propName}": ` +
632-
getParameterValue(context, propValue, options);
638+
getParameterValue(context, propValue, childOptions);
633639
}
634640
if (propRetValue) values.push(propRetValue);
635641
}

packages/typespec-ts/test/modularUnit/scenarios/samples/propertyFlatten/mulipleFlattenCases.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,5 +151,112 @@ async function main(): Promise<void> {
151151
await read();
152152
}
153153

154+
main().catch(console.error);
155+
```
156+
157+
# Independent multi-level flatten should work for sample input
158+
159+
When two flatten decorators are at different levels connected through a non-flatten property
160+
(not consecutive/transition), the sample generator should apply both flattens independently.
161+
162+
## TypeSpec
163+
164+
This is tsp definition.
165+
166+
```tsp
167+
model InnerContent {
168+
state?: string;
169+
scrubbingRules?: string;
170+
}
171+
172+
model MiddleSettings {
173+
@Azure.ClientGenerator.Core.Legacy.flattenProperty
174+
innerContent?: InnerContent;
175+
}
176+
177+
model OuterProperties {
178+
settings?: MiddleSettings;
179+
description?: string;
180+
}
181+
182+
@doc("This is a simple model.")
183+
model BodyParameter {
184+
name: string;
185+
186+
@Azure.ClientGenerator.Core.Legacy.flattenProperty
187+
properties: OuterProperties;
188+
}
189+
190+
@doc("show example demo")
191+
op read(@body body?: BodyParameter): void;
192+
193+
```
194+
195+
Enable the raw content with TCGC dependency.
196+
197+
```yaml
198+
needArmTemplate: true
199+
withVersionedApiVersion: true
200+
needTCGC: true
201+
```
202+
203+
## Example
204+
205+
Raw json files.
206+
207+
```json
208+
{
209+
"title": "read",
210+
"operationId": "read",
211+
"parameters": {
212+
"body": {
213+
"name": "test",
214+
"properties": {
215+
"settings": {
216+
"innerContent": {
217+
"state": "Enabled",
218+
"scrubbingRules": "rule1"
219+
}
220+
},
221+
"description": "a description"
222+
}
223+
}
224+
},
225+
"responses": {
226+
"200": {}
227+
}
228+
}
229+
```
230+
231+
## Samples
232+
233+
Generate sample with both flatten levels applied:
234+
235+
```ts samples
236+
/** This file path is /samples-dev/readSample.ts */
237+
import { TestingClient } from "@azure/internal-test";
238+
239+
/**
240+
* This sample demonstrates how to show example demo
241+
*
242+
* @summary show example demo
243+
* x-ms-original-file: 2021-10-01-preview/json.json
244+
*/
245+
async function read(): Promise<void> {
246+
const endpoint = process.env.TESTING_ENDPOINT || "";
247+
const client = new TestingClient(endpoint);
248+
await client.read({
249+
body: {
250+
name: "test",
251+
settings: { state: "Enabled", scrubbingRules: "rule1" },
252+
description: "a description",
253+
},
254+
});
255+
}
256+
257+
async function main(): Promise<void> {
258+
await read();
259+
}
260+
154261
main().catch(console.error);
155262
```

0 commit comments

Comments
 (0)