Skip to content

feat(wrapper-generator): complete v1.0 request-body binding - #3722

Open
Joywambui-maina wants to merge 18 commits into
powershell-v3from
feat/bind-request-body-properties
Open

feat(wrapper-generator): complete v1.0 request-body binding#3722
Joywambui-maina wants to merge 18 commits into
powershell-v3from
feat/bind-request-body-properties

Conversation

@Joywambui-maina

Copy link
Copy Markdown

Changes proposed in this pull request

  • Replace primitive-only request-body extraction with exhaustive property classification for the operations the WrapperGenerator emits.
  • Bind referenced Kiota models, enums, collections, formatted scalar types, nullable references, and numeric INF/NaN unions using their generated Kiota member types.
  • Bind schema-less properties as object and convert them to Kiota UntypedValue instances during assignment.
  • Replace the generated -Password and -ForceChangePasswordNextSignIn parameters with the published -PasswordProfile model parameter.
  • Preserve the published SDK's null-omission behavior for untyped values.
  • Add independent omission, coverage, inventory, compilation, and runtime-conversion gates.
  • Document the supported mappings, exclusion policies, scope boundary, and retained zero-population classifications.

Scope

This changes property binding only for operations that already generate. It does not add support for skipped actions, functions, unsupported path segments, or operations without a named request entity.

The operation-inventory gate verifies that this change does not alter which operations generate.

Validation

  • 148 WrapperGenerator tests pass.
  • All 38 v1.0 KiotaCompat specifications were measured.
  • The omission oracle reports zero failures across 2,214 generated body-writing cmdlets.
  • The coverage sweep reports zero unbound properties among operations that generate.
  • All 35 modules that produce wrapper manifests build and import successfully.
  • Runtime checks cover typed models, enums, Kiota Date, and 19 schema-less value-conversion cases.
  • The generated operation inventory is unchanged by the body-binding work.

Dependency

This PR is intentionally based on feature/wrapper-module-packaging so reviewers see only the 24 files belonging to request-body binding. After #3698 merges into powershell-v3, this PR will be retargeted to powershell-v3.

Closes #3707

Joywambui-maina and others added 13 commits August 5, 2026 13:43
Graph declares Edm.Int32/Int64 as "number" with the real type in the
format; mapping by type alone emitted double? against Kiota's int? and
did not compile. An explicit format now decides the CLR type, mirroring
Kiota's own mapping.
…racle audit

Auditing every v1.0 GET command in MgCommandMetadata.json against the
singularizer surfaced four words where the rules disagree with shipped
cmdlet names: Cookies -> "Cooky" (ships as ...HostCookie), Skus kept
as-is (ships as Get-MgSubscribedSku), Dns -> "Dn" (ships as
Get-MgDomainVerificationDnsRecord), Ios -> "Io" (ships as
Get-MgDeviceAppManagementIosManagedAppProtection). Adds two irregulars
and two invariants, each with a pinned test, and refreshes the README
test count.

82 tests passing. Full-inventory match after fix: 796 of 870 noun
segments; the remaining 74 are action/function segments and AutoRest
hand renames, tracked separately.
…nt, start edge-case catalog

Only 2 of 30 shipped whois-family commands truncate "Whois" to "Whoi"; per
review decision the generator emits the corrected ...HostWhois (no alias for
the old name), and the parity gate reports it as [CORRECTED] instead of
failing. "Statistics" joins the invariants, found via the DEVX Humanizer
exception list. edge-cases/naming-edge-cases.md starts the per-class
catalog of naming defects. 88 tests passing.
Build-WrapperModule.ps1 turns one OpenAPI doc into an importable module
(kiota client + wrappers + csproj + dll + PSD1 manifest), reading the
Kiota-compatible docs by default with a hard kiota timeout and per-module
doc fallback. Test-WrapperModule.ps1 imports each build in a fresh pwsh
and verifies exports, worker pairing, and the sessionless NoGraphSession
path. All 35 cmdlet-producing v1.0 modules build and pass.
Compiling all v1.0 modules against freshly generated kiota clients
surfaced eight alignment defects, each fixed and pinned by a test:
dispatchers re-wrapped worker errors (NoGraphSession was lost); body
properties colliding with path ids (published convention: -DeviceId1);
bare model types colliding with namespaces and BCL types (now fully
qualified, mirroring kiota's move-inside and reserved-name renames at
root and in sub-namespaces); collection responses resolved from their
own $ref; underscore members (riskEventTypes_v2 -> RiskEventTypesV2);
$select/$expand emitted only where declared; re-fetch only where a GET
exists; media/content endpoints skipped like $value.
…ant, catalog kiota edge cases

