UNPKG

@azure-tools/typespec-azure-resource-manager

Version:

TypeSpec Azure Resource Manager library

287 lines 12.1 kB
import { $doc, getFriendlyName, ignoreDiagnostics, } from "@typespec/compiler"; import { useStateMap } from "@typespec/compiler/utils"; import { $route, getHttpOperation } from "@typespec/http"; import { $actionSegment, $autoRoute, $createsOrReplacesResource, $deletesResource, $readsResource, $updatesResource, getActionSegment, getParentResource, getSegment, } from "@typespec/rest"; import { reportDiagnostic } from "./lib.js"; import { isArmLibraryNamespace } from "./namespace.js"; import { getArmResourceInfo, getResourceBaseType, isArmVirtualResource, isCustomAzureResource, ResourceBaseType, } from "./resource.js"; import { ArmStateKeys } from "./state.js"; function getArmResourceOperations(program, resourceType) { let operations = program.stateMap(ArmStateKeys.armResourceOperations).get(resourceType); if (!operations) { operations = { lifecycle: {}, lists: {}, actions: {} }; program.stateMap(ArmStateKeys.armResourceOperations).set(resourceType, operations); } return operations; } function resolveHttpOperations(program, data) { const result = {}; for (const [key, item] of Object.entries(data)) { const httpOperation = ignoreDiagnostics(getHttpOperation(program, item.operation)); result[key] = { ...item, path: httpOperation.path, httpOperation: httpOperation, }; } return result; } export function resolveResourceOperations(program, resourceType) { const operations = getArmResourceOperations(program, resourceType); // Returned the updated operations object return { lifecycle: resolveHttpOperations(program, operations.lifecycle), actions: resolveHttpOperations(program, operations.actions), lists: resolveHttpOperations(program, operations.lists), }; } function setResourceLifecycleOperation(context, target, resourceType, kind) { // Only register methods from non-templated interface types if (target.interface === undefined || target.interface.node === undefined || target.interface.node.templateParameters.length > 0) { return; } // We can't resolve the operation path yet so treat the operation as a partial // type so that we can fill in the missing details later const operations = getArmResourceOperations(context.program, resourceType); const operation = { name: target.name, kind, operation: target, operationGroup: target.interface.name, }; operations.lifecycle[kind] = operation; setArmOperationIdentifier(context.program, target, resourceType, { name: target.name, kind: kind, operation: target, operationGroup: target.interface.name, }); } export const [getArmOperationList, setArmOperationList] = useStateMap(ArmStateKeys.resourceOperationList); export function getArmResourceOperationList(program, resourceType) { let operations = getArmOperationList(program, resourceType); if (operations === undefined) { operations = new Set(); setArmOperationList(program, resourceType, operations); } return operations; } export function addArmResourceOperation(program, resourceType, operationData) { const operations = getArmResourceOperationList(program, resourceType); operations.add(operationData); setArmOperationList(program, resourceType, operations); } export const [getArmResourceOperationData, setArmResourceOperationData] = useStateMap(ArmStateKeys.armResourceOperationData); export function setArmOperationIdentifier(program, target, resourceType, data) { const operationId = { name: data.name, kind: data.kind, operation: target, operationGroup: data.operationGroup, resource: resourceType, }; // Initialize the operations for the resource type if not already done if (!getArmResourceOperationData(program, target)) { setArmResourceOperationData(program, target, operationId); } addArmResourceOperation(program, resourceType, operationId); } export const $armResourceRead = (context, target, resourceType) => { context.call($readsResource, target, resourceType); setResourceLifecycleOperation(context, target, resourceType, "read"); }; export const $armResourceCreateOrUpdate = (context, target, resourceType) => { context.call($createsOrReplacesResource, target, resourceType); setResourceLifecycleOperation(context, target, resourceType, "createOrUpdate"); }; export const $armResourceUpdate = (context, target, resourceType) => { context.call($updatesResource, target, resourceType); setResourceLifecycleOperation(context, target, resourceType, "update"); }; export const $armResourceDelete = (context, target, resourceType) => { context.call($deletesResource, target, resourceType); setResourceLifecycleOperation(context, target, resourceType, "delete"); }; export const $armResourceList = (context, target, resourceType) => { // Only register methods from non-templated interface types if (target.interface === undefined || target.interface.node === undefined || target.interface.node.templateParameters.length > 0) { return; } // We can't resolve the operation path yet so treat the operation as a partial // type so that we can fill in the missing details later const operations = getArmResourceOperations(context.program, resourceType); const operation = { name: target.name, kind: "list", operation: target, operationGroup: target.interface.name, }; operations.lists[target.name] = operation; addArmResourceOperation(context.program, resourceType, { name: target.name, kind: "list", operation: target, operationGroup: target.interface.name, resource: resourceType, }); setArmOperationIdentifier(context.program, target, resourceType, { name: target.name, kind: "list", operation: target, operationGroup: target.interface.name, }); }; export function armRenameListByOperationInternal(context, entity, resourceType, parentTypeName, parentFriendlyTypeName, applyOperationRename) { const { program } = context; if (parentTypeName === undefined || parentTypeName === "" || parentFriendlyTypeName === undefined || parentFriendlyTypeName === "") { [parentTypeName, parentFriendlyTypeName] = getArmParentName(context.program, resourceType); } const parentType = getParentResource(program, resourceType); if (parentType && !isArmVirtualResource(program, parentType) && !isCustomAzureResource(program, parentType)) { const parentResourceInfo = getArmResourceInfo(program, parentType); if (!parentResourceInfo && resourceType.namespace !== undefined && isArmLibraryNamespace(program, resourceType.namespace)) return; if (!parentResourceInfo) { reportDiagnostic(program, { code: "parent-type", messageId: "notResourceType", target: resourceType, format: { type: resourceType.name, parent: parentType.name }, }); return; } // Make sure the first character of the name is upper-cased parentTypeName = parentType.name[0].toUpperCase() + parentType.name.substring(1); } // Add a formatted doc string too context.call($doc, entity, `List ${resourceType.name} resources by ${parentType ? parentTypeName : parentFriendlyTypeName}`, undefined); if (applyOperationRename === undefined || applyOperationRename === true) { // Set the operation name entity.name = parentTypeName === "Extension" || parentTypeName === undefined || parentTypeName.length < 1 ? "list" : `listBy${parentTypeName}`; } } function getArmParentName(program, resource) { const parent = getParentResource(program, resource); if (parent && (isArmVirtualResource(program, parent) || isCustomAzureResource(program, parent))) { const parentName = getFriendlyName(program, parent) ?? parent.name; if (parentName === undefined || parentName.length < 2) { return ["", ""]; } return [ parentName, parentName.length > 1 ? parentName.charAt(0).toLowerCase() + parentName.substring(1) : "", ]; } switch (getResourceBaseType(program, resource)) { case ResourceBaseType.Extension: return ["Extension", "parent"]; case ResourceBaseType.Location: return ["Location", "location"]; case ResourceBaseType.Subscription: return ["Subscription", "subscription"]; case ResourceBaseType.Tenant: return ["Tenant", "tenant"]; case ResourceBaseType.ResourceGroup: default: return ["ResourceGroup", "resource group"]; } } export const $armResourceAction = (context, target, resourceType) => { const { program } = context; // Only register methods from non-templated interface types if (target.interface === undefined || target.interface.node === undefined || target.interface.node.templateParameters.length > 0) { return; } // We can't resolve the operation path yet so treat the operation as a partial // type so that we can fill in the missing details later const operations = getArmResourceOperations(program, resourceType); const operation = { name: target.name, kind: "action", operation: target, operationGroup: target.interface.name, }; operations.actions[target.name] = operation; addArmResourceOperation(program, resourceType, { name: target.name, kind: "action", operation: target, operationGroup: target.interface.name, resource: resourceType, }); setArmOperationIdentifier(context.program, target, resourceType, { name: target.name, kind: "action", operation: target, operationGroup: target.interface.name, }); const segment = getSegment(program, target) ?? getActionSegment(program, target); if (!segment) { // Also apply the @actionSegment decorator to the operation context.call($actionSegment, target, uncapitalize(target.name)); } }; function uncapitalize(name) { if (name === "") { return name; } return name[0].toLowerCase() + name.substring(1); } export const $armResourceCollectionAction = (context, target) => { context.program.stateMap(ArmStateKeys.armResourceCollectionAction).set(target, true); }; export function isArmCollectionAction(program, target) { return program.stateMap(ArmStateKeys.armResourceCollectionAction).get(target) === true; } export const $armOperationRoute = (context, target, options) => { const route = options?.route; if (!route && !options?.useStaticRoute) { context.call($autoRoute, target); return; } if (route && route.length > 0) { context.call($route, target, route); } }; export function getRouteOptions(program, target) { let options = undefined; if (target.interface) { options = options || program.stateMap(ArmStateKeys.armResourceRoute).get(target.interface); if (options) return options; } if (target.sourceOperation?.interface) { options = options || program.stateMap(ArmStateKeys.armResourceRoute).get(target.sourceOperation.interface); } if (target.sourceOperation?.interface?.sourceInterfaces[0]) { options = options || program .stateMap(ArmStateKeys.armResourceRoute) .get(target.sourceOperation.interface.sourceInterfaces[0]); } if (options) return options; return { useStaticRoute: false, }; } //# sourceMappingURL=operations.js.map