Skip to content

Fix: model array responses return directly (no body wrapper) when wrap-non-model-return is enabled#3856

Merged
MaryGao merged 17 commits intomainfrom
copilot/migration-tsp-model-array-fix
Mar 27, 2026
Merged

Fix: model array responses return directly (no body wrapper) when wrap-non-model-return is enabled#3856
MaryGao merged 17 commits intomainfrom
copilot/migration-tsp-model-array-fix

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 19, 2026

  • Adjust shouldWrap to return false for model arrays (HLC PropertyKind.Composite → no wrapper)
  • Update unit test scenario in wrapNonModelReturn.md
  • Update integration spec files (arrayItemTypes.spec.ts, azureClientOverload.spec.ts)
  • Regenerate azure-modular generated .d.ts files
  • Run smoke test and fix all failures: regenerated parametrizedHost and widget_dpg generated TypeScript files
  • Add detailed case-by-case comments in checkWrapNonModelReturn documenting HLC→modular mappings
    • Binary bytes → binary wrap
    • Model array (Foo[]) → PropertyKind.Composite → no wrap
    • dict/Record → PropertyKind.Dictionary → no wrap
    • model → PropertyKind.Composite → no wrap
    • Remaining (string, boolean, string[], any, enum) → PropertyKind.Primitive/Enum → wrap with body

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>
Copilot AI changed the title [WIP] [migration tsp] Fix model array response breakings during tsp migration Fix: model array responses return T[] directly instead of { body: T[] } when wrap-non-model-return is enabled Mar 19, 2026
Copilot AI requested a review from v-jiaodi March 19, 2026 09:16
@v-jiaodi
Copy link
Copy Markdown
Member

@copilot for unknown model , should generate xxxResponse = Record<string, unknown>; rather than xxxResponse = { body: any; };

… behavior

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 20, 2026

@copilot for unknown model , should generate xxxResponse = Record<string, unknown>; rather than xxxResponse = { body: any; };

Fixed in commit 3038f36. When wrap-non-model-return: true and the response type is unknown, the emitter now generates Record<string, unknown> as the type alias and returns result.body directly from the deserializer — matching HLC behavior.

Copilot AI changed the title Fix: model array responses return T[] directly instead of { body: T[] } when wrap-non-model-return is enabled Fix: model array and unknown responses match HLC behavior when wrap-non-model-return is enabled Mar 20, 2026
Comment thread packages/typespec-ts/test/modularUnit/scenarios/operations/wrapNonModelReturn.md Outdated
Copilot AI requested a review from v-jiaodi March 23, 2026 05:21
@v-jiaodi
Copy link
Copy Markdown
Member

@copilot fix smoke ci error and integration test ci error.

@v-jiaodi
Copy link
Copy Markdown
Member

@copilot fix smoke ci error and integration test ci error.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 23, 2026

@copilot fix smoke ci error and integration test ci error.

Fixed in commit 9434ce2. Updated the three failing spec files and regenerated the affected generated declaration files:

  • arrayItemTypes.spec.ts: modelValue.get() now returns InnerModel[] directly (removed .body)
  • azureClientOverload.spec.ts: list() and listByScope() now return Resource[] directly (removed .body)
  • scalar.spec.ts: unknown.get() now returns Record<string, unknown> directly (removed .body)

All 894 azure-modular integration tests pass.

