Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix some warnings in tsp converter #5031

Merged
merged 5 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@autorest/openapi-to-typespec",
"comment": "Fix some warnings in tsp converter",
"type": "patch"
}
],
"packageName": "@autorest/openapi-to-typespec"
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getOptions } from "../options";
import { generateDecorators } from "../utils/decorators";
import { generateDocs } from "../utils/docs";
import { getModelPropertiesDeclarations } from "../utils/model-generation";
import { generateSuppressionForDocumentRequired } from "../utils/suppressions";
import { generateSuppressionForDocumentRequired, generateSuppressions } from "../utils/suppressions";

export function generateObject(typespecObject: TypespecObject) {
const { isFullCompatible } = getOptions();
Expand All @@ -19,6 +19,8 @@ export function generateObject(typespecObject: TypespecObject) {
const decorators = generateDecorators(typespecObject.decorators);
decorators && definitions.push(decorators);

typespecObject.suppressions && definitions.push(...generateSuppressions(typespecObject.suppressions));

if (typespecObject.extendedParents?.length) {
const firstParent = typespecObject.extendedParents[0];
definitions.push(`model ${typespecObject.name} extends ${firstParent} {`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -580,68 +580,73 @@ function convertResourceActionOperations(

if (resourceMetadata.OtherOperations.length) {
for (const operation of resourceMetadata.OtherOperations) {
if (operation.Method === "POST") {
const swaggerOperation = operations[operation.OperationID];
const bodyParam = swaggerOperation.requests?.[0].parameters?.find((p) => p.protocol.http?.in === "body");
const isLongRunning = swaggerOperation.extensions?.["x-ms-long-running-operation"] ?? false;
const okResponse = swaggerOperation?.responses?.filter(
(o) => o.protocol.http?.statusCodes.includes("200"),
)?.[0];
// TODO: deal with non-schema response for action
let operationResponseName;
if (okResponse && isResponseSchema(okResponse)) {
if (!okResponse.schema.language.default.name.includes("·")) {
operationResponseName = okResponse.schema.language.default.name;
if (isResourceListResult(okResponse)) {
const valueSchema = ((okResponse as SchemaResponse).schema as ObjectSchema).properties?.find(
(p) => p.language.default.name === "value",
);
const responseName = dataTypes.get((valueSchema!.schema as ArraySchema).elementType)?.name;
operationResponseName = `ResourceListResult<${responseName ?? "void"}>`;
}
const swaggerOperation = operations[operation.OperationID];
const bodyParam = swaggerOperation.requests?.[0].parameters?.find((p) => p.protocol.http?.in === "body");
const isLongRunning = swaggerOperation.extensions?.["x-ms-long-running-operation"] ?? false;
const okResponse = swaggerOperation?.responses?.filter((o) => o.protocol.http?.statusCodes.includes("200"))?.[0];
// TODO: deal with non-schema response for action
let operationResponseName;
if (okResponse && isResponseSchema(okResponse)) {
if (!okResponse.schema.language.default.name.includes("·")) {
operationResponseName = okResponse.schema.language.default.name;
if (isResourceListResult(okResponse)) {
const valueSchema = ((okResponse as SchemaResponse).schema as ObjectSchema).properties?.find(
(p) => p.language.default.name === "value",
);
const responseName = dataTypes.get((valueSchema!.schema as ArraySchema).elementType)?.name;
operationResponseName = `ResourceListResult<${responseName ?? "void"}>`;
}
}
}

const request = bodyParam ? getTypespecType(bodyParam.schema, getSession().model) : "void";
const parameters = buildOperationParameters(swaggerOperation, resourceMetadata);
let kind;
if (!okResponse) {
// TODO: Sync operation should have a 204 response
kind = isLongRunning ? "ArmResourceActionNoResponseContentAsync" : "ArmResourceActionNoContentSync";
} else {
kind = isLongRunning ? "ArmResourceActionAsync" : "ArmResourceActionSync";
}
const templateParameters = [resourceMetadata.SwaggerModelName, request];
if (okResponse) {
templateParameters.push(operationResponseName ?? "void");
}
if (parameters.baseParameters) {
templateParameters.push(parameters.baseParameters);
}
if (parameters.parameters) {
templateParameters.push(`Parameters = ${parameters.parameters}`);
}

const tspOperationGroupName = getTSPOperationGroupName(resourceMetadata.SwaggerModelName);
const operationName = getOperationName(resourceMetadata.Name, operation.OperationID);
const customizations = getCustomizations(
bodyParam,
tspOperationGroupName,
operationName,
"body",
"The content of the action request",
);
converted.push({
doc: operation.Description,
kind: kind as any,
name: operationName,
clientDecorators: getOperationClientDecorators(swaggerOperation).concat(customizations[1]),
operationId: operation.OperationID,
templateParameters,
examples: swaggerOperation.extensions?.["x-ms-examples"],
customizations: customizations[0],
});
const request = bodyParam ? getTypespecType(bodyParam.schema, getSession().model) : "void";
const parameters = buildOperationParameters(swaggerOperation, resourceMetadata);
let kind;
if (!okResponse) {
// TODO: Sync operation should have a 204 response
kind = isLongRunning ? "ArmResourceActionNoResponseContentAsync" : "ArmResourceActionNoContentSync";
} else {
kind = isLongRunning ? "ArmResourceActionAsync" : "ArmResourceActionSync";
}
const templateParameters = [resourceMetadata.SwaggerModelName, request];
if (okResponse) {
templateParameters.push(operationResponseName ?? "void");
}
if (parameters.baseParameters) {
templateParameters.push(parameters.baseParameters);
}
if (parameters.parameters) {
templateParameters.push(`Parameters = ${parameters.parameters}`);
}

const tspOperationGroupName = getTSPOperationGroupName(resourceMetadata.SwaggerModelName);
const operationName = getOperationName(resourceMetadata.Name, operation.OperationID);
const customizations = getCustomizations(
bodyParam,
tspOperationGroupName,
operationName,
"body",
"The content of the action request",
);

const verbDecorator: TypespecDecorator | undefined =
operation.Method !== "POST"
? {
name: operation.Method.toLocaleLowerCase(),
}
: undefined;

converted.push({
doc: operation.Description,
kind: kind as any,
name: operationName,
clientDecorators: getOperationClientDecorators(swaggerOperation).concat(customizations[1]),
operationId: operation.OperationID,
templateParameters,
examples: swaggerOperation.extensions?.["x-ms-examples"],
customizations: customizations[0],
decorators: verbDecorator !== undefined ? [verbDecorator] : undefined,
});
}
}

Expand Down Expand Up @@ -695,38 +700,6 @@ function convertCheckNameAvailabilityOperations(
return converted;
}

function convertResourceOtherGetOperations(
resourceMetadata: ArmResource,
operations: Record<string, Operation>,
): TypespecOperation[] {
const converted: TypespecOperation[] = [];

if (resourceMetadata.OtherOperations.length) {
for (const operation of resourceMetadata.OtherOperations) {
if (operation.Method === "GET") {
const swaggerOperation = operations[operation.OperationID];
if (swaggerOperation.requests && swaggerOperation.requests[0]) {
const op = transformRequest(
swaggerOperation.requests[0],
swaggerOperation,
getSession().model,
) as TypespecOperation;
op.operationGroupName = getOperationGroupName(operation.OperationID);
op.operationId = operation.OperationID;
if (!op.fixMe) {
op.fixMe = [];
}
op.fixMe.push(`// FIXME: ${operation.OperationID} could not be converted to a resource operation`);
op.examples = swaggerOperation.extensions?.["x-ms-examples"];
converted.push(op);
}
}
}
}

return converted;
}

function getTspOperations(armSchema: ArmResourceSchema): [TspArmResourceOperation[], TypespecOperation[]] {
const resourceMetadata = armSchema.resourceMetadata;
const operations = getResourceOperations(resourceMetadata);
Expand Down Expand Up @@ -759,9 +732,6 @@ function getTspOperations(armSchema: ArmResourceSchema): [TspArmResourceOperatio
// check name availability operation
tspOperations.push(...convertCheckNameAvailabilityOperations(resourceMetadata, operations));

// other get operations
normalOperations.push(...convertResourceOtherGetOperations(resourceMetadata, operations));

return [tspOperations, normalOperations];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { get } from "lodash";
import { getDataTypes } from "../data-types";
import { TypespecObject, TypespecObjectProperty, WithSuppressDirective } from "../interfaces";
import { getOptions } from "../options";
import { addCorePageAlias } from "../utils/alias";
import {
getModelClientDecorators,
Expand All @@ -22,6 +23,7 @@ import {
} from "../utils/decorators";
import { getDiscriminator, getOwnDiscriminator } from "../utils/discriminator";
import { getLogger } from "../utils/logger";
import { ArmResourcePropertiesModel } from "../utils/resource-discovery";
import {
isAnyObjectSchema,
isAnySchema,
Expand All @@ -35,6 +37,7 @@ import {
} from "../utils/schemas";
import {
getPropertySuppressions,
getSuppressionsForModelExtension,
getSuppressionsForProvisioningState,
getSuppressionsForRecordProperty,
} from "../utils/suppressions";
Expand Down Expand Up @@ -64,6 +67,7 @@ const typespecTypes = new Map<string, string>([
]);

export function transformObject(schema: ObjectSchema, codeModel: CodeModel): TypespecObject {
const { isFullCompatible } = getOptions();
const typespecTypes = getDataTypes(codeModel);
let visited: Partial<TypespecObject> = typespecTypes.get(schema) as TypespecObject;
if (visited) {
Expand Down Expand Up @@ -92,7 +96,25 @@ export function transformObject(schema: ObjectSchema, codeModel: CodeModel): Typ
discriminatorProperty && properties.push(discriminatorProperty);
}

const [extendedParents, spreadParents] = getExtendedAndSpreadParents(schema, codeModel);
const [extendedParents, spreadParents, extendSuppressions] = getExtendedAndSpreadParents(schema, codeModel);
const suppressions = extendSuppressions;

if (isFullCompatible && (schema as ArmResourcePropertiesModel).isPropertiesModel === true) {
const provisioningProperty = schema.properties?.find((p) => p.language.default.name === "provisioningState");
if (provisioningProperty === undefined) suppressions.push(...getSuppressionsForProvisioningState());
pshao25 marked this conversation as resolved.
Show resolved Hide resolved
else if (!isChoiceSchema(provisioningProperty.schema) && !isSealedChoiceSchema(provisioningProperty.schema)) {
const provisioningProperty = properties.find((p) => p.name === "provisioningState");
if (provisioningProperty) {
const propertySuppression = provisioningProperty.suppressions ?? [];
propertySuppression.push(...getSuppressionsForProvisioningState());
provisioningProperty.suppressions = propertySuppression;
}
}
}
if (isFullCompatible) {
const provisioningProperty = properties.find((p) => p.name === "provisioningState");
}

const updatedVisited: TypespecObject = {
name,
doc,
Expand All @@ -103,6 +125,7 @@ export function transformObject(schema: ObjectSchema, codeModel: CodeModel): Typ
spreadParents,
decorators: getModelDecorators(schema),
clientDecorators: getModelClientDecorators(schema),
suppressions,
};

addCorePageAlias(updatedVisited);
Expand Down Expand Up @@ -194,7 +217,7 @@ function getParents(schema: ObjectSchema): string[] {
function getExtendedAndSpreadParents(
schema: ObjectSchema,
codeModel: CodeModel,
): [extendedParents: string[], spreadParents: string[]] {
): [extendedParents: string[], spreadParents: string[], suppressions: WithSuppressDirective[]] {
// If there is a discriminative parent: extendedParents = [this discriminative parent], spreadParents = [all the other parents]
// Else if only one parent which is not dictionary: extendedParents = [this parent], spreadParents = []
// Else if only one parent which is dictionary: extendedParents = [], spreadParents = [Record<elementType>]
Expand All @@ -210,18 +233,20 @@ function getExtendedAndSpreadParents(
.map((p) =>
isDictionarySchema(p) ? `Record<${getTypespecType(p.elementType, codeModel)}>` : p.language.default.name,
),
[],
];
}

if (immediateParents.length === 1 && !isDictionarySchema(immediateParents[0])) {
return [[immediateParents[0].language.default.name], []];
return [[immediateParents[0].language.default.name], [], getSuppressionsForModelExtension()];
}

return [
[],
immediateParents.map((p) =>
isDictionarySchema(p) ? `Record<${getTypespecType(p.elementType, codeModel)}>` : p.language.default.name,
),
[],
];
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { readFileSync } from "fs";
import { join } from "path";
import { CodeModel, ObjectSchema, Operation, SchemaResponse } from "@autorest/codemodel";
import { CodeModel, isObjectSchema, ObjectSchema, Operation, SchemaResponse } from "@autorest/codemodel";
import { getArmCommonTypeVersion, getSession } from "../autorest-session";
import { TypespecObject, TspArmResource, TypespecEnum } from "../interfaces";
import { getSkipList } from "./type-mapping";
Expand Down Expand Up @@ -127,12 +127,20 @@ export interface ArmResourceSchema extends ObjectSchema {
resourceMetadata: ArmResource;
}

export interface ArmResourcePropertiesModel extends ObjectSchema {
isPropertiesModel: boolean;
}

export function tagSchemaAsResource(schema: ObjectSchema, metadata: Metadata): void {
const resourcesMetadata = metadata.Resources;

for (const resourceName in resourcesMetadata) {
if (resourcesMetadata[resourceName].SwaggerModelName === schema.language.default.name) {
(schema as ArmResourceSchema).resourceMetadata = resourcesMetadata[resourceName];
const propertiesModel = schema.properties?.find((p) => p.serializedName === "properties");
if (propertiesModel && isObjectSchema(propertiesModel.schema)) {
(propertiesModel.schema as ArmResourcePropertiesModel).isPropertiesModel = true;
}
return;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ export function getSuppressionsForArmResourceDeleteSync(): WithSuppressDirective
];
}

export function getSuppressionsForModelExtension(): WithSuppressDirective[] {
return [
{
suppressionCode: "@azure-tools/typespec-azure-core/composition-over-inheritance",
suppressionMessage: "For backward compatibility",
},
];
}

export function getSuppressionsForRecordProperty(): WithSuppressDirective[] {
return [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ model CreateDeploymentOptions {
/**
* Represents the state of a deployment job.
*/
#suppress "@azure-tools/typespec-azure-core/composition-over-inheritance" "For backward compatibility"
model DeploymentJobState extends JobState {}

/**
Expand Down Expand Up @@ -532,6 +533,7 @@ model Warning {
/**
* Represents the state of an export job.
*/
#suppress "@azure-tools/typespec-azure-core/composition-over-inheritance" "For backward compatibility"
model ExportProjectJobState extends JobState {
/**
* The URL to use in order to download the exported project.
Expand All @@ -542,6 +544,7 @@ model ExportProjectJobState extends JobState {
/**
* Represents the state of an import job.
*/
#suppress "@azure-tools/typespec-azure-core/composition-over-inheritance" "For backward compatibility"
model ImportProjectJobState extends JobState {}

/**
Expand Down Expand Up @@ -634,6 +637,7 @@ model TrainingJobs is Azure.Core.Page<TrainingJobState>;
/**
* Represents the state of a training job.
*/
#suppress "@azure-tools/typespec-azure-core/composition-over-inheritance" "For backward compatibility"
model TrainingJobState extends JobState {
/**
* Represents training tasks detailed result.
Expand Down Expand Up @@ -702,6 +706,7 @@ model SubTrainingJobState {
/**
* Represents the state of a project deletion job.
*/
#suppress "@azure-tools/typespec-azure-core/composition-over-inheritance" "For backward compatibility"
model ProjectDeletionJobState extends JobState {}

/**
Expand Down
Loading
Loading