The full-module parity sweep found two shipped-name issues: AutoRest
truncated /places/{id}/checkIns at the preposition (8 commands ship as
*-MgPlaceCheck while Get-MgPlaceCheckInCount keeps "In") - corrected per
policy with gate rows and pinned tests; and "Rights" needs to be an
inflection invariant (Get-MgPrivacySubjectRightsRequest, 42 cmdlets) -
Compliance now matches 23 of 23. New edge-cases/kiota-alignment file
catalogs the compile-found defect classes; README refreshed. 103 tests.
A second operation resolving to an already-written cmdlet file now fails
generation with the full collision list instead of silently overwriting it,
which is the silent-drop failure mode AutoRest had.

OData cast list/item pairs (owners/graph.user) now merge like plain pairs,
and the sweep's collisions land as cited NamingOverrides entries: termStore
and agreement-file stitches, default-singleton renames (SubSite,
DefaultDrive, DefaultCalendarEvent), and nested navs the SDK never shipped.
Remaining families are tracked on #3704.
… data

Derive-CollisionResolutions.ps1 replays the checked-in collision inventory
(212 lines, 365 contested routes) against MgCommandMetadata and emits
exact-match resolution data: 191 suppressions (routes the published SDK
prunes) and 64 renames (published nouns), each entry carrying its oracle
evidence. The files embed into the generator and apply only when
UseCollisionData is set; -Validate fails on drift, and a new xunit test
runs it on every `dotnet test` so staleness fails the suite instead of
depending on someone remembering to run the script by hand. Derivation
itself fails on any unclassified or ambiguous route. Only 2 cross-path
variant merges exist in all of v1.0 (GroupPhoto, ShareListItem) - deferred
with the singleton side kept, cataloged in crosspath-merge-edge-cases.md.

Full 39-module v1.0 generation now produces zero collisions; 20 published
commands that lost filename races are recovered; exact-name matches rise
5,042 -> 5,098.

