Skip to content

[Swagger Linter Migration] ParametersSchemaAsTypeObject - #5361

Open
Yuchao Yan (msyyc) wants to merge 12 commits into
Azure:mainfrom
msyyc:promote-parameters-schema-as-type-object-to-arm
Open

[Swagger Linter Migration] ParametersSchemaAsTypeObject#5361
Yuchao Yan (msyyc) wants to merge 12 commits into
Azure:mainfrom
msyyc:promote-parameters-schema-as-type-object-to-arm

Conversation

@msyyc

@msyyc Yuchao Yan (msyyc) commented Sep 1, 2026

Copy link
Copy Markdown
Member

Summary

Promotes the ARM request-body guideline represented by Swagger validator rule ParametersSchemaAsTypeObject as the idiomatic TypeSpec rule use-model-request-body.

TypeSpec-first behavior

The native rule validates authored TypeSpec semantics rather than reproducing AutoRest's emitted Swagger schema details:

  • request bodies must use a plain Model without an indexer
  • named and inline models are allowed
  • model-property references are checked using their underlying type
  • arrays, records, primitives, unions, files, and other non-model body shapes are rejected
  • absent bodies, synthetic void bodies, and multipart bodies are exempt
  • encoding, format, schema-reference, and emitter-specific schema replacement behavior is intentionally not simulated

This follows the review decision to prefer idiomatic TypeSpec validation and preserve Swagger parity only where it maps naturally to TypeSpec. Constructs already rejected by Azure rules or emitter diagnostics do not justify additional AutoRest simulation in this rule.

Relationship to lintdiff evidence

The original lintdiff migration.md records the earlier exact-emission parity investigation and remains useful historical evidence. Its exact diagnostic-parity conclusion is not the acceptance criterion for this promoted rule; differences caused by invalid or non-idiomatic TypeSpec are intentional. The source document lives only on feature/lintdiff-migration-new, so revising it requires a separate change on that branch rather than adding the lintdiff package to this main-targeted PR.

Validation

  • 10 focused use-model-request-body tests pass
  • ARM package build and lint pass
  • generated ARM rule references updated
  • Azure rulesets build and 4 ruleset-definition tests pass

Yuchao Yan (msyyc) and others added 3 commits September 1, 2026 14:54
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@msyyc Yuchao Yan (msyyc) added the int:azure-specs Run integration tests against azure-rest-api-specs label Sep 1, 2026
@microsoft-github-policy-service microsoft-github-policy-service Bot added lib:azure-resource-manager Issues for @azure-tools/typespec-azure-core library meta:website TypeSpec.io updates linter Issues related to linter rules labels Sep 1, 2026
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • @azure-tools/typespec-azure-resource-manager
  • @azure-tools/typespec-azure-rulesets
Show changes

@azure-tools/typespec-azure-resource-manager - feature ✏️

Add the use-model-request-body ARM lint rule, an idiomatic TypeSpec migration of the Swagger ParametersSchemaAsTypeObject validator rule.

@azure-tools/typespec-azure-rulesets - internal ✏️

Register the ARM use-model-request-body lint rule as disabled in the resource manager ruleset.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

📦 Package size report

✅ No notable package size changes compared to the base branch.

13 package(s) with no notable change
Package Packed (base → head) Δ Packed Unpacked (base → head) Δ Unpacked
@azure-tools/typespec-azure-resource-manager 183.70 KB → 183.77 KB +74 B (+0.0%) 1.11 MB → 1.11 MB +633 B (+0.1%)
@azure-tools/typespec-azure-rulesets 5.35 KB → 5.36 KB +15 B (+0.3%) 33.04 KB → 33.23 KB +196 B (+0.6%)
@azure-tools/azure-http-specs 146.79 KB → 146.79 KB 1.16 MB → 1.16 MB
@azure-tools/typespec-autorest 81.22 KB → 81.22 KB 396.61 KB → 396.61 KB
@azure-tools/typespec-autorest-canonical 7.42 KB → 7.42 KB 26.00 KB → 26.00 KB
@azure-tools/typespec-azure-core 130.84 KB → 130.84 KB 709.83 KB → 709.83 KB
@azure-tools/typespec-azure-portal-core 42.47 KB → 42.47 KB 193.19 KB → 193.19 KB
@azure-tools/typespec-client-generator-core 237.05 KB → 237.05 KB 1.27 MB → 1.27 MB
@azure-tools/typespec-go 261.43 KB → 261.43 KB 1.34 MB → 1.34 MB
@azure-tools/typespec-java 13.51 MB → 13.51 MB 15.04 MB → 15.04 MB
@azure-tools/typespec-metadata 15.91 KB → 15.91 KB 62.26 KB → 62.26 KB
@azure-tools/typespec-python 42.22 KB → 42.22 KB 164.91 KB → 164.91 KB
@azure-tools/typespec-ts 540.86 KB → 540.86 KB 2.60 MB → 2.60 MB

Packed = gzipped .tgz published to npm. Unpacked = total extracted size. 🆕 added, 🗑️ removed. Packages from the core/ submodule are not included.
🔴 grew · 🟢 shrank — only changes of at least 512 B and 0.5% are marked.

@pkg-pr-new

pkg-pr-new Bot commented Sep 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@azure-tools/typespec-azure-resource-manager@5361
npm i https://pkg.pr.new/@azure-tools/typespec-azure-rulesets@5361

commit: 50b037e

@azure-sdk-automation

Copy link
Copy Markdown
Contributor

You can try these changes here

🛝 Playground 🌐 Website

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Required suppression guidance and the manually maintained ARM rules table entry are missing.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Promotes the Swagger request-body schema check into the ARM TypeSpec linter.

Changes:

  • Adds and registers request-body-must-be-object.
  • Covers AutoRest schema-emission behavior with extensive tests.
  • Updates rulesets, references, and release metadata.
File summaries
File Description
.chronus/changes/promote-parameters-schema-as-type-object-2026-08-31.md Records the feature release.
packages/typespec-azure-resource-manager/README.md Lists the new rule.
packages/typespec-azure-resource-manager/src/linter.ts Registers the rule.
packages/typespec-azure-resource-manager/src/rules/request-body-must-be-object.md Documents rule behavior.
packages/typespec-azure-resource-manager/src/rules/request-body-must-be-object.ts Implements schema classification.
packages/typespec-azure-resource-manager/test/rules/request-body-must-be-object.test.ts Tests supported body forms.
packages/typespec-azure-rulesets/src/rulesets/resource-manager.ts Adds the disabled ruleset entry.
website/src/content/docs/docs/libraries/azure-resource-manager/reference/linter.md Updates website rule references.
Review details
  • Files reviewed: 8/8 changed files
  • Comments generated: 2
  • Review effort level: Balanced

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/typespec-azure-resource-manager/src/linter.ts Outdated
Comment thread packages/typespec-azure-resource-manager/src/rules/request-body-must-be-object.md Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

The implementation self-imports its package root, creating a circular dependency and coupling source builds to generated output.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

packages/typespec-azure-resource-manager/src/rules/request-body-must-be-object.ts:2

  • This self-import resolves through the package's public dist/src/index.* export and creates an index -> linter -> rule -> index cycle. It can also bind source builds/tests to stale generated output instead of the current implementation. Use the direct intra-package module import, consistent with the rest of this package.
  • Files reviewed: 9/9 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Comment thread packages/typespec-azure-resource-manager/src/rules/request-body-must-be-object.ts Outdated
Comment thread .chronus/changes/promote-parameters-schema-as-type-object-2026-08-31.md Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@msyyc

Copy link
Copy Markdown
Member Author

Timothee Guerin (@timotheeguerin) updated with your comments and pls take a review again.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
}
const targetFormat = isSecret(program, target) ? "password" : undefined;
const encodedSchema = getEmittedScalarSchema(program, encoding.type);
const mergedFormat = mergeFormatAndEncoding(

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.

why do we need this whole format thing

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.

This is not handling authored @format; that support was removed. It mirrors AutoRest's internal @encode behavior because encoding only replaces the schema type when mergeFormatAndEncoding() produces a format.

For example:

model Payload {
  value: string;
}

model Request {
  @encode("custom", int32)
  payload: Payload;
}

@post op create(@body body: Request.payload): void;

Although the underlying TypeSpec property is model-shaped, AutoRest applies the encoding and emits an integer schema such as { type: "integer", format: "int32" }; the migrated Swagger rule must therefore report it. Other encodings can produce no usable format and leave an untyped schema, which the original rule does not report.

So the format value is only an intermediate signal used to determine whether AutoRest applies the encoding and changes schema.type. I agree the reason is subtle and will add documentation around this logic.

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.

but this doesn't make sense, the goal of this rule is to check the body is a model, either it is or it;s not. If it has any encode to anything else it is not(If that is even worth checking), that's it don't need to check further. The rules should NOT try to mimic exactly what autorest output did they should work wiht what you can do in typespec.

@msyyc Yuchao Yan (msyyc) Sep 7, 2026

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.

Context

A TypeSpec Model is a compiler-level construct, not necessarily a Swagger type: object.

Examples:

model Request {
  value: string;
}

emits an object schema.

model Request is Array<string>;

is also a TypeSpec Model, but emits:

{ "type": "array", "items": { "type": "string" } }

Visibility transformations, model properties, templates, files, and encodings can further change the effective emitted schema.

The reverse also matters: a non-Model TypeSpec type can emit no Swagger type, such as unknown; the Swagger rule ignores it even though it is not a TypeSpec model.

Need discussion

Now the gap is clear and we should answer the question: whether real behavior equivalence is strict standard for the rule migration. And I need discussion with catalinaperalta

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.

yeah by model I mean a plain model (one without an indexer) which is easily checkable, what does this have to do with encode.

@msyyc Yuchao Yan (msyyc) Sep 9, 2026

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.

This resolves my response to the array example: although arrays have kind === "Model", they have an indexer, so the simple plain-model check still rejects them. The remaining decision is product-level: whether this promotion prioritizes Swagger diagnostic parity or translates the Swagger guideline into idiomatic TypeSpec policy. CC catalinaperalta

yeah by model I mean a plain model (one without an indexer) which is easily checkable, what does this have to do with encode.

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.

it is still feature parity, you cannot do that in TypeSpec, the check that swagger was doing with format has no equivalence in TypeSpec, this is just dead code. Can you show me a test that would pass here without all that extra noise.

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 should focus on being idiomatic to TypeSpec and not bringing in swagger logic into the linter rules. Wherever relevant we should maintain parity with the swagger checks but only if it's not violating the previous statement of not being idiomatic to typespec

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.

Updated in a29fa65 following this guidance and Catalina's TypeSpec-first decision. The rule now checks the authored body semantically: a valid single body must resolve to a Model without an indexer. It retains only the HTTP-level void and multipart exemptions and project-owned diagnostic targeting. All AutoRest encoding, format, union-emission, scalar-emission, and reference-resolution simulation was removed. The focused suite was rewritten around plain models, model-property references, arrays/records, transformed ARM action arrays, file bodies, primitives/non-models, synthetic void, and multipart bodies; all 10 tests pass.

Yuchao Yan (msyyc) added a commit that referenced this pull request Sep 10, 2026
…igrations (#5446)

## Summary

Update only `.github/skills/develop-lintdiff-rule/SKILL.md` to codify
the migration principle settled in [PR
#5361](#5361 (comment)):
prefer idiomatic TypeSpec validation and preserve Swagger parity only
where it naturally maps to TypeSpec semantics.

Exact executable Swagger behavior is not the migration contract when
reproducing it requires non-idiomatic checks, AutoRest schema
formatting/encoding simulation, or handling constructs already
invalidated by TypeSpec or Azure rules. The guidance now requires tests
showing that added special cases affect valid supported TypeSpec;
otherwise, omit the complexity and document the intentional parity gap.

Align coverage classification, the semantic completeness gate, fixture
requirements, migration evidence, and review guidance with this
priority. Corpus/lintdiff and emission-matrix evidence remain useful
research tools, not mandates to reproduce emitter behavior. This follows
Timothée Guérin's [plain-model/indexer
guidance](#5361 (comment))
and Catalina Peralta's confirmation of the idiomatic-TypeSpec-first
principle.

## Scope

Independent documentation-only PR based on and targeting
`feature/lintdiff-migration-new`, not `main`. No production rules,
fixtures, generated corpus data, dependency changes, or release
metadata. Chronus excludes Markdown files from change detection.

## Validation

- Prettier check limited to the changed skill document.
- `git diff --check`.
- No repository-wide formatting, build, or tests for this
documentation-only change.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@msyyc Yuchao Yan (msyyc) changed the title [Swagger Linter Migration] ParametersSchemaAsTypeObject [Swagger Linter Migration] UseModelRequestBody Sep 10, 2026
Yuchao Yan (msyyc) added a commit that referenced this pull request Sep 10, 2026
## Summary

Adopt the TypeSpec-first migration principle settled in
#5361: native linter rules
should validate idiomatic TypeSpec semantics, preserving Swagger parity
only where it naturally maps to that contract. Exact executable Swagger
behavior is not a requirement when it entails emitter/format/encoding
simulation or handling constructs already invalidated by TypeSpec or
Azure rules.

- Update the develop-lintdiff-rule skill's implementation boundary,
evidence gate, fixture requirements, migration reporting, and review
guidance. Added complexity must have tests demonstrating value for valid
supported TypeSpec; otherwise omit it and document intentional parity
gaps.
- Update ParametersSchemaAsTypeObject/migration.md to preserve
historical corpus numbers and evidence while labeling exact-emission
parity as historical, not the promotion acceptance criterion. State the
promoted use-model-request-body contract: a plain model without an
indexer, with absent/synthetic void and multipart exemptions.

## Scope

Independent documentation-only PR against
`feature/lintdiff-migration-new`. Contains exactly the skill and
migration note; no production implementation, generated corpus data, or
dependency changes. Markdown is excluded by the Chronus changedFiles
configuration, so no release metadata is added.

The existing corpus evidence remains historical; no new corpus run or
broad repository build/test was performed for this documentation change.

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@msyyc Yuchao Yan (msyyc) changed the title [Swagger Linter Migration] UseModelRequestBody [Swagger Linter Migration] ParametersSchemaAsTypeObject Sep 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

int:azure-specs Run integration tests against azure-rest-api-specs lib:azure-resource-manager Issues for @azure-tools/typespec-azure-core library linter Issues related to linter rules meta:website TypeSpec.io updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants