Skip to content

[Swagger Linter Migration] ValidQueryParametersForPointOperations - #5273

Merged
Yuchao Yan (msyyc) merged 13 commits into
Azure:mainfrom
msyyc:promote-valid-query-parameters-point-operations
Sep 3, 2026
Merged

[Swagger Linter Migration] ValidQueryParametersForPointOperations#5273
Yuchao Yan (msyyc) merged 13 commits into
Azure:mainfrom
msyyc:promote-valid-query-parameters-point-operations

Conversation

@msyyc

@msyyc Yuchao Yan (msyyc) commented Aug 20, 2026

Copy link
Copy Markdown
Member

Original Swagger linters

This promoted TypeSpec rule intentionally covers two Swagger validator rules:

ValidQueryParametersForPointOperations implements ARM RPC guideline RPC-Uri-V1-13.
ParametersInPointGet implements ARM RPC guideline RPC-Get-V1-08.

Official TypeSpec rule name: point-operation-invalid-query-parameter (renamed during promotion to follow TypeSpec linter naming conventions).

ValidQueryParametersForPointOperations performs these checks:

  • Traverses resolved Swagger paths and x-ms-paths entries.
  • Classifies a URI as a point path only when its final provider-qualified portion contains /providers/{namespace} followed by one or more resource-type/resource-name pairs; resource names may be {parameters} or default.
  • Checks GET, PUT, PATCH, and DELETE operations.
  • Reads each operation's parameters array and ignores non-query parameters.
  • Allows api-version and reports every other query parameter independently.
  • Excludes collection paths, unmatched trailing path segments, and providerless paths.

ParametersInPointGet is the older production GET-only form of the same policy. It performs these checks:

  • Traverses Swagger paths entries.
  • Classifies a URI as a point resource path with getResourcesPathHierarchyBasedOnResourceType.
  • Checks only GET operations.
  • Allows GET query parameters named exactly api-version.
  • Reports every other GET query parameter at the operation parameters array.

How the Swagger linters work

ValidQueryParametersForPointOperations is invoked over the resolved maps selected by $[paths,'x-ms-paths']. The function loops each URI, applies the shared isPointOperation regex to the portion beginning at the last /providers/, then loops GET/PUT/PATCH/DELETE and filters each resolved parameter array for query parameters other than api-version. Each rejected emitted parameter produces one error located at that operation's parameters array.

ParametersInPointGet uses a narrower production path: it loops the Swagger paths object, classifies each URI with the ARM resource hierarchy helper, checks only the get operation, and reports query parameters other than api-version. This is a subset of the broader point-operation rule, so it should map to the same TypeSpec implementation rather than to a second production TypeSpec rule.

The broader Swagger rule is stagingOnly, so normal production AutoRest validation disables it and reports 0 projects. The checked-in migration investigation instead ran the actual Spectral staging rule. Its initial 64-project same-corpus population became 62 projects after restricting both sides to the 462 projects whose TypeSpec compiled, with all 62 projects overlapping. The production ParametersInPointGet row separately shows 40 Swagger projects, all overlapping the same TypeSpec rule.

Raw diagnostic counts are intentionally not one-to-one: Swagger reports emitted operation-parameter occurrences, while a shared TypeSpec parameter declaration can instantiate into several operations and projected versions. The final staging comparison is 321 Swagger diagnostics versus 724 TypeSpec diagnostics, but 62 versus 62 projects with no one-sided projects. The GET-only production comparison is 189 Swagger diagnostics versus the same raw 724 TypeSpec diagnostics, with 40 overlapping Swagger projects and 22 TypeSpec-only projects explained by PUT/PATCH/DELETE coverage from the broader staging rule. The validator also accepts x-ms-paths, while a clean TypeSpec @sharedRoute equivalent was not included because its emitted ?_overload=... disambiguator does not reproduce the upstream rule.

Source TypeSpec lintdiff rule

The user-marked done source is tsp-lintdiff-local-linter/valid-query-parameters-for-point-operations on branch feature/lintdiff-migration-new, captured at intake commit e9d5541c2ef3e354ce1bf6ab3332dfb87620a8d2. The source worktree was clean at intake and had no uncommitted rule changes. This promotion did not modify the lintdiff source, fixtures, snapshots, manifests, or documentation.