export function checkWrapNonModelReturn(
context: SdkContext,
operation: ServiceOperation
): { shouldWrap: boolean; isBinary: boolean } {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we don't need to maitain XXXResponse for model array and any object, so we could only adjust shouldWrap contiditon.

Copy link
Copy Markdown
Member

@v-jiaodi v-jiaodi Mar 26, 2026

Choose a reason for hiding this comment

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

@copilot revert src and ut files change. Apply a fix as described below:
confirmed the logic in HLC we would only wrap with body when the type is not PropertyKind.Composite or PropertyKind.Dictionary and for array type its kind is from its array item.

const hasBodyProperty =
bodyType?.kind !== PropertyKind.Composite &&
bodyType?.kind !== PropertyKind.Dictionary;

So the mapping is:

  • string → PropertyKind.Primitive -> wrapper
  • boolean → PropertyKind.Primitive -> wrapper
  • string[] → PropertyKind.Primitive (array keeps item kind) -> wrapper
  • any → PropertyKind.Primitive -> wrapper
  • enum → PropertyKind.Enum -> wrapper
  • model array (Foo[]) → PropertyKind.Composite (array keeps item kind from Foo) -> no wrapper
  • any object (SchemaType.AnyObject) → PropertyKind.Dictionary -> no wrapper

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in commit 91cd9bc. Reverted operationHelpers.ts and emitModels.ts to main's approach (no isModelArray/isUnknown flags), and applied the fix solely by adjusting shouldWrap: added a single condition in checkWrapNonModelReturn to return noWrap when type.kind === "array" && type.valueType.kind === "model" (matching HLC's PropertyKind.Composite → no body wrapper). The unknown case now correctly keeps shouldWrap=true (PropertyKind.Primitive → wrapper with body).


// Check if it's an unknown type (free-form object)
// These are returned as Record<string, unknown> directly to match HLC behavior
if (type.kind === "unknown") {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this would be impacted by our feature flag #3858.

by default unknown would be translated as any so shouldWrap would be false.

Copilot AI changed the title Fix: model array and unknown responses match HLC behavior when wrap-non-model-return is enabled Fix: model array responses return directly (no body wrapper) when wrap-non-model-return is enabled Mar 26, 2026
@v-jiaodi
Copy link
Copy Markdown
Member

@copilot run pnpm smoke-test to fix ci under typespec-test folder

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 26, 2026

@copilot run pnpm smoke-test to fix ci under typespec-test folder

Done in commit 3dfa90c. Ran the smoke test and regenerated the affected generated files for parametrizedHost and widget_dpg:

  • Removed ConfidentialLedgerListCollectionsResponse, BudgetsGetBudgetsResponse, SAPWidgetsSAPListWidgetsResponse type aliases
  • Operations now return model arrays directly (Collection[], Widget[])
  • Updated classic interface files, index re-exports, and api.md review files

All smoke tests pass ("All specs succeeded!").

@JialinHuang803
Copy link
Copy Markdown
Member

Should we include the Record case as well #3864?

Comment thread packages/typespec-ts/src/modular/helpers/operationHelpers.ts Outdated
@MaryGao
Copy link
Copy Markdown
Member

MaryGao commented Mar 27, 2026

Should we include the Record case as well #3864?

The Record is already included in existing cases, the above issue we notice is because we treat unknown as any, it would fit into a wrapper case.

We have a fix #3869 to treat unknown as any object which is the same as hlc handling, after that fix, the Record breaking would be fixed automactially.

Copilot AI requested a review from MaryGao March 27, 2026 03:19
@MaryGao MaryGao merged commit 3e68f57 into main Mar 27, 2026
16 checks passed
@MaryGao MaryGao deleted the copilot/migration-tsp-model-array-fix branch March 27, 2026 05:49
Copilot AI added a commit that referenced this pull request Mar 27, 2026
… from main

Regenerated 6 scenarios (NetworkAnalytics.Management, healthInsights_radiologyinsights,
loadtesting_modular, nestedClient, openai_modular, schemaRegistry) that were affected
by the merge with main branch (PR #3856: model array responses fix). This ensures
the check:tree CI step passes.

Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/47b50ca2-9eda-4d7f-8560-c906ba14c70f

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>
MaryGao added a commit that referenced this pull request Mar 30, 2026
…r leading-digit identifiers (#3868)

* Initial plan

* Fix enum member names: use enum type name as prefix instead of underscore"

- Update emitEnumMember to accept enumTypeName parameter and use it as prefix instead of _ for invalid identifiers
- Update buildEnumTypes to pass normalized enum type name to emitEnumMember
- Update prefix-adding-in-enum-member diagnostic message format to include enumTypeName
- Update enumKeyNorm.md scenario snapshot to use enum type name prefix
- Update extends.md scenario snapshot with new enum member names
- Update enumUnion.spec.ts test to properly verify new diagnostic behavior

Co-authored-by: MaryGao <9943211+MaryGao@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/99a3e736-bfc1-4400-a41d-56f4053c4638

* Refactor emitEnumMember for cleaner code structure after review

Co-authored-by: MaryGao <9943211+MaryGao@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/99a3e736-bfc1-4400-a41d-56f4053c4638

* Regenerate TypeSpec smoke test scenarios with new enum member naming

Generated files updated to reflect the new enum member naming where enum type
name is used as prefix instead of underscore (e.g., Versions100 instead of _100,
Versions20240701Preview instead of _20240701Preview). This ensures the CI
check:tree step passes since it compares generated files against committed files.

Co-authored-by: MaryGao <9943211+MaryGao@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/d16aef3a-466d-4251-a6fe-489bd3fd2549

* Restore and regenerate openai_non_branded TypeSpec test scenario

The previous commit accidentally deleted the openai_non_branded generated
files because it uses a non-standard tspconfig.yaml path (in spec/ not root).
Re-running the smoke test properly regenerates these files.

Co-authored-by: MaryGao <9943211+MaryGao@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/d16aef3a-466d-4251-a6fe-489bd3fd2549

* Run pnpm smoke-test to regenerate TypeSpec test scenarios after merge from main

Regenerated 6 scenarios (NetworkAnalytics.Management, healthInsights_radiologyinsights,
loadtesting_modular, nestedClient, openai_modular, schemaRegistry) that were affected
by the merge with main branch (PR #3856: model array responses fix). This ensures
the check:tree CI step passes.

Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/47b50ca2-9eda-4d7f-8560-c906ba14c70f

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>

* Refactor emitEnumMember: compute enumTypeName from member.enumType.name internally

Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/4a41bf9d-0c14-444a-8f5e-2995bbcb3461

Co-authored-by: MaryGao <9943211+MaryGao@users.noreply.github.com>

* Fix duplicate enum member names by adding numeric suffix when collision occurs

Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/335fe4df-4788-4ba4-8c2a-079e2935ec43

Co-authored-by: MaryGao <9943211+MaryGao@users.noreply.github.com>

* Revert headerParamWithClientInitialization.md and storageCompatResponse.md to original state

Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/7e7b2568-202d-4eae-8fc3-c62f37697674

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>

* Should not change when DO_NOT_NORMALIZE prefix

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: MaryGao <9943211+MaryGao@users.noreply.github.com>
Co-authored-by: Jiao Di (MSFT) <80496810+v-jiaodi@users.noreply.github.com>
Co-authored-by: Mary Gao <marygao@microsoft.com>
JialinHuang803 pushed a commit to JialinHuang803/autorest.typescript that referenced this pull request Apr 9, 2026
…ap-non-model-return` is enabled (Azure#3856)

* Initial plan

* fix: return model array responses as T[] directly to match HLC behavior

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>

* fix: return unknown responses as Record<string, unknown> to match HLC behavior

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>

* fix: generate Resource[] instead of (Resource)[] for model array response alias

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/6e436425-0256-49d0-8f11-05e4ff1ace61

* fix: update integration test specs for new direct response types (no .body wrapper)

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/1b0cb8e1-c52f-4dcb-a032-712f3d13d44d

* fix: simplify type assertion in scalar spec to use strictEqual<unknown>

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/1b0cb8e1-c52f-4dcb-a032-712f3d13d44d

* revert: remove spec-coverage.json and add to .gitignore

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/bf6a9e83-02c8-4bd2-afc7-4bfc90f6bc9a

* revert: undo .gitignore change

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/28742408-c2e9-475b-bf3d-779187207397

* fix: adjust shouldWrap to return false for model arrays, matching HLC behavior

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/714f6c94-fff2-443b-8808-af3cf523667a

* fix: regenerate smoke test generated files for parametrizedHost and widget_dpg

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/c7ebfb7e-4f78-4ccc-b331-5968ed42635f

* refactor: add detailed HLC→modular case comments in checkWrapNonModelReturn

Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/90664101-edd0-4d62-af61-9e9c6b6b722b

Co-authored-by: MaryGao <9943211+MaryGao@users.noreply.github.com>

* add ut

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>
Co-authored-by: MaryGao <9943211+MaryGao@users.noreply.github.com>
Co-authored-by: Jiao Di (MSFT) <v-jiaodi@microsoft.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants