Inlcude csharp rename decorator when openai-to-typespec generating tsp (#4907)

Fixes https://github.com/Azure/autorest.csharp/issues/4236.
Generate csharp renaming decorator when openai-to-typespec generating
tsp. (include rename of resource, resource.property, model,
model.property, enum, enum.member and operation name)

related autorest.csharp change can be found at
https://github.com/Azure/autorest.csharp/pull/4380
This commit is contained in:
Rodge Fu 2024-03-19 21:20:34 +08:00 коммит произвёл GitHub
Родитель cc5a4dc000
Коммит 63ffe68961
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
16 изменённых файлов: 357 добавлений и 35 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -296,3 +296,4 @@ regression-tests/output
# TS incremental build cache
*.tsbuildinfo
*.njsproj

Просмотреть файл

@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@autorest/openapi-to-typespec",
"comment": "support generating csharp rename decorator when converting to tsp",
"type": "minor"
}
],
"packageName": "@autorest/openapi-to-typespec"
}

Просмотреть файл

@ -10,20 +10,18 @@
#>
param(
[Parameter(Mandatory)]
[string]
# Specifies the swagger config file, not the swagger json, but the readme config.
[Parameter(Mandatory = $true, HelpMessage = "Specifies the swagger config file (not the swagger json, but the readme config) or autorest.md file in the azure-sdk-for-net repo if .net related configuration is expected to be included.")]
[string]
$swaggerConfigFile,
[Parameter(Mandatory = $false, HelpMessage = "Specified the output folder, deafult to current folder.")]
[string]
# Specified the output folder, deafult to current folder.
$outputFolder,
[Parameter(Mandatory = $false, HelpMessage = "Specified the csharp codegen, default to https://aka.ms/azsdk/openapi-to-typespec-csharp.")]
[string]
# Specified the csharp codegen, default to https://aka.ms/azsdk/openapi-to-typespec-csharp.
$csharpCodegen = "https://aka.ms/azsdk/openapi-to-typespec-csharp",
[Parameter(Mandatory = $false, HelpMessage = "Specified the converter codegen, default to https://aka.ms/azsdk/openapi-to-typespec.")]
[string]
# Specified the converter codegen, default to https://aka.ms/azsdk/openapi-to-typespec.
$converterCodegen = "."
)
$converterCodegen = ".")
function GenerateMetadata ()
{
@ -42,7 +40,7 @@ function GenerateMetadata ()
function DoConvert ()
{
Write-Host "##Converting from swagger to tsp with in $outputFolder with $converterCodegen"
$cmd = "autorest --version=3.10.1 --openapi-to-typespec --isAzureSpec --isArm --use=`"$converterCodegen`" --output-folder=$outputFolder $swaggerConfigFile"
$cmd = "autorest --version=3.10.1 --openapi-to-typespec --csharp=false --isAzureSpec --isArm --use=`"$converterCodegen`" --output-folder=$outputFolder $swaggerConfigFile"
Write-Host "$cmd"
Invoke-Expression $cmd
if ($LASTEXITCODE) { exit $LASTEXITCODE }

Просмотреть файл

@ -1,5 +1,9 @@
import { getSession } from "../autorest-session";
import { generateArmResourceClientDecorator, generateObjectClientDecorator } from "../generate/generate-client";
import {
generateArmResourceClientDecorator,
generateEnumClientDecorator,
generateObjectClientDecorator,
} from "../generate/generate-client";
import { TypespecProgram } from "../interfaces";
import { getOptions } from "../options";
import { formatTypespecFile } from "../utils/format";
@ -34,8 +38,14 @@ function generateClient(program: TypespecProgram) {
.filter((r) => r !== "")
.join("\n\n")
: "";
if (objects === "" && armResources === "") {
const enums = models.enums
.map(generateEnumClientDecorator)
.filter((r) => r !== "")
.join("\n\n");
if (objects === "" && armResources === "" && enums === "") {
return "";
}
return [imports, "\n", namespaces, "\n", objects, "\n", armResources].join("\n");
return [imports, "\n", namespaces, "\n", objects, "\n", armResources, "\n", enums].join("\n");
}

Просмотреть файл

@ -51,8 +51,8 @@ function getArmResourceImports(program: TypespecProgram): string[] {
const resourceMetadata = getArmResourcesMetadata();
const imports: string[] = [];
for (const resource in resourceMetadata) {
imports.push(`import "./${resourceMetadata[resource].SwaggerModelName}.tsp";`);
for (const resource in resourceMetadata.Resources) {
imports.push(`import "./${resourceMetadata.Resources[resource].SwaggerModelName}.tsp";`);
}
if (program.operationGroups.length > 0) {

Просмотреть файл

@ -1,10 +1,12 @@
import pluralize from "pluralize";
import { TspArmResource, TypespecObject } from "../interfaces";
import { TspArmResource, TypespecObject, TypespecEnum, TypespecOperation } from "../interfaces";
import { generateAugmentedDecorators } from "../utils/decorators";
export function generateObjectClientDecorator(typespecObject: TypespecObject) {
const definitions: string[] = [];
definitions.push(generateAugmentedDecorators(typespecObject.name, typespecObject.clientDecorators));
for (const property of typespecObject.properties) {
const decorators = generateAugmentedDecorators(
`${typespecObject.name}.${property.name}`,
@ -16,11 +18,50 @@ export function generateObjectClientDecorator(typespecObject: TypespecObject) {
return definitions.join("\n");
}
export function generateEnumClientDecorator(typespecEnum: TypespecEnum) {
const definitions: string[] = [];
definitions.push(generateAugmentedDecorators(typespecEnum.name, typespecEnum.clientDecorators));
for (const choice of typespecEnum.members) {
const decorators = generateAugmentedDecorators(`${typespecEnum.name}.${choice.name}`, choice.clientDecorators);
decorators && definitions.push(decorators);
}
return definitions.join("\n");
}
export function generateOperationClientDecorator(operation: TypespecOperation) {
const definitions: string[] = [];
definitions.push(generateAugmentedDecorators(operation.name, operation.clientDecorators));
return definitions.join("\n");
}
export function generateArmResourceClientDecorator(resource: TspArmResource): string {
const definitions: string[] = [];
const formalOperationGroupName = pluralize(resource.name);
let targetName = formalOperationGroupName;
if (resource.name === formalOperationGroupName) {
return `@@clientName(${formalOperationGroupName}OperationGroup, "${formalOperationGroupName}")`;
targetName = `${formalOperationGroupName}OperationGroup}`;
definitions.push(`@@clientName(${formalOperationGroupName}OperationGroup, "${formalOperationGroupName}")`);
}
return "";
if (resource.clientDecorators && resource.clientDecorators.length > 0)
definitions.push(generateAugmentedDecorators(resource.name, resource.clientDecorators));
for (const op of resource.resourceOperations) {
if (op.clientDecorators && op.clientDecorators.length > 0)
definitions.push(generateAugmentedDecorators(`${targetName}.${op.name}`, op.clientDecorators));
}
for (const property of resource.properties) {
const decorators = generateAugmentedDecorators(`${targetName}.${property.name}`, property.clientDecorators);
decorators && definitions.push(decorators);
}
return definitions.join("\n");
}

Просмотреть файл

@ -15,6 +15,7 @@ export interface TypespecOptions {
export interface TypespecChoiceValue extends WithDoc {
name: string;
value: string | number | boolean;
clientDecorators?: TypespecDecorator[];
}
export interface WithDoc {
@ -42,6 +43,7 @@ export interface TypespecOperation extends WithDoc, WithSummary, WithFixMe {
operationGroupName?: string;
operationId?: string;
examples?: Record<string, Record<string, unknown>>;
clientDecorators?: TypespecDecorator[];
}
export type ResourceKind =
@ -120,6 +122,7 @@ export interface TypespecEnum extends TypespecDataType {
members: TypespecChoiceValue[];
isExtensible: boolean;
decorators?: TypespecDecorator[];
clientDecorators?: TypespecDecorator[];
}
export interface WithFixMe {
@ -137,6 +140,7 @@ export interface TypespecParameter extends TypespecDataType {
isOptional: boolean;
type: string;
decorators?: TypespecDecorator[];
clientDecorators?: TypespecDecorator[];
location: TypespecParameterLocation;
serializedName: string;
defaultValue?: any;
@ -171,6 +175,7 @@ export interface TypespecObject extends TypespecDataType {
extendedParents?: string[];
spreadParents?: string[];
decorators?: TypespecDecorator[];
clientDecorators?: TypespecDecorator[];
alias?: TypespecAlias;
}
@ -201,6 +206,7 @@ export interface TspArmResourceOperationBase extends WithDoc, WithFixMe {
name: string;
templateParameters?: string[];
decorators?: TypespecDecorator[];
clientDecorators?: TypespecDecorator[];
operationId?: string;
examples?: Record<string, Record<string, unknown>>;
customizations?: string[];

Просмотреть файл

@ -17,6 +17,7 @@ import { emitTypespecConfig } from "./emiters/emit-typespec-config";
import { getModel } from "./model";
import { pretransformArmResources } from "./pretransforms/arm-pretransform";
import { pretransformNames } from "./pretransforms/name-pretransform";
import { pretransformRename } from "./pretransforms/rename-pretransform";
import { markErrorModels } from "./utils/errors";
import { markPagination } from "./utils/paging";
import { markResources } from "./utils/resources";
@ -27,6 +28,7 @@ export async function processConverter(host: AutorestExtensionHost) {
const codeModel = session.model;
pretransformNames(codeModel);
pretransformArmResources(codeModel);
pretransformRename(codeModel);
markPagination(codeModel);
markErrorModels(codeModel);
markResources(codeModel);

Просмотреть файл

@ -0,0 +1,136 @@
import {
ChoiceSchema,
CodeModel,
ObjectSchema,
SealedChoiceSchema,
Schema,
ChoiceValue,
Property,
Parameter,
SchemaType,
Operation,
} from "@autorest/codemodel";
import { TypespecDecorator } from "../interfaces";
import { getOptions } from "../options";
import { getLogger } from "../utils/logger";
import { Metadata, getArmResourcesMetadata } from "../utils/resource-discovery";
type RenamableSchema = Schema | Property | Parameter | ChoiceValue | Operation;
const logger = () => getLogger("rename-pretransform");
export function pretransformRename(codeModel: CodeModel): void {
const { isArm } = getOptions();
if (!isArm) {
return;
}
const metadata = getArmResourcesMetadata();
applyRenameMapping(metadata, codeModel);
applyOverrideOperationName(metadata, codeModel);
}
export function createCSharpNameDecorator(schema: RenamableSchema): TypespecDecorator {
return {
name: "clientName",
module: "@azure-tools/typespec-client-generator-core",
namespace: "Azure.ClientGenerator.Core",
arguments: [schema.language.csharp!.name, "csharp"],
};
}
function parseNewCSharpNameAndSetToSchema(schema: RenamableSchema, renameValue: string) {
const newName = parseNewName(renameValue);
setSchemaCSharpName(schema, newName);
}
function setSchemaCSharpName(schema: RenamableSchema, newName: string) {
if (!schema.language.csharp)
schema.language.csharp = { name: newName, description: schema.language.default.description };
else schema.language.csharp.name = newName;
}
function parseNewName(value: string) {
// TODO: format not supported
return value.split("|")[0].trim();
}
function applyOverrideOperationName(metadata: Metadata, codeModel: CodeModel) {
for (const opId in metadata.OverrideOperationName) {
const found = codeModel.operationGroups.flatMap((og) => og.operations).find((op) => op.operationId === opId);
if (found) parseNewCSharpNameAndSetToSchema(found, metadata.OverrideOperationName[opId]);
else
logger().warning(
`Can't find operation to rename for OverrideOperationName rule: ${opId}->${metadata.OverrideOperationName[opId]}`,
);
}
}
function applyRenameMapping(metadata: Metadata, codeModel: CodeModel) {
for (const key in metadata.RenameMapping) {
const subKeys = key
.split(".")
.map((s) => s.trim())
.filter((s) => s.length > 0);
if (subKeys.length === 0) continue;
const lowerFirstSubKey = subKeys[0].toLowerCase();
const value = metadata.RenameMapping[key];
const found: Schema | undefined = [
...(codeModel.schemas.choices ?? []),
...(codeModel.schemas.sealedChoices ?? []),
...(codeModel.schemas.objects ?? []),
].find((o: Schema) => o.language.default.name.toLowerCase() === lowerFirstSubKey);
if (!found) {
logger().warning(`Can't find object or enum for RenameMapping rule: ${key} -> ${value}`);
continue;
}
if (found.type === SchemaType.Choice || found.type == SchemaType.SealedChoice) {
transformEnum(subKeys, value, found as ChoiceSchema | SealedChoiceSchema);
} else if (found.type === SchemaType.Object) {
transformObject(subKeys, value, found as ObjectSchema);
} else {
logger().error(`Unexpected schema type '${found.type}' found with key ${key}`);
}
}
}
function transformEnum(keys: string[], value: string, target: ChoiceSchema | SealedChoiceSchema) {
if (keys.length === 1) parseNewCSharpNameAndSetToSchema(target, value);
else if (keys.length === 2) {
const lowerMemberValue = keys[1].toLowerCase();
const found = target.choices.find((c) => c.language.default.name.toLowerCase() === lowerMemberValue);
if (found) parseNewCSharpNameAndSetToSchema(found, value);
else logger().warning(`Can't find enum member for RenameMapping rule: ${keys.join(".")} -> ${value}`);
} else {
logger().error(`Unexpected keys for enum RenameMapping: ${keys.join(".")}`);
}
}
function transformObject(keys: string[], value: string, target: ObjectSchema) {
if (keys.length === 1) parseNewCSharpNameAndSetToSchema(target, value);
else if (keys.length === 2) {
const lowerPropertyName = keys[1].toLowerCase();
const found = target.properties?.find((p) => p.language.default.name.toLowerCase() === lowerPropertyName);
if (found) parseNewCSharpNameAndSetToSchema(found, value);
else logger().warning(`Can't find object property for RenameMapping rule: ${keys.join(".")} -> ${value}`);
} else if (keys.length > 2) {
// handle flatten scenario
const lowerPropName = keys.pop()?.toLowerCase();
let cur = target;
for (let i = 1; i < keys.length && cur; i++) {
const foundProp = cur.properties?.find((p) => p.language.default.name.toLowerCase() === keys[i].toLowerCase());
cur = foundProp?.schema as ObjectSchema;
}
const foundProp = cur?.properties?.find((p) => p.language.default.name.toLowerCase() === lowerPropName);
if (foundProp) parseNewCSharpNameAndSetToSchema(foundProp, value);
else {
logger().warning(`Can't find object property for RenameMapping rule: ${keys.join(".")} -> ${value}`);
}
} else {
logger().error(`Unexpected keys for object property RenameMapping: ${keys.join(".")}`);
}
}

Просмотреть файл

@ -14,6 +14,8 @@ import {
isFirstLevelResource,
} from "../interfaces";
import { getOptions, updateOptions } from "../options";
import { createCSharpNameDecorator } from "../pretransforms/rename-pretransform";
import { getOperationClientDecorators } from "../utils/decorators";
import {
ArmResource,
ArmResourceSchema,
@ -105,6 +107,11 @@ export function transformTspArmResource(schema: ArmResourceSchema): TspArmResour
decorators.push({ name: "extensionResource" });
}
const armResourceOperations = operations[0];
const otherOperations = operations[1];
const clientDecorators = buildResourceClientDecorators(schema, armResourceOperations, otherOperations);
return {
fixMe,
resourceKind: getResourceKind(schema),
@ -119,8 +126,9 @@ export function transformTspArmResource(schema: ArmResourceSchema): TspArmResour
propertiesPropertyDescription,
doc: schema.language.default.description,
decorators,
resourceOperations: operations[0],
normalOperations: operations[1],
clientDecorators,
resourceOperations: armResourceOperations,
normalOperations: otherOperations,
optionalStandardProperties: getArmCommonTypeVersion() ? getResourceOptionalStandardProperties(schema) : [],
baseModelName,
locationParent: getLocationParent(schema),
@ -190,6 +198,7 @@ function convertResourceReadOperation(
kind: "ArmResourceRead",
name: getOperationName(operation.OperationID),
operationId: operation.OperationID,
clientDecorators: getOperationClientDecorators(swaggerOperation),
templateParameters: baseParameters
? [resourceMetadata.SwaggerModelName, baseParameters]
: [resourceMetadata.SwaggerModelName],
@ -206,6 +215,7 @@ function convertResourceExistsOperation(resourceMetadata: ArmResource): TspArmRe
doc: swaggerOperation.language.default.description,
kind: "ArmResourceExists",
name: swaggerOperation.operationId ? getOperationName(swaggerOperation.operationId) : "exists",
clientDecorators: getOperationClientDecorators(swaggerOperation),
operationId: swaggerOperation.operationId,
parameters: [
`...ResourceInstanceParameters<${resourceMetadata.SwaggerModelName}, BaseParameters<${resourceMetadata.SwaggerModelName}>>`,
@ -256,6 +266,7 @@ function convertResourceCreateOrReplaceOperation(
doc: operation.Description,
kind: isLongRunning ? "ArmResourceCreateOrReplaceAsync" : "ArmResourceCreateOrReplaceSync",
name: operationName,
clientDecorators: getOperationClientDecorators(swaggerOperation),
operationId: operation.OperationID,
templateParameters: templateParameters,
examples: swaggerOperation.extensions?.["x-ms-examples"],
@ -343,6 +354,7 @@ function convertResourceUpdateOperation(
doc: operation.Description,
kind: kind as any,
name: getOperationName(operation.OperationID),
clientDecorators: getOperationClientDecorators(swaggerOperation),
operationId: operation.OperationID,
templateParameters,
examples: swaggerOperation.extensions?.["x-ms-examples"],
@ -379,6 +391,7 @@ function convertResourceDeleteOperation(
: "ArmResourceDeleteWithoutOkAsync"
: "ArmResourceDeleteSync",
name: getOperationName(operation.OperationID),
clientDecorators: getOperationClientDecorators(swaggerOperation),
operationId: operation.OperationID,
templateParameters,
examples: swaggerOperation.extensions?.["x-ms-examples"],
@ -415,6 +428,7 @@ function convertResourceListOperations(
doc: operation.Description,
kind: "ArmResourceListByParent",
name: getOperationName(operation.OperationID),
clientDecorators: getOperationClientDecorators(swaggerOperation),
operationId: operation.OperationID,
templateParameters: templateParameters,
examples: swaggerOperation.extensions?.["x-ms-examples"],
@ -448,6 +462,7 @@ function convertResourceListOperations(
doc: operation.Description,
kind: "ArmResourceListAtScope",
name: getOperationName(operation.OperationID),
clientDecorators: getOperationClientDecorators(swaggerOperation),
operationId: operation.OperationID,
templateParameters,
examples: swaggerOperation.extensions?.["x-ms-examples"],
@ -457,6 +472,7 @@ function convertResourceListOperations(
doc: operation.Description,
kind: "ArmListBySubscription",
name: getOperationName(operation.OperationID),
clientDecorators: getOperationClientDecorators(swaggerOperation),
operationId: operation.OperationID,
templateParameters: [resourceMetadata.SwaggerModelName],
examples: swaggerOperation.extensions?.["x-ms-examples"],
@ -483,6 +499,7 @@ function convertResourceListOperations(
name: swaggerOperation.operationId
? getOperationName(swaggerOperation.operationId)
: `listBy${resourceMetadata.Parents[0].replace(/Resource$/, "")}`,
clientDecorators: getOperationClientDecorators(swaggerOperation),
operationId: swaggerOperation.operationId,
templateParameters: baseParameters
? [resourceMetadata.SwaggerModelName, baseParameters]
@ -549,6 +566,7 @@ function convertResourceActionOperations(
doc: operation.Description,
kind: kind as any,
name: operationName,
clientDecorators: getOperationClientDecorators(swaggerOperation),
operationId: operation.OperationID,
templateParameters,
examples: swaggerOperation.extensions?.["x-ms-examples"],
@ -585,6 +603,7 @@ function convertCheckNameAvailabilityOperations(
doc: operation.Description,
kind: "checkLocalNameAvailability",
name: getOperationName(operation.OperationID),
clientDecorators: getOperationClientDecorators(swaggerOperation),
operationId: operation.OperationID,
examples: swaggerOperation.extensions?.["x-ms-examples"],
templateParameters: [request, response],
@ -594,6 +613,7 @@ function convertCheckNameAvailabilityOperations(
doc: operation.Description,
kind: "checkGlobalNameAvailability",
name: getOperationName(operation.OperationID),
clientDecorators: getOperationClientDecorators(swaggerOperation),
operationId: operation.OperationID,
examples: swaggerOperation.extensions?.["x-ms-examples"],
templateParameters: [request, response],
@ -860,6 +880,19 @@ function buildResourceDecorators(schema: ArmResourceSchema): TypespecDecorator[]
return resourceModelDecorators;
}
function buildResourceClientDecorators(
schema: ArmResourceSchema,
armResourceOperations: TspArmResourceOperation[],
normalOperations: TypespecOperation[],
): TypespecDecorator[] {
const clientDecorator: TypespecDecorator[] = [];
if (schema.language.csharp?.name) {
clientDecorator.push(createCSharpNameDecorator(schema));
}
return clientDecorator;
}
function getSingletonName(schema: ArmResourceSchema): string {
const key = schema.resourceMetadata.ResourceKey;
const pathLast = schema.resourceMetadata.GetOperations[0].Path.split("/").pop() ?? "";

Просмотреть файл

@ -1,7 +1,7 @@
import { ChoiceSchema, ChoiceValue, CodeModel, SchemaType, SealedChoiceSchema } from "@autorest/codemodel";
import { getDataTypes } from "../data-types";
import { TypespecChoiceValue, TypespecEnum } from "../interfaces";
import { getEnumDecorators } from "../utils/decorators";
import { getEnumChoiceClientDecorators, getEnumClientDecorators, getEnumDecorators } from "../utils/decorators";
import { transformValue } from "../utils/values";
export function transformEnum(schema: SealedChoiceSchema | ChoiceSchema, codeModel: CodeModel): TypespecEnum {
@ -12,6 +12,7 @@ export function transformEnum(schema: SealedChoiceSchema | ChoiceSchema, codeMod
if (!typespecEnum) {
typespecEnum = {
decorators: getEnumDecorators(schema),
clientDecorators: getEnumClientDecorators(schema),
doc: schema.language.default.description,
kind: "enum",
name: schema.language.default.name.replace(/-/g, "_"),
@ -36,6 +37,7 @@ function transformChoiceMember(member: ChoiceValue): TypespecChoiceValue {
doc: member.language.default.description,
name: member.language.default.name,
value: transformValue(member.value),
clientDecorators: getEnumChoiceClientDecorators(member),
};
}

Просмотреть файл

@ -14,7 +14,12 @@ import { get } from "lodash";
import { getDataTypes } from "../data-types";
import { TypespecObject, TypespecObjectProperty } from "../interfaces";
import { addCorePageAlias } from "../utils/alias";
import { getModelDecorators, getPropertyClientDecorators, getPropertyDecorators } from "../utils/decorators";
import {
getModelClientDecorators,
getModelDecorators,
getPropertyClientDecorators,
getPropertyDecorators,
} from "../utils/decorators";
import { getDiscriminator, getOwnDiscriminator } from "../utils/discriminator";
import { getLogger } from "../utils/logger";
import {
@ -89,6 +94,7 @@ export function transformObject(schema: ObjectSchema, codeModel: CodeModel): Typ
extendedParents: getExtendedParents(schema),
spreadParents: getSpreadParents(schema, codeModel),
decorators: getModelDecorators(schema),
clientDecorators: getModelClientDecorators(schema),
};
addCorePageAlias(updatedVisited);

Просмотреть файл

@ -21,7 +21,7 @@ import {
} from "../interfaces";
import { transformDataType } from "../model";
import { getOptions } from "../options";
import { getPropertyDecorators } from "../utils/decorators";
import { getOperationClientDecorators, getPropertyDecorators } from "../utils/decorators";
import { getLogger } from "../utils/logger";
import { getLanguageMetadata } from "../utils/metadata";
import { isConstantSchema } from "../utils/schemas";
@ -114,6 +114,7 @@ export function transformRequest(_request: Request, operation: Operation, codeMo
doc,
summary,
parameters,
clientDecorators: getOperationClientDecorators(operation),
verb: transformVerb(requests?.[0].protocol),
route: transformRoute(requests?.[0].protocol),
responses: [...new Set(transformedResponses)],

Просмотреть файл

@ -1,15 +1,18 @@
import {
ChoiceSchema,
ObjectSchema,
ChoiceValue,
Parameter,
Property,
Schema,
SchemaType,
SealedChoiceSchema,
SerializationStyle,
Operation,
isNumberSchema,
} from "@autorest/codemodel";
import { TypespecDecorator, DecoratorArgument } from "../interfaces";
import { createCSharpNameDecorator } from "../pretransforms/rename-pretransform";
import { getOwnDiscriminator } from "./discriminator";
import { isSealedChoiceSchema, isStringSchema } from "./schemas";
@ -55,6 +58,15 @@ export function getModelDecorators(model: ObjectSchema): TypespecDecorator[] {
return decorators;
}
export function getModelClientDecorators(model: ObjectSchema): TypespecDecorator[] {
const decorators: TypespecDecorator[] = [];
if (model.language.csharp?.name) {
decorators.push(createCSharpNameDecorator(model));
}
return decorators;
}
export function getPropertyDecorators(element: Property | Parameter): TypespecDecorator[] {
const decorators: TypespecDecorator[] = [];
@ -153,6 +165,10 @@ export function getPropertyClientDecorators(element: Property | Parameter): Type
});
}
if (element.language.csharp?.name) {
decorators.push(createCSharpNameDecorator(element));
}
return decorators;
}
@ -240,6 +256,35 @@ export function getEnumDecorators(enumeration: SealedChoiceSchema | ChoiceSchema
return decorators;
}
export function getEnumClientDecorators(enumeration: SealedChoiceSchema | ChoiceSchema): TypespecDecorator[] {
const decorators: TypespecDecorator[] = [];
if (enumeration.language.csharp?.name) {
decorators.push(createCSharpNameDecorator(enumeration));
}
return decorators;
}
export function getEnumChoiceClientDecorators(enumChoice: ChoiceValue): TypespecDecorator[] {
const decorators: TypespecDecorator[] = [];
if (enumChoice.language.csharp?.name) {
decorators.push(createCSharpNameDecorator(enumChoice));
}
return decorators;
}
export function getOperationClientDecorators(operation: Operation): TypespecDecorator[] {
const decorators: TypespecDecorator[] = [];
if (operation.language.csharp?.name) {
decorators.push(createCSharpNameDecorator(operation));
}
return decorators;
}
export function generateDecorators(decorators: TypespecDecorator[] = []): string {
const definitions: string[] = [];
for (const decorator of decorators ?? []) {

Просмотреть файл

@ -1,4 +1,4 @@
import { TypespecProgram } from "../interfaces";
import { TypespecDecorator, TypespecProgram } from "../interfaces";
import { getOptions } from "../options";
type Imports = {
@ -46,12 +46,36 @@ export function getModelsImports(program: TypespecProgram) {
export function getClientImports(program: TypespecProgram) {
const modules = new Set<string>();
const namespaces = new Set<string>();
const addImports = (decs: TypespecDecorator[] | undefined) => {
for (const dec of decs ?? []) {
dec.module && modules.add(`import "${dec.module}";`);
dec.namespace && namespaces.add(`using ${dec.namespace};`);
}
};
for (const model of program.models.objects) {
addImports(model.clientDecorators);
for (const property of model.properties) {
for (const decorator of property.clientDecorators ?? []) {
decorator.module && modules.add(`import "${decorator.module}";`);
decorator.namespace && namespaces.add(`using ${decorator.namespace};`);
}
addImports(property.clientDecorators);
}
}
for (const model of program.models.enums) {
addImports(model.clientDecorators);
for (const choice of model.members) {
addImports(choice.clientDecorators);
}
}
for (const resource of program.models.armResources) {
addImports(resource.clientDecorators);
for (const property of resource.properties) {
addImports(property.clientDecorators);
}
for (const op of resource.resourceOperations) {
addImports(op.clientDecorators);
}
for (const op of resource.normalOperations) {
addImports(op.clientDecorators);
}
}

Просмотреть файл

@ -21,6 +21,12 @@ export interface _ArmPagingMetadata {
NextLinkName: string;
}
export interface Metadata {
Resources: Record<string, ArmResource>;
RenameMapping: Record<string, string>;
OverrideOperationName: Record<string, string>;
}
export interface ArmResource {
Name: string;
GetOperations: _ArmResourceOperation[];
@ -46,7 +52,7 @@ export interface ArmResource {
IsSingletonResource: boolean;
}
let armResourceCache: Record<string, ArmResource> | undefined;
let metadataCache: Metadata | undefined;
export interface OperationWithResourceOperationFlag extends Operation {
isResourceOperation?: boolean;
@ -118,19 +124,19 @@ export function getResourceExistOperation(resource: ArmResource): Operation | un
}
}
export function getArmResourcesMetadata(): Record<string, ArmResource> {
if (armResourceCache) {
return armResourceCache;
export function getArmResourcesMetadata(): Metadata {
if (metadataCache) {
return metadataCache;
}
const session = getSession();
const outputFolder: string = session.configuration["output-folder"] ?? "";
try {
const content = readFileSync(join(outputFolder, "resources.json"), "utf-8");
const { Resources }: { Resources: Record<string, ArmResource> } = JSON.parse(content);
armResourceCache = Resources;
const metadata: Metadata = JSON.parse(content);
metadataCache = metadata;
return armResourceCache;
return metadataCache;
} catch (e) {
throw new Error(`Failed to load resources.json from ${outputFolder} \n ${e}`);
}
@ -141,7 +147,8 @@ export interface ArmResourceSchema extends ObjectSchema {
}
export function tagSchemaAsResource(schema: ObjectSchema): void {
const resourcesMetadata = getArmResourcesMetadata();
const metadata = getArmResourcesMetadata();
const resourcesMetadata = metadata.Resources;
for (const resourceName in resourcesMetadata) {
if (resourcesMetadata[resourceName].SwaggerModelName.toLowerCase() === schema.language.default.name.toLowerCase()) {