Destination analysis

This rule belongs in @azure-tools/typespec-azure-resource-manager because validator metadata declares applicability: ARM, sources: ["arm"], and the fixture explicitly selects the resource-manager ruleset. Its semantics depend on ARM provider-qualified resource paths and ARM RPC guidance. Azure Core was technically possible because the implementation needs only compiler and HTTP APIs, but placing ARM-only URI policy in the shared data-plane package would expose the wrong dependency and ruleset surface. No equivalent official ARM or Core rule exists.

How the promoted TypeSpec linter works

The promoted rule visits TypeSpec operations and resolves each with getHttpOperation. It filters to GET, PUT, PATCH, and DELETE, then applies the same provider/resource-pair path regex as the Swagger helper to the portion after the last /providers/. For eligible point paths, it examines resolved HTTP parameters, ignores non-query parameters and case-insensitive api-version, and reports each additional query parameter on its authorable TypeSpec parameter declaration.

This one TypeSpec rule therefore covers both Swagger inputs: it covers ParametersInPointGet when the verb is GET, and it covers ValidQueryParametersForPointOperations across GET/PUT/PATCH/DELETE. The implementation intentionally does not use ARM operation-kind metadata because that would misclassify list-shaped reads and providerless resource-group DELETE operations that the Swagger path matcher excludes. It also performs no promotion-only deduplication, preserving the done lintdiff rule's operation traversal and source-target behavior. No version projection or semantic behavior was added during promotion.

Fixture-to-native test mapping

Original lintdiff fixture Native vitest case Coverage note
extra-query-param it("emits for extra query parameters on top-level GET, PUT, PATCH, and DELETE operations") Covers top-level point-resource GET, PUT, PATCH, and DELETE operations, each with one disallowed query parameter.
nested-extra-query-param it("emits for extra query parameters on nested point GET and PUT operations") Covers nested point-resource GET and PUT operations with disallowed query parameters.
multiple-query-params it("emits one diagnostic for each extra query parameter") Preserves one diagnostic per extra query parameter on the same point operation.
legacy-action-point-get it("classifies a GET operation by point-path shape regardless of its authoring template") Reduces the legacy template to its semantic requirement and verifies that point-path shape, not authoring template, controls eligibility.
api-version-only it("allows point operations whose only query parameter is api-version") Covers compliant point operations where the only query parameter is api-version.
list-operation it("allows query parameters on collection operations") Covers compliant collection paths, where non-api-version query parameters are allowed.
list-shaped-read it("allows query parameters on list-shaped read paths") Covers the compliant list-shaped read regression for a path with an unmatched trailing segment.
providerless-delete it("allows query parameters on providerless DELETE operations") Covers the compliant providerless resource-group-style DELETE regression.

No validator snapshots or lintdiff corpus artifacts were copied.

Migration evidence

The focused fixtures, real-service comparison, full-corpus counts, former TypeSpec-only projects, projection fix, diagnostic-cardinality analysis, compile-success population, and remaining uncertainty for ValidQueryParametersForPointOperations are documented in migration.md.

The companion ParametersInPointGet investigation confirms the same TypeSpec rule covers every assessable production GET-only Swagger project and explains the 22 TypeSpec-only projects as broader PUT/PATCH/DELETE coverage, not as false positives or a need for another TypeSpec rule: #5210

Promotion sync policy

If review identifies a semantic gap, this PR should remain blocked until the user explicitly reopens the lintdiff repair workflow. The immutable source rule must be repaired and revalidated first; semantic changes should not be made only in this promotion PR.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 72da97a1-a62c-41e5-b4da-c2a485f735d4
@msyyc Yuchao Yan (msyyc) added the int:azure-specs Run integration tests against azure-rest-api-specs label Aug 20, 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 Aug 20, 2026
@github-actions

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 an ARM lint rule that warns when point GET, PUT, PATCH, or DELETE operations declare query parameters other than api-version.

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

Add an ARM lint rule that warns when point GET, PUT, PATCH, or DELETE operations declare query parameters other than api-version.

@github-actions

github-actions Bot commented Aug 20, 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-java 13.51 MB → 13.51 MB -130 B (-0.0%) 15.03 MB → 15.03 MB
@azure-tools/typespec-azure-resource-manager 173.71 KB → 173.76 KB +58 B (+0.0%) 1.05 MB → 1.05 MB +625 B (+0.1%)
@azure-tools/typespec-azure-rulesets 5.22 KB → 5.24 KB +21 B (+0.4%) 32.57 KB → 32.75 KB +192 B (+0.6%)
@azure-tools/azure-http-specs 146.71 KB → 146.71 KB 1.16 MB → 1.16 MB
@azure-tools/typespec-autorest 81.01 KB → 81.01 KB 395.40 KB → 395.40 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.84 KB → 709.84 KB
@azure-tools/typespec-azure-portal-core 42.40 KB → 42.40 KB 192.91 KB → 192.91 KB
@azure-tools/typespec-client-generator-core 229.48 KB → 229.48 KB 1.23 MB → 1.23 MB
@azure-tools/typespec-go 261.24 KB → 261.24 KB 1.34 MB → 1.34 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 536.70 KB → 536.70 KB 2.58 MB → 2.58 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 Aug 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

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

commit: 3bf6b85

@azure-sdk-automation

Copy link
Copy Markdown
Contributor

You can try these changes here

🛝 Playground 🌐 Website

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 8ed00e6d-dd0a-40f7-8871-ee32f0f371fb
@msyyc

Yuchao Yan (msyyc) commented Aug 21, 2026

Copy link
Copy Markdown
Member Author

Finding from the ParametersInPointGet migration check: we do not need a separate TypeSpec linter for ParametersInPointGet.

ParametersInPointGet is the older production Swagger rule for point GET operations only. The migrated TypeSpec rule in this PR, valid-query-parameters-for-point-operations, is the right shared implementation because it covers that GET behavior and also covers the broader staging-only Swagger rule ValidQueryParametersForPointOperations for point GET/PUT/PATCH/DELETE.

So the expected follow-up is documentation/evidence only: map ParametersInPointGet to this broader rule and explain the apparent TypeSpec-only projects as PUT/PATCH/DELETE coverage from the broader rule, not as false positives or a need for another rule.

@catalinaperalta

Copy link
Copy Markdown
Member

while a clean TypeSpec SharedRoute equivalent was not included because its emitted ?_overload=... disambiguator does not reproduce the upstream rule.

Is this saying that we skipped the check on the sharedRoute entries?

@catalinaperalta catalinaperalta left a comment

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.

overall lgtm and seems to match the original rule, we should double check though if we should include the sharedRoute instances

Comment thread packages/typespec-azure-rulesets/src/rulesets/resource-manager.ts Outdated
Use ARM operation templates in the point operation query parameter rule documentation examples.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 03547afb-ae31-401d-9aa8-6c617a9af395
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9e777ab0-db49-43b1-be78-74bb99a8e955
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9e777ab0-db49-43b1-be78-74bb99a8e955
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9e777ab0-db49-43b1-be78-74bb99a8e955
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9e777ab0-db49-43b1-be78-74bb99a8e955
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9e777ab0-db49-43b1-be78-74bb99a8e955
@msyyc

Copy link
Copy Markdown
Member Author

Timothee Guerin (@timotheeguerin) Thanks for your review and I updated the PR with your suggestions just now. Pls help take a review again when spare.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9e777ab0-db49-43b1-be78-74bb99a8e955
@msyyc

Yuchao Yan (msyyc) commented Sep 1, 2026

Copy link
Copy Markdown
Member Author

Timothee Guerin (@timotheeguerin) Thanks for your review and I updated the PR with your suggestions just now.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9e777ab0-db49-43b1-be78-74bb99a8e955
@msyyc
Yuchao Yan (msyyc) added this pull request to the merge queue Sep 3, 2026
Merged via the queue into Azure:main with commit e4c2e5c Sep 3, 2026
44 checks passed
@msyyc
Yuchao Yan (msyyc) deleted the promote-valid-query-parameters-point-operations branch September 3, 2026 02:58
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.

3 participants