in packages/extensions/openapi-to-typespec/src/transforms/transform-operations.ts [109:227]
export function transformRequest(
_request: Request,
operation: Operation,
codeModel: CodeModel,
groupName: string | undefined = undefined,
): TypespecOperation | TspArmProviderActionOperation {
const { isFullCompatible, isArm } = getOptions();
const { language, responses, requests } = operation;
const name = _.lowerFirst(language.default.name);
const doc = language.default.description;
const summary = language.default.summary;
const { paging } = getLanguageMetadata(operation.language);
const transformedResponses = transformResponses(responses ?? []);
const visitedParameter: Set<Parameter> = new Set();
let parameters = (operation.parameters ?? [])
.filter((p) => filterOperationParameters(p, visitedParameter))
.map((v) => transformParameter(v, codeModel));
parameters = [
...parameters,
...getRequestParameters(operation)
.filter((p) => filterOperationParameters(p, visitedParameter))
.map((v) => transformParameter(v, codeModel)),
];
const extensions: Extension[] = [];
if (paging) {
extensions.push("Pageable");
}
const resource = operation.language.default.resource;
let decorators: TypespecDecorator[] | undefined = undefined;
if (
groupName &&
operation.operationId &&
operation.operationId !== `${Case.pascal(groupName)}_${Case.pascal(name)}`
) {
const decorator = createOperationIdDecorator(operation.operationId!);
if (isFullCompatible) {
decorator.suppressionCode = "@azure-tools/typespec-azure-core/no-openapi";
decorator.suppressionMessage = "non-standard operations";
}
decorators = [decorator];
}
if (isArm) {
const route = transformRoute(requests?.[0].protocol);
if (route.startsWith("/subscriptions/{subscriptionId}/providers/") || route.startsWith("/providers/")) {
const action = getActionForPrviderTemplate(route);
if (action !== undefined) {
const isLongRunning = operation.extensions?.["x-ms-long-running-operation"] ?? false;
decorators ??= [];
decorators.push({
name: "autoRoute",
module: "@typespec/rest",
namespace: "TypeSpec.Rest",
});
const verb = transformVerb(requests?.[0].protocol);
// For Async, there should be a 202 response without body and might be a 200 response with body
// For Sync, there might be a 200 response with body
const response = transformedResponses.find((r) => r[0] === "200")?.[1] ?? undefined;
const finalStateVia =
operation.extensions?.["x-ms-long-running-operation-options"]?.["final-state-via"] ?? "location";
const lroHeaders =
isLongRunning && finalStateVia === "azure-async-operation" ? "Azure-AsyncOperation" : undefined;
const suppressions =
isFullCompatible && lroHeaders ? [getSuppressionWithCode(SuppressionCode.LroLocationHeader)] : undefined;
return {
kind: isLongRunning ? "ArmProviderActionAsync" : "ArmProviderActionSync",
doc,
summary,
name,
verb: verb === "post" ? undefined : verb,
action: action === name ? undefined : action,
scope: route.startsWith("/providers/") ? undefined : "SubscriptionActionScope",
response,
parameters: parameters
.filter((p) => p.location !== "body")
.map((p) => {
if (p.location === "path") {
const segment = getSegmentForPathParameter(route, p.name);
if (p.decorators === undefined) p.decorators = [];
p.decorators.push({
name: "segment",
arguments: [segment],
});
}
return p;
}),
request: parameters.find((p) => p.location === "body"),
decorators,
lroHeaders,
suppressions,
examples: operation.extensions?.["x-ms-examples"],
operationId: operation.operationId,
};
}
}
}
return {
name,
doc,
summary,
parameters,
clientDecorators: getOperationClientDecorators(operation),
verb: transformVerb(requests?.[0].protocol),
route: transformRoute(requests?.[0].protocol),
responses: transformedResponses,
extensions: [],
resource,
decorators,
examples: operation.extensions?.["x-ms-examples"],
operationId: operation.operationId,
};
}