Also: cmdlets emit into a per-module namespace derived from the client
namespace instead of the leftover MgPoC placeholder; Build-WrapperModule's
generated csproj references Authentication by a relative path instead of
an absolute one; its -Configuration parameter now actually reaches the
wrapper generator's own build, not just the final module build; and a
pre-existing nullable warning in the list/item pairing check is fixed.
121 tests pass.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
fix(wrapper-generator): fail loudly on cmdlet file collisions
Request bodies bound only top-level primitives, so 4,466 property
occurrences across the v1.0 specs had no parameter. Every shape the
classifier reaches now binds: referenced models and enums, formatted
strings, schema-less UntypedNode values (converted on assignment, nulls
dropped to match the published SDK's AddIf), and the numeric INF/NaN
union. The invented -Password pair is replaced by the published
-PasswordProfile. New gates verify it - omission oracle, coverage sweep,
inventory diff, runtime conversions: 0 unbound across all 38 specs, 35
modules build and import, 148 tests. The pre-existing naming-parity gap
is tracked separately.
Both lines carried the same singularizer-era fixes as different commits, so
the five conflicts resolve to identical rules plus each side's real
additions: powershell-v3's docs/edge-cases layout and lean comments win;
the packaging line's Rights invariant, ResolveParameterNameCollisions, and
PlaceCheckIn corrections survive. README test count set to the measured
121; its no-compile-test claim was already false here and is corrected.

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.

Pull request overview

This PR upgrades the WrapperGenerator’s request-body parameter binding from “top-level primitives only” to a comprehensive classifier-driven binding model aligned with the Kiota-generated CLR types, and adds documentation + tooling gates to validate binding coverage, runtime conversions, and operation inventory stability.

Changes:

  • Introduces exhaustive request-body property classification (scalars, referenced models/enums/collections, schema-less/untyped, excluded-by-policy, unsupported shapes) and wires it into cmdlet emission for New/Update.
  • Adds runtime conversion support for schema-less properties via an emitted UntypedValue.From(object) helper, plus additional generator logging and validation scripts (coverage oracle, measurement sweep, operation inventory diff).
  • Expands and reorganizes documentation for binding rules and edge cases; updates build/test scripts to support committed wrapper output and validation.

Reviewed changes

Copilot reviewed 22 out of 25 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tools/WrapperGenerator/StderrLogger.cs Adds configurable minimum log level for CLI runs.
tools/WrapperGenerator/Singularizer.cs Updates naming-rule commentary and preserves “Whois” behavior rationale.
tools/WrapperGenerator/SchemaProperties.cs Implements request-body property classifier + exclusion/unsupported shape model.
tools/WrapperGenerator/README.md Updates docs to reflect full body binding, committed output layout, and validation gates.
tools/WrapperGenerator/Program.cs Adds --log-level argument and wires it into stderr logging.
tools/WrapperGenerator/PowerShellWrapperGenerationService.cs Integrates classification/binding into New/Update emission and adds reconciliation logging.
tools/WrapperGenerator/edge-cases/naming-edge-cases.md Removes legacy path in favor of docs-based catalog location.
tools/WrapperGenerator/docs/edge-cases/naming-edge-cases.md Extends naming edge-case catalog with additional cases and wrapper-surface change note.
tools/WrapperGenerator/docs/edge-cases/kiota-alignment-edge-cases.md Adds catalog of Kiota-vs-prediction alignment findings and encoded rules.
tools/WrapperGenerator/docs/edge-cases/crosspath-merge-edge-cases.md Documents cross-path cmdlet-variant deferral policy and known cases.
tools/WrapperGenerator/docs/edge-cases/body-binding-edge-cases.md Documents residual unsupported body shapes and why they remain deferred.
tools/WrapperGenerator/docs/body-property-binding.md Adds authoritative binding spec, mapping tables, exclusions, and verification model.
tools/WrapperGenerator/CmdletEmitter.cs Emits complex/untyped parameters + assignments; adds UntypedValue helper and null-safe collection writes.
tools/WrapperGenerator.Tests/SpecShapeTests.cs Adds tests pinning spec/reader behaviors relied on by binding (nav-property extension, nullable ref shape, enum refs).
tools/WrapperGenerator.Tests/SchemaPropertiesTests.cs Adds extensive classifier tests (formats, unions, exclusions, collisions, accounting invariants).
tools/WrapperGenerator.Tests/NamingTests.cs Updates deliberate-correction commentary (contains a small typo).
tools/WrapperGenerator.Tests/EmitterTests.cs Extends emitter tests to cover complex typed parameters and confirms password special-case removal.
tools/Test-WrapperModule.ps1 Adds stale-binary gate + runtime binding checks for complex/enums/scalars/untyped conversion matrix.
tools/Test-BodyBindingCoverage.ps1 Adds independent oracle to ensure every settable Kiota body member is bound or policy-cited.
tools/New-WrapperOutputManifest.ps1 Adds manifest generator for reviewable inventory of committed wrapper output under src/.
tools/Measure-BodyPropertyCoverage.ps1 Adds sweep script summarizing unbound properties by shape across all specs.
tools/Compare-WrapperOperationInventory.ps1 Adds inventory diff tool to ensure parameter-only changes don’t alter generated operations.
tools/Compare-WrapperCmdletNames.ps1 Small doc/comment updates for deliberate correction policy linkage.
tools/Build-WrapperModule.ps1 Adds -IntoSource to write the committed wrapper layout under src/<Module>/<ApiVersion>/wrapper/.
.gitignore Un-ignores src/BackupRestore/ so the module folder can be committed.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tools/WrapperGenerator.Tests/NamingTests.cs
Comment thread tools/WrapperGenerator/CmdletEmitter.cs
Comment thread tools/WrapperGenerator/SchemaProperties.cs
An error occurred while trying to automatically change base from feature/wrapper-module-packaging to powershell-v3 August 18, 2026 18:08
Record-only merge after #3698 squash-merged feature/wrapper-module-packaging
into powershell-v3. The branch already contains every change from that squash
(verified: packaging tip is an ancestor, and its diff against powershell-v3 is
empty), so this commit changes no files - it restores an accurate merge base so
the PR diff against powershell-v3 shows only the request-body binding work.
@Joywambui-maina
Joywambui-maina changed the base branch from feature/wrapper-module-packaging to powershell-v3 August 20, 2026 17:57
@Joywambui-maina
Joywambui-maina changed the base branch from powershell-v3 to main August 20, 2026 17:57
@Joywambui-maina
Joywambui-maina changed the base branch from main to powershell-v3 August 20, 2026 17:57
A bare primitive-typed branch (anyOf[$ref, {type: string}]) no longer reads
as a nullability placeholder, so such a union is reported instead of silently
collapsing to the reference - pinned by a test; generation output across the
current specs is byte-identical. Also fixes a comment typo in NamingTests.
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.

WrapperGenerator: bind complex request-body properties as typed Kiota-model parameters

2 participants