Skip to main content

update-resolve-arm-resources

Update, debug, or review the typespec-azure-resource-manager resolveArmResources API, including versioned resource views, operation association, ARM state and cache isolation, projected TypeSpec types, and dependency-neutral logical naming hooks.

معلومات المصدر

المستودع
Azure/typespec-azure
آخر نشاط في المصدر
٢٣ أكتوبر ٢٠٢٦ في ٠٢:٠١
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٢٧
التفرعات
٩٢

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
update-resolve-arm-resources
description
Update, debug, or review the typespec-azure-resource-manager resolveArmResources API, including versioned resource views, operation association, ARM state and cache isolation, projected TypeSpec types, and dependency-neutral logical naming hooks.
allowed-tools
shell
# Update `resolveArmResources` Use this skill for changes to `resolveArmResources`, `ResolvedResource`, `Provider`, ARM resource operation resolution, selected-version ARM metadata, or integrations that consume this metadata. Read `packages/typespec-azure-resource-manager/proposal/resolve-arm-resources.md` for the base resource graph contract and `website/src/content/docs/docs/howtos/ARM/getting-resource-information.md` for the supported consumer workflow before changing the API or its state and cache behavior. ## Purpose of the API `resolveArmResources(program)` translates ARM decorators and HTTP metadata into a provider model containing: - declared ARM resources; - resource lifecycle, list, action, and associated operations; - non-resource provider operations; - ARM resource type and instance-path identity; - parent and scope relationships; - singleton metadata; and - references to the TypeSpec models and operations that produced the metadata. The no-options API is a multi-version declaration view. A selected-version API must instead return projected types and only declarations available in the requested API version. ## Core invariants Preserve all of these invariants: 1. The no-options result remains backward compatible. 2. A selected-version result never mixes original types with types from a mutation realm. 3. Resource association is based on ARM and HTTP structural metadata before client-facing names are applied. 4. Resource names, operation names, and operation-group names are logical metadata, not wire API. 5. Wire identity never changes through a naming hook. 6. Consumer-specific names never enter a shared provider cache. 7. A call for one version cannot affect another version or the default view. 8. Parent and resource-valued scope references point into the same returned resource graph. 9. Provider operations are selected from the same namespace graph as resources. 10. Decorator state keyed by a projected type is not trusted until embedded type references are checked. 11. Program-wide ARM registration state is never cleared to prepare one selected version. 12. Repeated resolution of the same version reuses the same projected namespace and realm. 13. `ResolvedResource.kind` returns only `Tracked` or `Proxy`. Keep broader resource categories in structural state and map every non-tracked category to `Proxy` during finalization. ## Implementation map Read these files together before editing: | File | Responsibility | | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | | `packages/typespec-azure-resource-manager/src/resource.ts` | Public result types, main resolver, identity parsing, parent and scope resolution, provider operation traversal | | `packages/typespec-azure-resource-manager/src/private.decorators.ts` | Resource registration and `listArmResources` | | `packages/typespec-azure-resource-manager/src/operations.ts` | Resource operation registration and operation state | | `packages/typespec-azure-resource-manager/src/namespace.ts` | Provider namespace registration and lookup | | `packages/typespec-azure-resource-manager/src/state.ts` | ARM state keys | | `packages/typespec-azure-resource-manager/test/resource-resolution.test.ts` | Resolver behavior and regression tests | | `packages/typespec-client-generator-core/src/public-utils.ts` | TCGC `getLibraryName` policy | | `packages/typespec-client-generator-core/src/decorators.ts` | TCGC `@clientName` lookup | | `packages/typespec-client-generator-core/src/internal-utils.ts` | Existing version mutation usage | | `core/packages/versioning/src/mutator.ts` | Snapshot mutator creation | | `core/packages/compiler/src/experimental/mutators.ts` | Mutation and realm creation | | `core/packages/compiler/src/experimental/realm.ts` | Realm ownership and state-map behavior | ## Resolution flow The current resolver: 1. Finds the ARM provider namespace. 2. Checks the resolved-provider cache. 3. Enumerates decorator-registered resource models. 4. Resolves resource operation candidates and HTTP operations. 5. Detects resource identities from strict instance lifecycle paths. 6. Associates non-identity operations. 7. Resolves parent and scope relationships. 8. Collects unassociated provider operations. 9. Caches the provider result. When modifying one stage, inspect its downstream assumptions. Resource names are logical metadata, not wire API, but the current implementation uses them as an internal association signal. External naming must therefore run after association. ## Versioning workflow For a selected API version: 1. Resolve the original provider namespace. 2. Use `getVersioningMutators(program, providerNamespace)`. 3. Match the exact root version value. 4. Apply the snapshot with `unsafe_mutateSubgraphWithNamespace`. 5. Require and cache the returned namespace and non-null realm by program, provider namespace, and version. 6. Resolve from the cached namespace and realm, not by looking up the provider again. 7. Filter enumerated ARM state to exact realm-owned keys. 8. Use the projected provider namespace as the derived provider-cache key. 9. Compute HTTP metadata from projected operations. `getVersioningMutators` creates new mutator objects each time, and the compiler mutation cache keys on mutator identity. Never recreate a snapshot on every resolver call, and never cache only the mutator. Cache the projected namespace and its owning realm together. The default view must explicitly exclude all realm-owned types. Qualified-name deduplication is not enough because historical snapshots can rename a projected type. Do not implement a selected-version view by filtering only the final provider. Projection is required for renames, type changes, optionality changes, removed members, and operation return types. For a multi-service program: 1. Discover service namespaces with `listServices(program)`. 2. Select exact shared `Version` metadata, normally from `getAllVersions(program, namespace)`. 3. Validate that every selected namespace is an ARM provider namespace and every `Version` is the registered object owned by that namespace. 4. Project and resolve each service independently because services can have unrelated version enums while sharing one ARM provider string. 5. Filter realm registrations to types declared under the projected service namespace; mutating one service can re-register sibling-service decorators in the same realm. 6. Finalize each service with its own `Version.value`, then concatenate resources and provider operations in selection order. 7. Return no partial provider if any selection is invalid or cannot be projected. Use namespace and `Version` references for programmatic selection. Do not identify a service by its ARM provider string: Compute subservices all use `Microsoft.Compute`. ## State and cache classification Treat these as registration state: - `armResources` - `armResourceOperations` - `resourceOperationList` - `armResourceOperationData` - `armResourceNameExpression` - `armProviderNamespaces` - `armSingletonResources` - `resourceBaseType` - `armBuiltInResource` - `customAzureResource` Treat these as derived caches: - `armResolvedResources` - `armResourcesCached` When adding a state key, document which class it belongs to. Selected snapshots do not clear these maps: realm-owned keys and the projected provider namespace isolate their derived entries from the declaration view. Realm state maps can fall back to parent program state for original types. An entry visible from a realm is not necessarily owned by that realm. Check `unsafe_Realm.realmForType.get(type) === selectedRealm`. ## Naming integrations The ARM package must not import TCGC. Expose or use a dependency-neutral callback that receives: - name kind, including separate `resource-model` and full `resource` phases; - projected TypeSpec declaration; - current ARM logical name; - selected version; - associated resource model when relevant; - ARM resource type string when relevant; and - resource instance path when the callback needs to distinguish multiple occurrences. Apply naming only after structural resolution. All supported names are non-wire logical metadata: - resource name; - operation name; and - operation-group name. Never change: - provider namespace; - resource type path segments; - resource instance path; - HTTP path or method; - serialized names; - parent or scope identity; or - singleton keys. Do not describe resource names, operation names, or operation-group names as wire API. Only their current use as internal resolver grouping data requires the post-resolution ordering. Use `resourceModel` for the TypeSpec `Model` associated with an operation. Use `resourceType` for the ARM resource type string formatted as `${provider}/${types.join("/")}`. Do not use `resourceType` to refer to a TypeSpec model. Keep `ArmResourceOperation.resourceName` and `resourceModelName` consistent with resource naming. Retain a deferred expression at the decorator boundary instead of reconstructing or editing an eager string. Expressions distinguish explicit values, literals, model operands, concatenation, and legacy path algorithms. Extension and built-in formulas must retain every contributing model. Evaluate the same expression with original model names for grouping and with `resource-model` results for final output. The complete `resource` result runs afterward and has final precedence. Explicit decorator and template names are opaque expressions. Treat undefined and empty template sentinel values as omitted. If multiple identity operations contribute to an occurrence, conservatively retain the explicit expression if any of them supplied the name. Include both the ARM resource type string and instance path in resource naming requests because one model and one resource type can produce several resolved resource occurrences. For example, subscription-scoped and tenant-scoped resources can share the same resource type string while having different instance paths. Resource type alone does not encode scope, parent identifiers, or extension-resource targets. Public instance paths preserve named HTTP parameters such as `{subscriptionId}`. Canonical `{}` segments are only for internal identity comparison and must not replace parameter names in returned provider metadata or naming requests. Track synthetic parents internally and invoke the name resolver with `type: undefined`. Current synthetic parents reuse the child model in their stored `type` field, but that model is not an authoritative declaration for the synthetic resource. Consumers can use `defaultName`, `resourceType`, or `resourceInstancePath` to name synthetic occurrences explicitly. Do not issue `resource-model` requests for synthetic resources. For a TCGC integration test, let the consumer call `getLibraryName` or `getClientNameOverride`. Do not duplicate TCGC precedence in ARM. The implemented consumer adapter is: ```ts resolveArmResources(program, { version, nameResolver: ({ kind, type }) => kind === "resource" || type === undefined ? undefined : getLibraryName(tcgcContext, type), }); ``` ## Required tests Start with failing tests for the requested behavior. ### Compatibility - Existing unversioned result is unchanged. - Existing multi-version result is unchanged when no version is supplied. - Creating a TCGC context before resolution does not create duplicate resources. ### Selected versions Use at least three versions and cover: - resource added and removed; - operation added and removed; - model or operation renamed; - property type changed; - property made optional or required; - operation return type changed; - provider operation filtering; and - parent and scope consistency. Assert returned declared types belong to the selected realm. ### Multi-service selected versions Use one small reusable TypeSpec fixture rather than copying a production specification. Cover: - discovering ARM services and selecting the final declared version of each; - independently versioned services that share one ARM provider string; - one combined provider with resources and provider operations in selection order; - a mixed-version selection and a single-entry selection; - parent and resource-valued scope references into the returned combined graph; - each naming request receiving the selected service's version value; and - atomic diagnostics for empty, duplicate, non-ARM, and mismatched namespace/version selections. Rely on the existing compatibility and call-order suites instead of duplicating them for the multi-service entry point. ### Isolation Run different call orders in one compiled program: - default then V1 then V2; - V2 then V1 then default; - the same version twice; - different name resolvers for the same version; and - named then unnamed resolution. Compare stable scalar projections rather than deeply comparing embedded TypeSpec graphs. Assert realm ownership separately. No custom name may leak to another call. ### Naming - Rename every model operand in standard, extension, built-in, and legacy derived names. - Verify explicit names remain opaque and complete resource overrides have final precedence. - Verify baseline grouping is unchanged by resolver-produced names. - Verify a full, path-specific resource override wins over model-derived naming. - Rename a resource model, operation, and operation interface. - Verify all aliases of one operation receive the same name. - Verify paths and resource type segments remain unchanged. - Verify synthetic parents receive `type: undefined` and can be renamed by default name or path. - Verify synthetic parents receive no `resource-model` request. - Verify empty callback results produce the intended diagnostic behavior. ## Common failure modes - Deduplicating projected and original resources by qualified name. This can choose the original model for a selected version. - Allowing a renamed realm type into the default view because its qualified name differs. - Recreating version mutators and realms for every call. - Caching a mutator without caching the projected namespace and its owning realm. - Calling `resolveProviderNamespace(program)` after mutation. It can return the original namespace. - Traversing all program operations instead of the selected provider namespace. - Reusing `armResolvedResources` for a customized or versioned call. - Mutating a cached `Provider` during post-processing. - Checking only a state-map key while a value still references original types. - Applying TCGC names before resource identity matching. - Passing the reused child model as the authoritative type for a synthetic parent. - Renaming ARM wire resource type segments with a client name. - Clearing ARM registration maps program-wide. - Adding an ARM runtime dependency on TCGC. ## Editing rules - Keep the no-options path explicit and easy to compare with previous behavior. - Prefer a small internal resolution context over optional parameters threaded independently through many helpers. - Use proper TypeScript types; do not use `any` to bypass realm or operation distinctions. - Preserve existing resource graph references when copying results. - Add comments only where realm ownership or cache isolation is non-obvious. - Do not change unrelated resolver heuristics while adding version or naming support. - If changing `.tsp` files, run `tsp format`. - If changing decorator option models in `.tsp`, regenerate TypeScript types with `tspd`. ## Validation Use mise from the repository root: ```powershell mise exec -- pnpm -r --filter "@azure-tools/typespec-azure-resource-manager..." build mise exec -- pnpm --filter "@azure-tools/typespec-azure-resource-manager" test mise exec -- pnpm --filter "@azure-tools/typespec-client-generator-core" test mise exec -- pnpm format mise exec -- pnpm lint ``` During development, use targeted Vitest selectors first. Before a PR, add the required Chronus change description for every affected package.
عرض على GitHub