From c85ea6a31e4dd7e45b4de0762fcc018b0062f6f6 Mon Sep 17 00:00:00 2001 From: Qiaoqiao Zhang <55688292+qiaozha@users.noreply.github.com> Date: Mon, 19 Apr 2021 14:21:44 +0800 Subject: [PATCH] CLIModel refactor step 1 - split interfaces (#824) * command-interfaces-user-cases-document * document update * group change * bugfixes and doc improvement * update group description * remove new sdk release impact on scenario test * autorest directive and cli directive document * refactor of code model impl * fix codemoel layer * refactor fixes * refactor * reserve work * refactor the codemodel * example refactor * resolve conflict part * resolve conflicts * Manual config feature gap after refactor (#827) * manual-config-feature-gap-after-refactor * fix-test * add test config * manual config features and tests * scenario test * add array type example * feature type * remove unused reference --- src/generate/CodeModelAz.ts | 296 -- src/generate/CodeModelAzImpl.ts | 4182 ----------------- src/generate/azgenerator.ts | 16 +- src/generate/codemodel/AzExample.ts | 59 + src/generate/codemodel/CodeModelAz.ts | 74 + src/generate/codemodel/CodeModelAzImpl.ts | 1758 +++++++ src/generate/codemodel/Command.ts | 180 + src/generate/codemodel/CommandGroup.ts | 172 + src/generate/codemodel/Config.ts | 119 + src/generate/codemodel/Example.ts | 1458 ++++++ src/generate/codemodel/Extension.ts | 69 + src/generate/codemodel/Method.ts | 187 + src/generate/codemodel/MethodParameter.ts | 336 ++ src/generate/codemodel/Parameter.ts | 401 ++ src/generate/codemodel/Schema.ts | 185 + src/generate/generators/Base.ts | 16 +- src/generate/generators/CoreFull.ts | 44 +- src/generate/generators/CoreIncre.ts | 25 +- src/generate/generators/ExtensionFull.ts | 18 +- src/generate/generators/ExtensionIncre.ts | 25 +- src/generate/generators/Factory.ts | 9 +- src/generate/renders/CliMeta.ts | 7 +- src/generate/renders/CliNamespaceInit.ts | 2 +- src/generate/renders/CliReport.ts | 133 +- src/generate/renders/CliTopAction.ts | 8 +- src/generate/renders/CliTopCustom.ts | 5 +- src/generate/renders/CliTopHelp.ts | 6 +- src/generate/renders/CliTopInit.ts | 50 +- src/generate/renders/TemplateBase.ts | 2 +- .../renders/extraExt/CliExtHistory.ts | 2 +- .../renders/extraExt/CliExtMetadata.ts | 8 +- src/generate/renders/extraExt/CliExtReadme.ts | 16 +- .../renders/extraExt/CliExtSetupCfg.ts | 2 +- .../renders/extraExt/CliExtSetupPy.ts | 25 +- .../extraMain/CliMainDocSourceJsonMap.ts | 16 +- .../renders/extraMain/CliMainRequirement.ts | 9 +- .../renders/extraMain/CliMainSetupPy.ts | 8 +- src/generate/renders/generated/CliActions.ts | 5 +- .../renders/generated/CliClientFactory.ts | 31 +- src/generate/renders/generated/CliCommands.ts | 65 +- src/generate/renders/generated/CliCustom.ts | 401 +- src/generate/renders/generated/CliHelp.ts | 244 +- src/generate/renders/generated/CliParams.ts | 199 +- .../renders/generated/CliValidators.ts | 2 +- src/generate/renders/tests/CliTestCmdlet.ts | 17 +- src/generate/renders/tests/CliTestInit.ts | 5 +- src/generate/renders/tests/CliTestPrepare.ts | 10 +- src/generate/renders/tests/CliTestScenario.ts | 25 +- src/generate/renders/tests/CliTestStep.ts | 36 +- src/generate/renders/tests/ScenarioTool.ts | 2 +- src/modifiers.ts | 73 + .../kusto/configuration/readme.az.md | 24 + .../kusto/generated/commands.py | 26 +- .../kusto/generated/commands.py | 26 +- .../src/kusto/azext_kusto/generated/custom.py | 4 +- .../ext_default_folder/src/kusto/report.md | 4 +- .../src/kusto/azext_kusto/generated/custom.py | 4 +- .../src/kusto/report.md | 4 +- test/unittest/render-getActionRenderData.ts | 5 +- test/unittest/render-getCommandsRenderData.ts | 5 +- test/unittest/render-getRenderData.ts | 5 +- 61 files changed, 6101 insertions(+), 5049 deletions(-) delete mode 100644 src/generate/CodeModelAz.ts delete mode 100644 src/generate/CodeModelAzImpl.ts create mode 100644 src/generate/codemodel/AzExample.ts create mode 100644 src/generate/codemodel/CodeModelAz.ts create mode 100644 src/generate/codemodel/CodeModelAzImpl.ts create mode 100644 src/generate/codemodel/Command.ts create mode 100644 src/generate/codemodel/CommandGroup.ts create mode 100644 src/generate/codemodel/Config.ts create mode 100644 src/generate/codemodel/Example.ts create mode 100644 src/generate/codemodel/Extension.ts create mode 100644 src/generate/codemodel/Method.ts create mode 100644 src/generate/codemodel/MethodParameter.ts create mode 100644 src/generate/codemodel/Parameter.ts create mode 100644 src/generate/codemodel/Schema.ts diff --git a/src/generate/CodeModelAz.ts b/src/generate/CodeModelAz.ts deleted file mode 100644 index a84182d66..000000000 --- a/src/generate/CodeModelAz.ts +++ /dev/null @@ -1,296 +0,0 @@ -/* --------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *-------------------------------------------------------------------------------------------- */ - -import { Operation, OperationGroup, Parameter, Property, Schema } from '@azure-tools/codemodel'; -import { CodeModelTypes, DataGraph, GenerationMode, RenderInput } from '../utils/models'; -import { ResourcePool } from './renders/tests/ScenarioTool'; -import { TestStepExampleFileRestCall } from 'oav/dist/lib/testScenario/testResourceTypes'; - -export class MethodParam { - public value: any; - public isList: boolean; - public isSimpleListOrArray: boolean; - public submethodparameters: Property[]; - public inBody: boolean; - public constructor(value, isList, isSimpleListOrArray, submethodparameters, inBody) { - this.value = value; - this.isList = isList; - this.isSimpleListOrArray = isSimpleListOrArray; - this.submethodparameters = submethodparameters; - this.inBody = inBody; - } -} - -export enum KeyValueType { - No, - Classic, - PositionalKey, - ShorthandSyntax, - SimpleArray, -} - -export class ExampleParam { - name: string; - value: any; - isJson: boolean; - keyValue: KeyValueType; - keys: string[]; - defaultName: string; - methodParam: MethodParam; - ancestors: string[]; - replacedValue: any; - rawValue: any; - public constructor( - name: string, - value: any, - isJson: boolean, - keyValue: KeyValueType, - keys: string[], - defaultName: string, - methodParam: MethodParam, - ancestors: string[], - rawValue: any, - ) { - this.name = name; - this.value = value; - this.isJson = isJson; - this.keyValue = keyValue; - this.keys = keys; - this.defaultName = defaultName; - this.methodParam = methodParam; - this.ancestors = ancestors; - this.rawValue = rawValue; - } -} -export class CommandExample { - // this should be "create", "update", "list", "show", or custom name - public Method: string; - public Command: string; - public Id: string; - public Title: string; - public Parameters: ExampleParam[]; - // public MethodName: string; - public Path: string; - public ResourceClassName: string; - public HttpMethod: string; // Get, Post, Put ... - public MethodResponses: any[]; - public Method_IsLongRun: boolean; - public MethodParams: MethodParam[]; - public ExampleObj: any; - public commandStringItems: string[]; - public CommandString: string; -} - -export interface CodeModelAz { - init(): any; - SelectFirstExtension(): boolean; - SelectNextExtension(): boolean; - CliGenerationMode: GenerationMode; - AzextFolder: string; - - IsCliCore: boolean; - minCliCoreVersion: string; - SDK_NeedSDK: boolean; - SDK_IsTrack1: boolean; - SDK_NoFlatten: boolean; - AzureCliFolder: string; - AzureCliExtFolder: string; - azOutputFolder: string; - Extension_Name: string; - Extension_Parent: string; - Extension_Description: string; - Extension_NameUnderscored: string; - ConfiguredScenario: boolean; - Extension_NameClass: string; - Extension_TestScenario: any; - Extension_DefaultTestScenario: any; - Extension_ClientSubscriptionBound: boolean; - Extension_ClientBaseUrlBound: boolean; - Extension_ClientAuthenticationPolicy: string; - Extension_Mode: string; - ResourceType: string | undefined; - isComplexSchema(type: string, param: any): boolean; - - SelectFirstCommandGroup(needRefer?: boolean): boolean; - SelectNextCommandGroup(needRefer?: boolean): boolean; - - CommandGroup: OperationGroup; - CommandGroup_Name: string; - CommandGroup_Help: string; - CommandGroup_DefaultName: string; - CommandGroup_HasShowCommand: boolean; - CommandGroup_HasCommand: boolean; - CommandGroup_CliKey: string; - CommandGroup_MaxApi: string; - CommandGroup_MinApi: string; - CommandGroup_ResourceType: string | undefined; - CommandGroup_Mode: string; - CommandGroup_ClientFactoryName(group?: OperationGroup): string; - CommandGroup_OperationTmplName: string; - CommandGroup_CustomCommandTypeName(group?: OperationGroup): string; - CommandGroup_Referenced: boolean; - - SelectFirstCommand(): boolean; - SelectNextCommand(): boolean; - - Command: Operation; - Command_Name: string; - Command_MethodName: string; - Command_FunctionName: string; - Command_GetOriginalOperation: any; - Command_OriginalCommandGroup: OperationGroup; - Command_ClientFactoryName: string; - Command_NeedGeneric: boolean; - Command_MaxApi: string; - Command_MinApi: string; - Command_ResourceType: string | undefined; - Command_GenericSetterParameter(Operation): Parameter; - - Command_Help: string; - Command_IsLongRun: boolean; - Command_SubGroupName: string; - Command_Mode: string; - Command_Type: string; - Command_GenericSetterArgName: string; - - SelectFirstMethod(): boolean; - SelectNextMethod(): boolean; - - Method: Operation; - Method_IsFirst: boolean; - Method_IsLast: boolean; - Method_Name: string; - Method_NameAz: string; - Method_NameCli: string; - Method_Help: string; - Method_CliKey: string; - Method_MaxApi: string; - Method_MinApi: string; - Method_ResourceType: string | undefined; - Method_BodyParameterName: string; - Method_IsLongRun: boolean; - Method_GetOriginalOperation: any; - Method_GenericSetterParameter(Operation): Parameter; - Method_NeedGeneric: boolean; - Method_Mode: string; - Method_AzExamples: CommandExample[]; - // Method_SetAzExamples(examples: CommandExample[]): void; - Operation_IsHidden(op?: Operation): boolean; - - SelectFirstMethodParameter(containHidden?: boolean): boolean; - SelectNextMethodParameter(containHidden?: boolean): boolean; - EnterSubMethodParameters(param?: Parameter): boolean; - ExitSubMethodParameters(): boolean; - - MethodParameter_Name: string; - MethodParameter_NameAz: string; - MethodParameter_CliKey: string; - MethodParameter_MaxApi: string; - MethodParameter_MinApi: string; - MethodParameter_ResourceType: string | undefined; - MethodParameter_IsArray: boolean; - MethodParameter_NamePython: string; - MethodParameter_MapsTo: string; - MethodParameter_Description: string; - MethodParameter_Type: string; - MethodParameter_IsList: boolean; - MethodParameter_IsSimpleArray: boolean; - MethodParameter_IsListOfSimple: boolean; - MethodParameter_IsPolyOfSimple: boolean; - MethodParameter_IsDiscriminator: boolean; - MethodParameter_IdPart: string; - MethodParameter_ArgGroup: string; - MethodParameter: Parameter; - MethodParameters: Array; - SubMethodParameter: Parameter; - - MethodParameter_In: string; - MethodParameter_IsHidden: boolean; - MethodParameter_IsRequired: boolean; - MethodParameter_IsFlattened: boolean; - MethodParameter_IsCliFlattened: boolean; - MethodParameter_RequiredByMethod: boolean; - MethodParameter_EnumValues: string[]; - MethodParameters_AddPolySubClass(oriParam, para): boolean; - MethodParameter_DefaultValue: any | undefined; - MethodParameter_DefaultConfigKey: string | undefined; - MethodParameter_Mode: string; - MethodParameter_IsPositional: boolean; - MethodParameter_IsShorthandSyntax: boolean; - MethodParameter_PositionalKeys: string[]; - Parameter_Type(Parameter): string; - Schema_Type(Schema): string; - Parameter_IsList(Parameter): boolean; - Parameter_IsListOfSimple(Parameter): boolean; - Parameter_IsPolyOfSimple(Parameter): boolean; - MethodParameter_ActionName: string; - Parameter_SetAzNameMapsTo(string, Parameter): void; - Parameter_InGlobal(Parameter): boolean; - Parameter_IsHidden(Parameter): boolean; - Parameter_IsFlattened(Parameter): boolean; - Parameter_IsCliFlattened(Parameter): boolean; - Parameter_MapsTo(Parameter): string; - Parameter_SubMapsTo(subMethodName, Parameter): string; - Schema_MapsTo(Schema); - Parameter_Name(): string; - Parameter_NameAz(Parameter): string; - Parameter_CliKey(Parameter): string; - Parameter_NamePython(Parameter): string; - Parameter_Description(Parameter): string; - Parameter_DefaultValue(Parameter): any | undefined; - Parameter_DefaultConfigKey(Parameter): string | undefined; - Parameter_IsPositional(Parameter): boolean; - Parameter_IsShorthandSyntax(Parameter): boolean; - Schema_Description(Schema): string; - Schema_FlattenedFrom(Schema): Schema; - Schema_IsPositional(Schema): boolean; - - GetModuleOperationName(group?: OperationGroup): string; - GetModuleOperationNamePython(): string; - GetModuleOperationNamePythonUpper(): string; - GetPythonNamespace(): string; - GetPythonPackageName(): string; - GetResourcePool(): ResourcePool; - - // Python - PythonMgmtClient: string; - - GenerateTestInit(): void; - SelectFirstExample(): boolean; - SelectNextExample(): boolean; - FindExampleById( - id: string, - commandParams: any, - examples: any[], - minimum: boolean, - step?: TestStepExampleFileRestCall, - ): string[][]; - GetExampleWait(example: CommandExample): string[]; - SelectFirstAzExample(): boolean; - SelectNextAzExample(): boolean; - AzExample: CommandExample; - AzExample_CommandString: string; - AzExample_CommandStringItems: string[]; - GetExamples(includeGenerated: boolean): CommandExample[]; - GetSubscriptionKey(): string; - GetPreparerEntities(): any[]; - GatherInternalResource(); - FindExampleWaitById(id: string, step?: TestStepExampleFileRestCall): string[][]; - GetExampleItems(example: CommandExample, isTest: boolean, commandParams: any): string[]; - GetExampleChecks(example: CommandExample): string[]; - RandomizeNames: boolean; - - // readme config - CliCoreLib: string; - GenMinTest: boolean; - GetMetaData(): { [key: string]: any }; - getModelData( - layer: CodeModelTypes, - inputProperties: Map, - dependencies: DataGraph, - ); - GetActionData(): any[]; - GetTestUniqueResource: boolean; -} diff --git a/src/generate/CodeModelAzImpl.ts b/src/generate/CodeModelAzImpl.ts deleted file mode 100644 index f1a9265ce..000000000 --- a/src/generate/CodeModelAzImpl.ts +++ /dev/null @@ -1,4182 +0,0 @@ -/* --------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *-------------------------------------------------------------------------------------------- */ -import * as path from 'path'; -import { Channel, Session } from '@autorest/extension-base'; -import { EnglishPluralizationService } from '@azure-tools/codegen'; -import { - CodeModel, - Operation, - OperationGroup, - Parameter, - ParameterLocation, - Property, - Request, - Schema, - SchemaType, -} from '@azure-tools/codemodel'; -import { values } from '@azure-tools/linq'; -import { - Capitalize, - deepCopy, - getGitStatus, - MergeSort, - parseResourceId, - ToCamelCase, - ToJsonString, - ToSnakeCase, - changeCamelToDash, - isEqualStringArray, - ToSentence, - isNullOrUndefined, - ToMultiLine, - isGeneratedExampleId, -} from '../utils/helper'; -import { - CodeGenConstants, - EXCLUDED_PARAMS, - GenerationMode, - AzConfiguration, - CodeModelTypes, - RenderInput, - DataGraph, - SortOrder, - CliCommandType, - ExtensionMode, -} from '../utils/models'; -import { - CodeModelAz, - CommandExample, - ExampleParam, - MethodParam, - KeyValueType, -} from './CodeModelAz'; -import { - azOptions, - GenerateDefaultTestScenario, - GenerateDefaultTestScenarioByDependency, - PrintTestScenario, - ResourcePool, - ObjectStatus, - GroupTestScenario, - LoadPreparesConfig, -} from './renders/tests/ScenarioTool'; -import { readFile } from '@azure-tools/async-io'; -import { TestStepExampleFileRestCall } from 'oav/dist/lib/testScenario/testResourceTypes'; -import * as process from 'process'; -class ActionParam { - public constructor( - public groupOpActionName: string, - public groupActionName: string, - public actionName: string, - public action: Parameter, - ) {} -} - -export class CodeModelCliImpl implements CodeModelAz { - codeModel: CodeModel; - options: any; - extensionName: string; - parentExtension: string; - currentOperationGroupIndex: number; - currentSubOperationGroupIndex: number; - currentOperationIndex: number; - currentParameterIndex: number; - currentExampleIndex: number; - currentAzExampleIndex: number; - preMethodIndex: number; - currentMethodIndex: number; - resourcePool: ResourcePool; - - suboptions: Property[]; - subOperationGroups: Operation[]; - submethodparameters: Parameter[]; - substack: Array<[Parameter[], number]>; - currentSubOptionIndex: number; - paramActionNameReference: Map; - allActions: Map; - private _testScenario: any; - private _defaultTestScenario: any[]; - private _configuredScenario: boolean; - private _clientSubscriptionBound: boolean; - private _clientBaseUrlBound: boolean; - private _clientAuthenticationPolicy: string; - private _generationMode: GenerationMode = GenerationMode.Full; - private _outputPath: string; - private _parentOptions: any; - private _useOptions: string[]; - - init(): void { - this.options = AzConfiguration.getValue(CodeGenConstants.az); - this._parentOptions = AzConfiguration.getValue(CodeGenConstants.parents); - this._useOptions = AzConfiguration.getValue(CodeGenConstants.use); - Object.assign(azOptions, this.options); - this.extensionName = this.options.extensions; - this.parentExtension = this.options[CodeGenConstants.parentExtension]; - this.currentOperationGroupIndex = -1; - this.currentSubOperationGroupIndex = -1; - this.currentOperationIndex = -1; - this.currentParameterIndex = -1; - this.currentExampleIndex = -1; - this.currentAzExampleIndex = -1; - this.preMethodIndex = -1; - this.currentMethodIndex = -1; - this.suboptions = null; - this.currentSubOptionIndex = -1; - this.submethodparameters = null; - this.substack = new Array<[Parameter[], number]>(); - this._clientBaseUrlBound = this.options[CodeGenConstants.clientBaseUrlBound]; - this._clientSubscriptionBound = this.options[CodeGenConstants.clientSubscriptionBound]; - this._clientAuthenticationPolicy = this.options[ - CodeGenConstants.clientAuthenticationPolicy - ]; - LoadPreparesConfig(this.options[CodeGenConstants.preparers]); - // this.sortOperationByAzCommand(); - } - - public constructor(protected session: Session) { - this.init(); - this.codeModel = session.model; - this.resourcePool = new ResourcePool(); - this.dealingSimplePolymorphism(); - this.setParamAzUniqueNames(); - this.sortOperationByAzCommand(); - this.calcOptionRequiredByMethod(); - this.dealingParameterAlias(); - } - - private sortOperationByAzCommand() { - for (const [idx, operationGroup] of this.codeModel.operationGroups.entries()) { - operationGroup.operations.sort(function (a, b) { - function getOrder(op: string) { - if (op.indexOf(' ') > -1) { - op = op.split(' ').last; - } - const opOrder = ['list', 'show', 'create', 'update', 'delete']; - let order = opOrder.indexOf(op.toLowerCase()) + 1; - if (order === 0) { - order = opOrder.length + 1; - } - return order; - } - function requiredParamLength(parameters) { - let ret = 0; - for (let i = 0; i < parameters.length; ++i) { - if (parameters[i].required) ret++; - } - return ret; - } - const oa = getOrder(a.language['az'].name); - const ob = getOrder(b.language['az'].name); - if (oa < ob) { - return -1; - } else if (oa > ob) { - return 1; - } else { - const la = a.language['az'].name; - const lb = b.language['az'].name; - if (la !== lb) { - return la.localeCompare(lb); - } - const requiredLenA = requiredParamLength(a.parameters); - const requiredLenB = requiredParamLength(b.parameters); - if (requiredLenA !== requiredLenB) return requiredLenA > requiredLenB ? -1 : 1; - return a.parameters.length > b.parameters.length ? -1 : 1; - } - }); - this.codeModel.operationGroups[idx] = operationGroup; - } - } - - public get RandomizeNames(): boolean { - const randomizeNames = this.options?.['randomize-names']; - if (randomizeNames) return true; - return false; - } - - public get FormalizeNames(): boolean { - const formalizeNames = this.options?.['formalize-names']; - if (formalizeNames) return true; - return false; - } - - public get ResourceType(): string | undefined { - return this.formResourceType(this.options?.['resource-type']); - } - - public get GenChecks(): boolean { - const disableChecks = this.options?.['disable-checks']; - if (disableChecks) return false; - return true; - } - - public get GetTestUniqueResource(): boolean { - const ret = this.options?.[CodeGenConstants.testUniqueResource]; - if (ret) return true; - return false; - } - - public get GenMinTest(): boolean { - const genMinTest = this.options?.['gen-min-test']; - if (genMinTest) return true; - return false; - } - - public GetResourcePool(): ResourcePool { - return this.resourcePool; - } - - public async GetMetaData(): Promise<{ [key: string]: any }> { - function getSwaggerFolder(parentsOptions: { [key: string]: any }) { - for (const k in parentsOptions) { - const v: string = parentsOptions[k]; - if ( - k.endsWith('.json') && - typeof v === 'string' && - v.startsWith('file:///') && - v.indexOf('specification') > 0 - ) { - const p = v.indexOf('specification'); - if (process.platform.toLowerCase().startsWith('win')) { - return v.slice('file:///'.length, p - 1); - } - return v.slice('file:///'.length - 1, p - 1); - } - } - return undefined; - } - const ret = {}; - ret['--use'] = this._useOptions; - - const swaggerFolder = getSwaggerFolder(this._parentOptions); - if (swaggerFolder) { - ret['swagger git status'] = getGitStatus(swaggerFolder).split('\n'); - } - - const azpkg = path.join(__dirname, '..', '..', '..', 'package.json'); - const pjson = JSON.parse(await readFile(azpkg)); - ret['package info'] = `${pjson.name} ${pjson.version}`; - return ret; - } - - private calcOptionRequiredByMethod() { - if (this.SelectFirstCommandGroup()) { - do { - if (this.SelectFirstCommand()) { - do { - let paramTime = 0; - const paramRequired: Map = new Map(); - if (this.SelectFirstMethod()) { - paramTime++; - if (this.SelectFirstMethodParameter()) { - do { - if (!paramRequired.has(this.MethodParameter_Name)) { - paramRequired.set( - this.MethodParameter_Name, - this.MethodParameter_IsRequired ? 1 : 0, - ); - } else if (this.MethodParameter_IsRequired) { - paramRequired.set( - this.MethodParameter_Name, - paramRequired.get(this.MethodParameter_Name) + 1, - ); - } - } while (this.SelectNextMethodParameter()); - } - while (this.SelectNextMethod()) { - paramTime++; - if (this.SelectFirstMethodParameter()) { - do { - if (!paramRequired.has(this.MethodParameter_Name)) { - paramRequired.set( - this.MethodParameter_Name, - this.MethodParameter_IsRequired ? 1 : 0, - ); - } else if (this.MethodParameter_IsRequired) { - paramRequired.set( - this.MethodParameter_Name, - paramRequired.get(this.MethodParameter_Name) + 1, - ); - } - } while (this.SelectNextMethodParameter()); - } - } - } - if (this.SelectFirstMethod()) { - let idGroups = new Map(); - idGroups = parseResourceId(this.Request.protocol.http.path); - let hasName = false; - if (this.SelectFirstMethodParameter()) { - do { - const parameters = this.MethodParameter; - const defaultName = parameters.language['cli'].cliKey; - const defaultToMatch = '{' + defaultName + '}'; - if (!isNullOrUndefined(idGroups)) { - for (const k of idGroups.entries()) { - if ( - k[1] === defaultToMatch && - defaultName !== 'resourceGroupName' - ) { - this.MethodParameter.language['az'].id_part = k[0]; - } - } - } - if (parameters.language['cli'].required) { - this.MethodParameter['RequiredByMethod'] = true; - } else { - this.MethodParameter['RequiredByMethod'] = - paramRequired.get(this.MethodParameter_Name) === - paramTime; - } - if (this.MethodParameter_MapsTo === 'name') { - hasName = true; - } - } while (this.SelectNextMethodParameter()); - if (hasName) { - this.Method['hasName'] = true; - } - } - while (this.SelectNextMethod()) { - let idGroups = new Map(); - idGroups = parseResourceId(this.Request.protocol.http.path); - let hasName = false; - if (this.SelectFirstMethodParameter()) { - do { - const parameters = this.MethodParameter; - const defaultName = parameters.language['cli'].cliKey; - const defaultToMatch = '{' + defaultName + '}'; - if (!isNullOrUndefined(idGroups)) { - for (const k of idGroups.entries()) { - if ( - k[1] === defaultToMatch && - defaultName !== 'resourceGroupName' - ) { - this.MethodParameter.language['az'].id_part = - k[0]; - } - } - } - if (parameters.language['cli'].required) { - this.MethodParameter['RequiredByMethod'] = true; - } else { - this.MethodParameter['RequiredByMethod'] = - paramRequired.get(this.MethodParameter_Name) === - paramTime; - } - if (this.MethodParameter_MapsTo === 'name') { - hasName = true; - } - } while (this.SelectNextMethodParameter()); - if (hasName) { - this.Method['hasName'] = true; - } - } - } - } - } while (this.SelectNextCommand()); - } - } while (this.SelectNextCommandGroup()); - } - } - - private dealingSimplePolymorphism() { - if (this.SelectFirstCommandGroup()) { - do { - if (this.SelectFirstCommand()) { - do { - if (this.SelectFirstMethod()) { - do { - if (this.SelectFirstMethodParameter()) { - do { - if (this.MethodParameter_IsFlattened) { - continue; - } - if (this.Parameter_IsPolyOfSimple(this.MethodParameter)) { - const polyBaseParam = this.MethodParameter; - const allChildParam: Array = []; - for (const child of this.MethodParameter.schema[ - 'children' - ].all) { - const childParam = new Parameter( - child.language.default.name, - child.language.default.description, - child, - child.language, - ); - childParam.language = child.language; - if ( - !isNullOrUndefined(child.language['cli']?.alias) - ) { - if ( - isNullOrUndefined( - childParam.language['az'].alias, - ) - ) { - childParam.language['az'].alias = []; - } - if ( - typeof child.language['cli'].alias === - 'string' - ) { - if ( - EXCLUDED_PARAMS.indexOf( - child.language['cli'].alias, - ) > -1 - ) { - child.language['cli'].alias = - 'gen_' + - child.language['cli'].alias; - } - childParam.language['az'].alias.push( - changeCamelToDash( - child.language['cli'].alias, - ), - ); - } else if ( - Array.isArray(child.language['cli'].alias) - ) { - for (let alias of child.language['cli'] - .alias) { - if ( - EXCLUDED_PARAMS.indexOf(alias) > -1 - ) { - alias = 'gen_' + alias; - } - childParam.language['az'].alias.push( - changeCamelToDash(alias), - ); - } - } - } - childParam['polyBaseParam'] = polyBaseParam; - allChildParam.push(childParam); - } - const addResult = this.MethodParameters_AddPolySubClass( - this.MethodParameter, - allChildParam, - ); - if (!addResult) { - this.session.message({ - Channel: Channel.Warning, - Text: - 'dealingSimplePolymorphisme error! baseClass: ' + - this.MethodParameter_MapsTo, - }); - } - } - } while (this.SelectNextMethodParameter()); - } - } while (this.SelectNextMethod()); - } - } while (this.SelectNextCommand()); - } - } while (this.SelectNextCommandGroup()); - } - } - - private setParamAzUniqueNames() { - this.paramActionNameReference = new Map(); - this.allActions = new Map(); - const nameActionReference: Map = new Map(); - const pythonReserveWord = ['all', 'id', 'format', 'type', 'filter']; - if (this.SelectFirstCommandGroup()) { - do { - if (this.SelectFirstCommand()) { - do { - const nameParamReference: Map = new Map< - string, - Parameter - >(); - if (this.SelectFirstMethod()) { - do { - if (this.SelectFirstMethodParameter()) { - do { - const paramName = this.MethodParameter_MapsTo; - const param = this.MethodParameter; - const originParam = this.MethodParameter; - let flattenedNames = - param?.['targetProperty']?.flattenedNames; - if ( - isNullOrUndefined(flattenedNames) && - !isNullOrUndefined(param.language['cli'].flattenedNames) - ) { - flattenedNames = param.language['cli'].flattenedNames; - } - const mapName: Array = []; - let paramFlattenedName = this.Parameter_MapsTo(param); - const names = this.Method_NameAz.split(' '); - if (flattenedNames && flattenedNames.length > 0) { - for (const item of flattenedNames) { - mapName.push(item); - } - mapName.pop(); - mapName.reverse(); - if ( - mapName[mapName.length - 1] === 'properties' || - mapName[mapName.length - 1] === 'parameters' - ) { - mapName.pop(); - } else if ( - names.length > 1 && - mapName[mapName.length - 1] === - names[0].replace(/-/g, '_') - ) { - mapName.pop(); - } - if (mapName.length > 0) { - const argGroupName = mapName - .reverse() - .map((item) => { - return ToSentence(item); - }) - .join(' '); - this.MethodParameter.language[ - 'az' - ].arg_group = argGroupName; - } - paramFlattenedName = paramName; - } - if (names.length > 1) { - let subgroup: string = names[0]; - subgroup = subgroup.replace(/-/g, '_'); - if (paramFlattenedName.startsWith(subgroup)) { - paramFlattenedName = paramFlattenedName.substr( - subgroup.length + 1, - ); - } - } - if ( - nameParamReference.has(paramFlattenedName) && - nameParamReference.get(paramFlattenedName)[ - 'targetProperty' - ] !== param['targetPropert'] - ) { - let tmpName = paramFlattenedName; - const preParam = nameParamReference.get( - paramFlattenedName, - ); - const preFlattenedNames = - preParam?.['targetProperty']?.flattenedNames; - let preParamFlattenedName = this.Parameter_MapsTo( - preParam, - ); - let preTmpName = preParamFlattenedName; - if (preFlattenedNames && preFlattenedNames.length > 0) { - preTmpName = preFlattenedNames - .map((pfn) => ToSnakeCase(pfn)) - .join('_'); - } - if (flattenedNames && flattenedNames.length > 0) { - tmpName = flattenedNames - .map((fn) => ToSnakeCase(fn)) - .join('_'); - } - if (preTmpName !== preParamFlattenedName) { - preParamFlattenedName = preTmpName; - } else if (tmpName !== paramFlattenedName) { - paramFlattenedName = tmpName; - } - if ( - pythonReserveWord.indexOf(paramFlattenedName) > -1 - ) { - paramFlattenedName += '_'; - } - if ( - pythonReserveWord.indexOf(preParamFlattenedName) > - -1 - ) { - preParamFlattenedName += '_'; - } - if (paramFlattenedName !== preParamFlattenedName) { - this.Parameter_SetAzNameMapsTo( - preParamFlattenedName, - preParam, - ); - nameParamReference.set( - preParamFlattenedName, - preParam, - ); - this.Parameter_SetAzNameMapsTo( - paramFlattenedName, - param, - ); - nameParamReference.set(paramName, param); - } else { - // if the full flattenedName within one command is the same but has two different reference. there's no way to split them. - this.session.message({ - Channel: Channel.Warning, - Text: - 'parameter ' + - paramFlattenedName + - ' has two different references but they have the same flattened name', - }); - } - } else { - // nameParamReference doesn't have the parameter - // or nameParamReference has the parameter and they are the same. - if ( - pythonReserveWord.indexOf(paramFlattenedName) > -1 - ) { - paramFlattenedName += '_'; - } - this.Parameter_SetAzNameMapsTo( - paramFlattenedName, - param, - ); - nameParamReference.set(paramFlattenedName, param); - } - if (this.MethodParameter_Name === 'tags') { - continue; - } - if (this.Parameter_IsPolyOfSimple()) { - continue; - } - if ( - this.MethodParameter_IsList && - this.MethodParameter_IsListOfSimple && - !this.MethodParameter_IsSimpleArray - ) { - const groupOpParamName: string = - 'Add' + - Capitalize( - ToCamelCase( - this.Command_FunctionName + - '_' + - this.MethodParameter_MapsTo, - ), - ); - const groupParamName: string = - 'Add' + - Capitalize( - ToCamelCase( - this.CommandGroup_Key + - '_' + - this.MethodParameter_MapsTo, - ), - ); - const actionName: string = - 'Add' + - Capitalize( - ToCamelCase(this.MethodParameter_MapsTo), - ); - const action = new ActionParam( - groupOpParamName, - groupParamName, - actionName, - param, - ); - if ( - nameActionReference.has(actionName) && - nameActionReference.get(actionName).action - .schema !== originParam.schema - ) { - const preAction = nameActionReference.get( - actionName, - ); - nameActionReference.delete(actionName); - let preActionUniqueName = preAction.actionName; - let actionUniqueName = actionName; - if ( - preAction.groupActionName !== - action.groupActionName - ) { - actionUniqueName = action.groupActionName; - preActionUniqueName = preAction.groupActionName; - } else if ( - preAction.groupOpActionName !== - action.groupOpActionName - ) { - actionUniqueName = action.groupOpActionName; - preActionUniqueName = - preAction.groupOpActionName; - } - this.paramActionNameReference.set( - preAction.action.schema, - preActionUniqueName, - ); - this.allActions.set( - preAction.action, - preActionUniqueName, - ); - this.paramActionNameReference.set( - param.schema, - actionUniqueName, - ); - this.allActions.set(param, actionUniqueName); - nameActionReference.set( - preActionUniqueName, - preAction, - ); - nameActionReference.set(actionUniqueName, action); - } else if ( - !this.paramActionNameReference.has( - originParam.schema, - ) - ) { - nameActionReference.set(actionName, action); - this.paramActionNameReference.set( - param.schema, - actionName, - ); - this.allActions.set(param, actionName); - } - } - } while (this.SelectNextMethodParameter()); - } - } while (this.SelectNextMethod()); - } - } while (this.SelectNextCommand()); - } - } while (this.SelectNextCommandGroup()); - } - } - - private dealingParameterAlias() { - this.getMethodParametersWithCallback(() => { - const parameterName = this.MethodParameter_MapsTo; - // this is to handle names like "format", "type", etc - if (parameterName.endsWith('_')) { - if (isNullOrUndefined(this.MethodParameter.language['az'].alias)) { - this.MethodParameter.language['az'].alias = []; - } - this.MethodParameter.language['az'].alias.push( - parameterName.substr(0, parameterName.length - 1), - ); - } else if ( - parameterName.endsWith('name') && - !this.Method['hasName'] && - parameterName.replace(/_name$|_/g, '') === - this.CommandGroup_DefaultName.toLowerCase() - ) { - if ( - isNullOrUndefined(this.MethodParameter.language['az'].alias) || - this.MethodParameter.language['az'].alias.length <= 0 - ) { - this.MethodParameter.language['az'].alias = []; - this.MethodParameter.language['az'].alias.push('name'); - this.MethodParameter.language['az'].alias.push('n'); - this.MethodParameter.language['az'].alias.push(parameterName); - } - } - }); - } - - public GetActionData() { - const actions = []; - SchemaType.Array; - this.allActions.forEach((actionName: string, param: Parameter) => { - if (actionName === 'AddEventGridDataConnection') { - param; - } - const action = { - actionName: actionName, - actionType: 'KeyValue', - }; - action.actionType = this.Parameter_IsPositional(param) - ? 'Positional' - : action.actionType; - action.actionType = this.Parameter_IsShorthandSyntax(param) - ? 'ShortHandSyntax' - : action.actionType; - action['mapsTo'] = this.Parameter_MapsTo(param); - action['type'] = this.Schema_Type(param.schema); - action['nameAz'] = this.Parameter_NameAz(param); - if (action['type'] === SchemaType.Array) { - action['baseClass'] = '_AppendAction'; - } else { - action['baseClass'] = 'Action'; - } - action['subProperties'] = []; - action['subPropertiesMapsTo'] = []; - action['subPropertiesNamePython'] = []; - action['subPropertiesNameAz'] = []; - action['constants'] = {}; - const baseParam = param['polyBaseParam']; - const keyToMatch = baseParam?.schema?.discriminator?.property?.language.python?.name; - const valueToMatch = param.schema?.['discriminatorValue']; - const allSubParameters = []; - if (this.EnterSubMethodParameters(param) && this.SelectFirstMethodParameter(true)) { - do { - const tmpParam = this.SubMethodParameter; - allSubParameters.push(tmpParam); - const pythonName = this.Parameter_NamePython(tmpParam); - const mapsTo = this.Parameter_MapsTo(tmpParam); - const nameAz = this.Parameter_NameAz(tmpParam); - const subType = this.Parameter_Type(tmpParam); - if ( - this.Parameter_Type(tmpParam) === SchemaType.Constant && - !isNullOrUndefined(tmpParam.schema['value']?.['value']) - ) { - action['constants'][ - `'${pythonName}'` - ] = `'${tmpParam.schema['value']['value']}'`; - } else if (tmpParam['readOnly']) { - continue; - } else if ( - keyToMatch === pythonName && - !isNullOrUndefined(keyToMatch) && - !isNullOrUndefined(valueToMatch) && - tmpParam['isDiscriminator'] - ) { - action['constants'][`'${keyToMatch}'`] = `'${valueToMatch}'`; - } else { - action['subProperties'].push({ - namePython: pythonName, - nameAz: nameAz, - type: subType, - }); - action['subPropertiesMapsTo'].push(mapsTo); - action['subPropertiesNamePython'].push(pythonName); - action['subPropertiesNameAz'].push(nameAz); - } - } while (this.SelectNextMethodParameter(true)); - if (action['actionType'] === 'Positional') { - const keys = this.Parameter_PositionalKeys(param, allSubParameters); - action['subPropertiesNamePython'] = keys; - } - } - SchemaType.Dictionary; - actions.push(action); - this.ExitSubMethodParameters(); - }); - return actions; - } - //= ================================================================================================================ - // Extension level information - // autorest.az will have support for multiple extensions from single swagger file. - // Following formats in readme.az.md shall be supported: - // - // For single extension: - // - // az: - // extensions: - // - // Multiple extensions: - // - // az: - // extensions: - // - - // - - // - // Multiple extensions with additional parameters: - // - // az: - // extensions: - // - name: - // something-else: value - // - name: - // something-else: value - // - // Initially single extension without additional parameters should be supported, however all formats should - // be handled correctly. - // - //= ================================================================================================================ - - public GenerateTestInit(): void { - if (this.GetResourcePool().hasTestResourceScenario) { - this._testScenario = GroupTestScenario( - this.GetResourcePool().generateTestScenario(), - this.Extension_NameUnderscored, - ); - this._configuredScenario = true; - } else if (this.codeModel['test-scenario']) { - this._testScenario = GroupTestScenario( - this.codeModel['test-scenario'], - this.Extension_NameUnderscored, - ); - this._configuredScenario = true; - } else { - this._testScenario = undefined; - this._configuredScenario = false; - } - this.GatherInternalResource(); - this.GetAllExamples(); - } - - public get ConfiguredScenario(): boolean { - // judge test-scenario whether have value - return this._configuredScenario; - } - - public SelectFirstExtension(): boolean { - // support only one initially - return true; - } - - public SelectNextExtension(): boolean { - return false; - } - - public get Extension_Name(): string { - return this.extensionName; - } - - public get Extension_Parent(): string { - return this.parentExtension; - } - - public get Extension_Description(): string { - if (!isNullOrUndefined(AzConfiguration.getValue(CodeGenConstants.extensionDescription))) { - return 'Manage ' + AzConfiguration.getValue(CodeGenConstants.extensionDescription); - } - return ( - 'Manage ' + - ToSentence(this.Extension_NameClass.replace(/ManagementClient|Client/gi, '')) - ); - } - - public get Extension_Mode(): string { - let extensionMode = AzConfiguration.getValue(CodeGenConstants.extensionMode); - this.codeModel.operationGroups.forEach((operationGroup) => { - if ( - operationGroup.language['az'].command === this.Extension_Name && - !isNullOrUndefined(operationGroup.language?.['cli']?.extensionMode) - ) { - extensionMode = operationGroup.language?.['cli']?.extensionMode; - } - }); - return extensionMode; - } - - public get Extension_NameUnderscored(): string { - return this.extensionName.replace(/-/g, '_'); - } - - public get Extension_NameClass(): string { - return this.codeModel.info['pascal_case_title']; - } - - public get Extension_TestScenario(): any { - return this._testScenario; - } - - public get Extension_DefaultTestScenario(): any { - return this._defaultTestScenario; - } - - public get Extension_ClientSubscriptionBound(): boolean { - return this._clientSubscriptionBound; - } - - public get Extension_ClientBaseUrlBound(): boolean { - return this._clientBaseUrlBound; - } - - public get Extension_ClientAuthenticationPolicy(): string { - return this._clientAuthenticationPolicy; - } - - public get CliGenerationMode(): GenerationMode { - return AzConfiguration.getValue(CodeGenConstants.generationMode); - } - - //= ================================================================================================================ - // Command Groups - // - // This interface provides enumeration of command groups assigned to currently selected extension. - // Currently all the command groups should be assigned to default extension (first one on the list). - // Users will be able to assign command groups to specific extension via readme.az.md file. - // Specification will be updated accordingly. - //= ================================================================================================================ - - public SelectFirstCommandGroup(needRefer = false): boolean { - // just enumerate through command groups in code-model-v4 - if (this.codeModel.operationGroups.length > 0) { - this.currentOperationGroupIndex = 0; - if ( - this.CommandGroup.language['cli'].hidden || - this.CommandGroup.language['cli'].removed - ) { - if (needRefer && this.CommandGroup_Referenced) { - return true; - } else if (this.SelectNextCommandGroup()) { - if (!this.SelectFirstCommand()) { - return this.SelectNextCommandGroup(); - } - return true; - } else { - return false; - } - } - if (needRefer && this.CommandGroup_Referenced) { - return true; - } else if (!this.SelectFirstCommand()) { - return this.SelectNextCommandGroup(needRefer); - } - return true; - } else { - this.currentOperationGroupIndex = -1; - return false; - } - } - - public SelectNextCommandGroup(needRefer = false): boolean { - if (this.currentOperationGroupIndex < this.codeModel.operationGroups.length - 1) { - this.currentOperationGroupIndex++; - if ( - this.CommandGroup.language['cli'].hidden || - this.CommandGroup.language['cli'].removed - ) { - if (needRefer && this.CommandGroup_Referenced) { - return true; - } else if (this.SelectNextCommandGroup()) { - if (!this.SelectFirstCommand()) { - return this.SelectNextCommandGroup(); - } - return true; - } else { - return false; - } - } - if (needRefer && this.CommandGroup_Referenced) { - return true; - } else if (!this.SelectFirstCommand()) { - return this.SelectNextCommandGroup(needRefer); - } - return true; - } else { - this.currentOperationGroupIndex = -1; - return false; - } - } - - public get CommandGroup(): OperationGroup { - if ( - this.currentOperationGroupIndex < 0 || - this.currentOperationGroupIndex >= this.codeModel.operationGroups.length - ) { - return undefined; - } - return this.codeModel.operationGroups[this.currentOperationGroupIndex]; - } - - public get CommandGroup_Name(): string { - return this.CommandGroup.language['az'].command; - } - - public get CommandGroup_Help(): string { - const groupDescription = this.CommandGroup.language['az']?.['description']; - if (!isNullOrUndefined(groupDescription) && groupDescription !== '') { - return groupDescription; - } - const extensionPart = this.Extension_Name.replace(/-/g, ' '); - const groupPart = changeCamelToDash(this.CommandGroup.language['az']?.name)?.replace( - /-/g, - ' ', - ); - if (groupPart === '') { - return ''; - } - if (extensionPart !== groupPart) { - return 'Manage ' + groupPart + ' with ' + extensionPart; - } else { - return 'Manage ' + groupPart; - } - } - - public get CommandGroup_Key(): string { - return this.CommandGroup.$key || this.CommandGroup_Name; - } - - public get CommandGroup_HasShowCommand(): boolean { - return this.CommandGroup.language['az'].hasShowCommand; - } - - public get CommandGroup_HasCommand(): boolean { - return this.SelectFirstCommand(); - } - - public get CommandGroup_Referenced(): boolean { - return this.CommandGroup.language['az']['referenced']; - } - - public get CommandGroup_DefaultName(): string { - const eps = new EnglishPluralizationService(); - return eps.singularize(this.CommandGroup.language['cli'].cliKey); - } - - public get CommandGroup_MaxApi(): string { - return this.CommandGroup.language['cli']?.['max-api']; - } - - public get CommandGroup_MinApi(): string { - return this.CommandGroup.language['cli']?.['min-api']; - } - - public get CommandGroup_ResourceType(): string | undefined { - return this.formResourceType(this.CommandGroup.language['cli']?.['resource-type']); - } - - public get CommandGroup_CliKey(): string { - return this.CommandGroup.language['cli']?.cliKey; - } - - public get CommandGroup_Mode(): string { - if (isNullOrUndefined(this.CommandGroup?.language?.['cli']?.extensionMode)) { - if (this.IsCliCore && this.Extension_Mode === ExtensionMode.Stable) { - return ExtensionMode.Experimental; - } - return this.Extension_Mode; - } - return this.CommandGroup?.language?.['cli']?.extensionMode; - } - - public CommandGroup_ClientFactoryName(group: OperationGroup = this.CommandGroup): string { - const cfName: string = - 'cf_' + - (this.GetModuleOperationName(group) !== '' - ? this.GetModuleOperationName(group) - : this.Extension_NameUnderscored + '_cl'); - return cfName; - } - - public get CommandGroup_OperationTmplName(): string { - const operationTmpl = - this.GetPythonNamespace() + - '.operations._' + - this.GetModuleOperationNamePython() + - '_operations#' + - this.GetModuleOperationNamePythonUpper() + - '.{}'; - return operationTmpl; - } - - public CommandGroup_CustomCommandTypeName(group: OperationGroup = this.CommandGroup): string { - const customName = - this.Extension_NameUnderscored + '_' + this.GetModuleOperationName(group); - return customName; - } - - public get CommandGroup_ShowExample(): CommandExample { - return this.CommandGroup?.['az-show-example']; - } - - public set CommandGroup_ShowExample(example: CommandExample) { - if (this.CommandGroup) this.CommandGroup['az-show-example'] = example; - } - - // ----------------------------------------------------------------------------------------------------------------- - // Commands - // - // This interface provides enumeration of commands in selected command group. - // Note that it doesn't map directly into operations from code-model-v4 - // Azure CLI usually provides following commands to operate on single resource: - // (1) "az create" -> PUT - // (2) "az update" -> PUT or PATCH - // (3) "az show" -> GET - // (4) "az list" -> GET - // (5) "az delete" -> DELETE - // (6) "az any-other-specific operation" -> POST or GET - // - // NOTE: It would be nice if the implementation enumerates commands in the sequence as above. - // - // Commands (1) - (5) represent basic CRUD operations and "create" / "update" / "show" / "list" / "delete" follow - // standard naming conventions in Azure CLI - // - // Commands (6) are custom and operation name should be used to generate command name. - // Note that some GET operations may be also custom operations (not "list"). - // This can be recognised by URL - it will be longer than "base" PUT URL. - // - // In all the cases except of (4) mapping of command to operation in code-model-v4 is one to one. - // In case (4) several operations shall be grouped into a single command called "list", for instance: - // "list", "list-by-resource-group", "list-by-something" - // - // In case (1) and (2) there may be seveal patterns. - // (A) single "create_or_update" (PUT) method - // (B) create_or_update (PUT) and "update" (PATCH) method - // (C) "create" (PUT) method and "update" (PATCH) method - // - // In case (A) single method will be mapped into 2 Azure CLI commands: - // "az create" -> create_or_update (PUT) - // "az update" -> create_or_update (PUT) - // as there's no separate "update" method available. - // - // In case (B) we have one to one mapping: - // "az create" -> create_or_update (PUT) - // "az update" -> update (PATCH) - // - // In case (C) we have one to one mapping as well: - // "az create" -> create (PUT) - // "az update" -> update (PATCH) - // ----------------------------------------------------------------------------------------------------------------- - - public SelectFirstCommand(): boolean { - // just enumerate through commands in command group - if (this.CommandGroup.operations.length > 0) { - this.currentOperationIndex = 0; - const operation = this.Command; - this.preMethodIndex = this.currentOperationIndex; - let needNext = false; - if (this.Operation_IsHidden(operation)) { - needNext = true; - } - while (this.currentOperationIndex + 1 < this.CommandGroup.operations.length) { - const tmpOperation = this.CommandGroup.operations[this.currentOperationIndex + 1]; - if (tmpOperation.language['az'].command === operation.language['az'].command) { - this.currentOperationIndex++; - if (!this.Operation_IsHidden(tmpOperation)) { - needNext = false; - } - } else { - break; - } - } - if (needNext && !this.SelectNextCommand()) { - return false; - } - this.SelectFirstMethod(); - this.SelectFirstMethodParameter(); - return true; - } else { - this.currentOperationIndex = -1; - return false; - } - } - - public SelectNextCommand(): boolean { - if (this.currentOperationIndex < this.CommandGroup.operations.length - 1) { - this.currentOperationIndex++; - this.preMethodIndex = this.currentOperationIndex; - const operation = this.Command; - let needNext = false; - if (this.Operation_IsHidden(operation)) { - needNext = true; - } - while (this.currentOperationIndex < this.CommandGroup.operations.length - 1) { - const tmpOperation = this.CommandGroup.operations[this.currentOperationIndex + 1]; - if (operation.language['az'].command === tmpOperation.language['az'].command) { - this.currentOperationIndex++; - if (!this.Operation_IsHidden(tmpOperation)) { - needNext = false; - } - } else { - break; - } - } - if (needNext && !this.SelectNextCommand()) { - return false; - } - this.SelectFirstMethod(); - this.SelectFirstMethodParameter(); - return true; - } else { - this.currentOperationIndex = -1; - return false; - } - } - - public Operation_IsHidden(op: Operation = this.Method): boolean { - if ( - op.language['cli'].hidden || - op.language['cli'].removed || - op.language['cli']['cli-operation-splitted'] - ) { - return true; - } - return false; - } - - public get Command(): Operation { - if ( - this.currentOperationIndex < 0 || - this.currentOperationIndex >= this.CommandGroup.operations.length - ) { - return undefined; - } - return this.CommandGroup.operations[this.currentOperationIndex]; - } - - public get Command_FunctionName(): string { - return this.Command_Name.replace(/( |-)/g, '_'); - } - - public get Command_Name(): string { - return this.Command.language['az'].command; - } - - public get Command_MethodName(): string { - return this.Command.language['az'].name; - } - - public Command_GenericSetterParameter(op: Operation = this.Command): Parameter { - if (isNullOrUndefined(op)) { - return null; - } - return op['genericSetterParam']; - } - - public get Command_Help(): string { - return this.Command.language['az'].description.replace(/\n/g, ' ').replace(/"/g, '\\\\"'); - } - - public get Command_GetOriginalOperation(): any { - const polyOriginal = this.Command.extensions?.['cli-poly-as-resource-original-operation']; - if ( - !isNullOrUndefined(polyOriginal) && - !isNullOrUndefined(polyOriginal.extensions?.['cli-split-operation-original-operation']) - ) { - const splitOriginal = - polyOriginal.extensions?.['cli-split-operation-original-operation']; - return splitOriginal; - } - const splittedOriginal = this.Command.extensions?.[ - 'cli-split-operation-original-operation' - ]; - if (!isNullOrUndefined(splittedOriginal)) { - return splittedOriginal; - } - return polyOriginal; - } - - public get Command_OriginalCommandGroup(): OperationGroup { - if (!isNullOrUndefined(this.Command.language?.['az']?.['originalOperationGroup'])) { - return this.Command.language?.['az']?.['originalOperationGroup']; - } - return undefined; - } - - public get Command_ClientFactoryName(): string { - if (!isNullOrUndefined(this.Command_OriginalCommandGroup)) { - return this.CommandGroup_ClientFactoryName(this.Command_OriginalCommandGroup); - } - return undefined; - } - - public get Command_NeedGeneric(): boolean { - if ( - this.Command.language['az'].isSplitUpdate && - this.CommandGroup_HasShowCommand && - !isNullOrUndefined( - this.Command_GenericSetterParameter(this.Command_GetOriginalOperation), - ) - ) { - return true; - } - return false; - } - - public get Command_IsLongRun(): boolean { - return !!this.Command.extensions?.['x-ms-long-running-operation']; - } - - public get Command_SubGroupName(): string { - const subCommandGroupName = this.Command.language['az'].subCommandGroup; - return isNullOrUndefined(subCommandGroupName) ? '' : subCommandGroupName; - } - - public get Command_Mode(): string { - if (isNullOrUndefined(this.Command?.language?.['cli']?.extensionMode)) { - return this.CommandGroup_Mode; - } - return this.Command?.language?.['cli']?.extensionMode; - } - - public get Command_Type(): string { - if (this.Command_MethodName === 'show') { - return CliCommandType.CUSTOM_SHOW_COMMAND; - } else if (this.Command_NeedGeneric) { - if (!isNullOrUndefined(this.Command_GenericSetterArgName)) { - return CliCommandType.GENERIC_UPDATE_COMMAND; - } - } - return CliCommandType.CUSTOM_COMMAND; - } - - public get Command_GenericSetterArgName(): string { - const genericParam = this.Command_GenericSetterParameter(this.Command_GetOriginalOperation); - if (isNullOrUndefined(genericParam)) { - return undefined; - } - return this.Parameter_NamePython(genericParam); - } - - public get Command_MaxApi(): string { - return this.Command.language['cli']?.['max-api']; - } - - public get Command_MinApi(): string { - return this.Command.language['cli']?.['min-api']; - } - - public get Command_ResourceType(): string | undefined { - return this.formResourceType(this.Command.language['cli']?.['resource-type']); - } - - public formResourceType(config: string | undefined): string { - if (isNullOrUndefined(config) || config.startsWith('ResourceType.')) return config; - else return 'ResourceType.' + config; - } - - //= ================================================================================================================ - // Methods / Operations associated with the command. - // - // Usually there will be one to one relationship between command and method. - // However in one case described above ("az list"), several methods may be assigned with single - // command, for instance "list", "list-by-resource-group", "list-by-someting-else". - // list - // In case of "list" command all the GET operations associated with the resource should be enumerated here, - // except of GET operation that returns particular instance of a resource and is associated to "show" command. - // - // There is also additional requirement for sort order of returned methods. They should be sorted by number - // of arguments. Those with more arguments should be listed first. - //= ================================================================================================================ - - public SelectFirstMethod(): boolean { - if (this.currentOperationIndex >= this.preMethodIndex) { - this.currentMethodIndex = this.preMethodIndex; - const method = this.Method; - if (this.Operation_IsHidden(method)) { - if (!this.SelectNextMethod()) { - return false; - } - } - this.SelectFirstMethodParameter(); - return true; - } else { - this.currentMethodIndex = -1; - return false; - } - } - - public SelectNextMethod(): boolean { - if (this.currentMethodIndex < this.currentOperationIndex) { - this.currentMethodIndex++; - const method = this.Method; - if (this.Operation_IsHidden(method)) { - if (!this.SelectNextMethod()) { - return false; - } - } - this.SelectFirstMethodParameter(); - return true; - } else { - this.currentMethodIndex = -1; - return false; - } - } - - public get Request(): Request { - return this.Method.requests[0]; - } - - public get Method(): Operation { - if ( - this.currentMethodIndex < 0 || - this.currentMethodIndex >= this.CommandGroup.operations.length - ) { - return undefined; - } - return this.CommandGroup.operations[this.currentMethodIndex]; - } - - public get Method_IsFirst(): boolean { - if (this.currentMethodIndex === this.preMethodIndex) { - return true; - } else { - return false; - } - } - - public get Method_IsLast(): boolean { - if (this.currentMethodIndex === this.currentOperationIndex) { - return true; - } else { - let curIndex = this.currentMethodIndex + 1; - let hasNext = false; - while (curIndex <= this.currentOperationIndex) { - if (!this.Operation_IsHidden(this.CommandGroup.operations[curIndex])) { - hasNext = true; - break; - } - curIndex++; - } - return !hasNext; - } - } - - public get Method_IsLongRun(): boolean { - return !!this.Method.extensions?.['x-ms-long-running-operation']; - } - - public get Method_Name(): string { - return this.Method.language.python.name; - } - - public get Method_NameAz(): string { - return this.Method.language['az'].name; - } - - public get Method_NameCli(): string { - return this.Method.language['cli'].name; - } - - public get Method_CliKey(): string { - return this.Method.language['cli']?.cliKey; - } - - public get Method_MaxApi(): string { - return this.Method.language['cli']?.['max-api']; - } - - public get Method_MinApi(): string { - return this.Method.language['cli']?.['min-api']; - } - - public get Method_ResourceType(): string | undefined { - return this.formResourceType(this.Method.language['cli']?.['resource-type']); - } - - public get Method_BodyParameterName(): string { - return null; - } - - public get Method_Path(): string { - return this.Method.requests[0].protocol?.http?.path; - } - - public get Method_Help(): string { - return this.Method.language['az'].description.replace(/\n/g, ' ').replace(/"/g, '\\\\"'); - } - - public get Method_HttpMethod(): string { - const ret = this.Method.requests[0].protocol?.http?.method || 'unknown'; - return ret.toLowerCase(); - } - - public Method_GenericSetterParameter(op: Operation = this.Method): Parameter { - if (isNullOrUndefined(op)) { - return null; - } - return op['genericSetterParam']; - } - - public get Method_NeedGeneric(): boolean { - if ( - this.Method.language['az'].isSplitUpdate && - this.CommandGroup_HasShowCommand && - !isNullOrUndefined(this.Method_GenericSetterParameter(this.Method_GetOriginalOperation)) - ) { - return true; - } - return false; - } - - public Get_Method_Name(language = 'az'): string { - return this.Method.language[language].name; - } - - public get Method_GetOriginalOperation(): any { - const polyOriginal = this.Method.extensions?.['cli-poly-as-resource-original-operation']; - if ( - !isNullOrUndefined(polyOriginal) && - !isNullOrUndefined(polyOriginal.extensions?.['cli-split-operation-original-operation']) - ) { - const splitOriginal = - polyOriginal.extensions?.['cli-split-operation-original-operation']; - return splitOriginal; - } - const splittedOriginal = this.Method.extensions?.['cli-split-operation-original-operation']; - if (!isNullOrUndefined(splittedOriginal)) { - return splittedOriginal; - } - return polyOriginal; - } - - public get Method_GetSplitOriginalOperation(): any { - return this.Method.extensions?.['cli-split-operation-original-operation']; - } - - public get Method_Mode(): string { - if (isNullOrUndefined(this.Method?.language?.['cli']?.extensionMode)) { - return this.Command_Mode; - } - return this.Method?.language?.['cli']?.extensionMode; - } - - public get Method_AzExamples(): CommandExample[] { - return this.Method?.['az-examples']; - } - - public set Method_AzExamples(examples: CommandExample[]) { - if (isNullOrUndefined(this.Method_AzExamples) || this.Method_AzExamples.length === 0) { - this.Method['az-examples'] = examples; - } - } - - //= ================================================================================================================ - // Methods Parameters. - // - // This interface is designed to enumerate all parameters of the selected method and their mapping to Python SDK. - //= ================================================================================================================ - public SelectFirstMethodParameter(containHidden = false): boolean { - if (!isNullOrUndefined(this.submethodparameters)) { - this.currentSubOptionIndex = 0; - const parameter = this.submethodparameters[this.currentSubOptionIndex]; - if (this.Parameter_IsHidden(parameter) && !containHidden) { - if (!this.SelectNextMethodParameter(containHidden)) { - return false; - } - } - return true; - } - if (this.MethodParameters.length > 0) { - this.currentParameterIndex = 0; - if ( - (this.MethodParameter_IsHidden && !containHidden) || - this.codeModel.globalParameters.indexOf(this.MethodParameter) > -1 - ) { - if (this.SelectNextMethodParameter(containHidden)) { - return true; - } else { - return false; - } - } - return true; - } else { - return false; - } - } - - public SelectNextMethodParameter(containHidden = false): boolean { - if (!isNullOrUndefined(this.submethodparameters)) { - this.currentSubOptionIndex++; - - if (this.currentSubOptionIndex >= this.submethodparameters.length) { - return false; - } - const parameter = this.submethodparameters[this.currentSubOptionIndex]; - if (this.Parameter_IsHidden(parameter) && !containHidden) { - if (!this.SelectNextMethodParameter(containHidden)) { - return false; - } - } - return true; - } - if (this.currentParameterIndex < this.MethodParameters.length - 1) { - this.currentParameterIndex++; - if ( - (this.MethodParameter_IsHidden && !containHidden) || - this.codeModel.globalParameters.indexOf(this.MethodParameter) > -1 - ) { - if (this.SelectNextMethodParameter(containHidden)) { - return true; - } else { - return false; - } - } - return true; - } else { - return false; - } - } - - public EnterSubMethodParameters(param: Parameter = this.MethodParameter): boolean { - const subParams = this.GetSubParameters(param); - if (isNullOrUndefined(subParams)) { - return false; - } else { - if (isNullOrUndefined(this.substack)) { - this.substack = new Array<[Parameter[], number]>(); - } - // reserve previous status - if (!isNullOrUndefined(this.submethodparameters)) { - this.substack.push([this.submethodparameters, this.currentSubOptionIndex]); - } - this.submethodparameters = subParams; - this.currentSubOptionIndex = 0; - return true; - } - } - - public GetSubParameters(param: Parameter = this.MethodParameter): Parameter[] { - // this should only works for - // 1. objects with simple properties - // 2. or objects with arrays as properties but has simple element type - // 3. or arrays with simple element types - // 4. or arrays with object element types but has simple properties - if (!this.Parameter_IsList(param)) { - return null; - } - if (!this.Parameter_IsListOfSimple(param)) { - return null; - } - - let submethodparameters = []; - if ( - this.Parameter_Type(param) === SchemaType.Array || - this.Parameter_Type(param) === SchemaType.Dictionary - ) { - if (param.schema['elementType'].type === SchemaType.Object) { - if (!isNullOrUndefined(param.schema?.['elementType']?.properties)) { - submethodparameters = param.schema?.['elementType']?.properties; - } - for (const parent of values(param.schema?.['elementType']?.parents?.all)) { - if (isNullOrUndefined(parent['properties'])) { - continue; - } - submethodparameters = submethodparameters.concat(parent['properties']); - } - } - } else if (this.Parameter_Type(param) === SchemaType.Object) { - if (!isNullOrUndefined(param.schema['properties'])) { - submethodparameters = param.schema['properties']; - } - for (const parent of values(param.schema?.['parents']?.all)) { - if (isNullOrUndefined(parent['properties'])) { - continue; - } - submethodparameters = submethodparameters.concat(parent['properties']); - } - } - if (submethodparameters.length === 0) { - return null; - } - return submethodparameters; - } - - public ExitSubMethodParameters(): boolean { - if (!isNullOrUndefined(this.submethodparameters)) { - if (this.substack.length > 0) { - const lastsub = this.substack.last; - this.submethodparameters = lastsub[0]; - this.currentSubOptionIndex = lastsub[1]; - this.substack.pop(); - } else { - this.submethodparameters = null; - this.currentSubOptionIndex = -1; - } - return true; - } - return false; - } - - public Parameter_SetAzNameMapsTo( - newName: string, - param: Parameter = this.MethodParameter, - ): void { - if (!isNullOrUndefined(param['nameBaseParam'])) { - param['nameBaseParam'].subParams[this.Method.language['cli'].name] = newName; - } - param.language['az'].mapsto = newName; - } - - public get MethodParameter_ActionName() { - const schema = this.MethodParameter.schema; - if (this.paramActionNameReference.has(schema)) { - return this.paramActionNameReference.get(schema); - } - return undefined; - } - - public get MethodParameter_Name(): string { - return this.Parameter_Name(this.MethodParameter); - } - - public get MethodParameter_NameAz(): string { - return this.Parameter_NameAz(this.MethodParameter); - } - - public get MethodParameter_CliKey(): string { - return this.Parameter_CliKey(this.MethodParameter); - } - - public get MethodParameter_MaxApi(): string { - return this.MethodParameter.language['cli']?.['max-api']; - } - - public get MethodParameter_MinApi(): string { - return this.MethodParameter.language['cli']?.['min-api']; - } - - public get MethodParameter_ResourceType(): string | undefined { - return this.formResourceType(this.MethodParameter.language['cli']?.['resource-type']); - } - - public get MethodParameter_IdPart(): string { - return this.MethodParameter.language['az'].id_part; - } - - public get MethodParameter_IsArray(): boolean { - if (!isNullOrUndefined(this.submethodparameters)) { - return ( - this.submethodparameters[this.currentSubOptionIndex].schema?.type === - SchemaType.Array - ); - } else { - return this.MethodParameter.schema?.type === SchemaType.Array; - } - } - - public get MethodParameter_NamePython(): string { - return this.Parameter_NamePython(this.MethodParameter); - } - - public get MethodParameter_MapsTo(): string { - return this.Parameter_MapsTo(this.MethodParameter); - } - - public Parameter_MapsTo(param: Parameter = this.MethodParameter): string { - if (EXCLUDED_PARAMS.indexOf(param.language['az'].mapsto) > -1) { - param.language['az'].mapsto = 'gen_' + param.language['az'].mapsto; - } - return param.language['az'].mapsto; - } - - public Parameter_SubMapsTo(subMethodName: string, param: Parameter = this.MethodParameter) { - if (!isNullOrUndefined(param?.['subParams']?.[subMethodName])) { - return param['subParams'][subMethodName]; - } - return this.Parameter_MapsTo(param); - } - - public Schema_MapsTo(schema: Schema): string { - return schema.language['az'].mapsto; - } - - public get MethodParameter_Description(): string { - return this.Parameter_Description(this.MethodParameter); - } - - public get MethodParameter_Type(): string { - return this.Parameter_Type(this.MethodParameter); - } - - public get MethodParameter_IsList(): boolean { - return this.Parameter_IsList(this.MethodParameter); - } - - public get MethodParameter_ArgGroup(): string { - return this.MethodParameter.language['az']?.arg_group; - } - - public get MethodParameter_Mode() { - if (isNullOrUndefined(this.MethodParameter?.language?.['cli']?.extensionMode)) { - return this.Method_Mode; - } - return this.MethodParameter?.language?.['cli']?.extensionMode; - } - - public get MethodParameter_IsPositional(): boolean { - return this.Parameter_IsPositional(this.MethodParameter); - } - - public get MethodParameter_IsShorthandSyntax(): boolean { - return this.Parameter_IsShorthandSyntax(this.MethodParameter); - } - - public isComplexSchema(type: string, param: any): boolean { - if ( - type === SchemaType.Array || - type === SchemaType.Object || - type === SchemaType.Dictionary || - type === SchemaType.Any || - param?.language?.['cli']?.json === true - ) { - return true; - } else { - return false; - } - } - - public get MethodParameter_IsListOfSimple(): boolean { - return this.Parameter_IsListOfSimple(this.MethodParameter); - } - - public Parameter_Type(param: Parameter = this.MethodParameter): string { - return this.Schema_Type(param?.schema); - } - - public Schema_Type(schema: Schema = this.MethodParameter.schema): string { - if (isNullOrUndefined(schema)) { - return undefined; - } - return schema.type; - } - - public Parameter_IsFlattened(param: Parameter = this.MethodParameter): boolean { - return !!param.flattened; - } - - public Parameter_IsShorthandSyntax(param: Parameter = this.MethodParameter): boolean { - return !!param.language['cli']?.shorthandSyntax; - } - - public Parameter_IsCliFlattened(param: Parameter = this.MethodParameter): boolean { - if ( - param?.language?.['cli']?.['cli-flattened'] && - !param.language['cli']['cli-m4-flattened'] - ) { - if (param['nameBaseParam']?.language?.['cli']?.['cli-m4-flattened']) { - return false; - } - return true; - } - return false; - } - - public Parameter_IsListOfSimple(param: Parameter = this.MethodParameter): boolean { - // objects that is not base class of polymorphic and satisfy one of the four conditions - // 1. objects with simple properties - // 2. or objects with arrays as properties but has simple element type - // 3. or arrays with simple element types - // 4. or arrays with object element types but has simple properties - // 5. or dicts with simple element properties - // 6. or dicts with arrays as element properties but has simple element type - if (this.Parameter_Type(param) === SchemaType.Any) { - return false; - } - if (this.Parameter_IsFlattened(param)) { - return false; - } - if (param.language['cli'].json === true) { - return false; - } - return this.Schema_IsListOfSimple(param.schema); - } - - public Schema_IsListOfSimple(schema: Schema = this.MethodParameter.schema): boolean { - // objects that is not base class of polymorphic and satisfy one of the four conditions - // 1. objects with simple properties - // 2. or objects with arrays as properties but has simple element type - // 3. or arrays with simple element types - // 4. or arrays with object element types but has simple properties - // 5. or dicts with simple element properties - // 6. or dicts with arrays as element properties but has simple element type - if (this.Schema_Type(schema) === SchemaType.Any) { - return false; - } - if (schema?.language?.['cli']?.json === true) { - return false; - } - if (this.Schema_Type(schema) === SchemaType.Array) { - if ( - schema['elementType'].type === SchemaType.Object || - schema['elementType'].type === SchemaType.Dictionary - ) { - for (const p of values(schema['elementType']?.properties)) { - if (p['readOnly']) { - continue; - } - if ( - p['schema'].type === SchemaType.Object || - p['schema'].type === SchemaType.Dictionary - ) { - return false; - } else if (p['schema'].type === SchemaType.Array) { - if (this.isComplexSchema(p['schema']?.elementType?.type, p['schema'])) { - return false; - } - for (const mp of values(p['schema']?.elementType?.properties)) { - if (this.isComplexSchema(mp['schema'].type, mp['schema'])) { - return false; - } - } - for (const parent of values(p['schema']?.elementType?.parents?.all)) { - for (const pp of values(parent['properties'])) { - if (this.isComplexSchema(pp['schema'].type, pp['schema'])) { - return false; - } - } - } - } else if (this.isComplexSchema(p['schema'].type, p['schema'])) { - return false; - } - } - return true; - } - } else if (this.Schema_Type(schema) === SchemaType.Object) { - if ( - !isNullOrUndefined(schema['children']) && - !isNullOrUndefined(schema['discriminator']) - ) { - return false; - } - for (const p of values(schema['properties'])) { - if (p['readOnly']) { - continue; - } - if ( - p['schema'].type === SchemaType.Object || - p['schema'].type === SchemaType.Dictionary - ) { - // objects.objects - return false; - } else if (p['schema'].type === SchemaType.Array) { - for (const mp of values(p['schema']?.elementType?.properties)) { - if (this.isComplexSchema(mp['schema'].type, mp['schema'])) { - return false; - } - } - for (const parent of values(p['schema']?.elementType?.parents?.all)) { - for (const pp of values(parent['properties'])) { - if (this.isComplexSchema(pp['schema'].type, pp['schema'])) { - return false; - } - } - } - } else if (this.isComplexSchema(p['schema'].type, p['schema'])) { - // objects.objects - return false; - } - } - return true; - } else if (this.Schema_Type(schema) === SchemaType.Dictionary) { - if ( - !isNullOrUndefined(schema['children']) && - !isNullOrUndefined(schema['discriminator']) - ) { - return false; - } - const p = schema['elementType']; - if (p.type === SchemaType.Object || p.type === SchemaType.Dictionary) { - // dicts.objects or dicts.dictionaries - return false; - } else if (p.type === SchemaType.Array) { - for (const mp of values(p.properties)) { - if (mp['readOnly']) { - continue; - } - if (this.isComplexSchema(mp['schema'].type, mp['schema'])) { - return false; - } - } - for (const parent of values(p.schema?.elementType?.parents?.all)) { - for (const pp of values(parent['properties'])) { - if (pp['readOnly']) { - continue; - } - if (this.isComplexSchema(pp['schema'].type, pp['schema'])) { - return false; - } - } - } - } else if (this.isComplexSchema(p.type, p)) { - // dicts.objects or dicts.dictionaries - return false; - } - return true; - } else if (this.MethodParameter_Type === SchemaType.Any) { - return false; - } - return false; - } - - public get MethodParameter_IsPolyOfSimple(): boolean { - return this.Parameter_IsPolyOfSimple(this.MethodParameter); - } - - public get MethodParameter_IsDiscriminator(): boolean { - return ( - this.Method_GetOriginalOperation && - this.MethodParameter['targetProperty'] && - this.MethodParameter['targetProperty']['isDiscriminator'] - ); - } - - public Parameter_IsPolyOfSimple(param: Parameter = this.MethodParameter): boolean { - if (!isNullOrUndefined(param['isPolyOfSimple'])) { - return param['isPolyOfSimple']; - } - if ( - param?.schema?.type === SchemaType.Object && - !isNullOrUndefined(param.schema['children']) && - !isNullOrUndefined(param.schema['discriminator']) - ) { - let isSimplePoly = true; - for (const child of param.schema['children'].all) { - if (this.Schema_IsList(child) && this.Schema_IsListOfSimple(child)) { - continue; - } - isSimplePoly = false; - break; - } - if (isSimplePoly) { - param['isPolyOfSimple'] = true; - } else { - param['isPolyOfSimple'] = false; - } - return isSimplePoly; - } - return false; - } - - public get MethodParameter_IsSimpleArray(): boolean { - return this.Parameter_IsSimpleArray(this.MethodParameter); - } - - private Parameter_IsSimpleArray(param: Parameter): boolean { - if (this.Parameter_Type(param) === SchemaType.Array) { - const elementType = param.schema['elementType'].type; - if (!this.isComplexSchema(elementType, param.schema)) { - return true; - } - } - return false; - } - - public Parameter_IsList(param: Parameter = this.MethodParameter): boolean { - if (this.Parameter_IsFlattened(param)) { - return false; - } - - if (this.isComplexSchema(this.Parameter_Type(param), param)) { - return true; - } - return false; - } - - public Parameter_PositionalKeys(param: Parameter, subMethodParams: Parameter[]): string[] { - let keys = []; - if (!(this.Parameter_IsList(param) && this.Parameter_IsListOfSimple(param))) { - return null; - } - if ( - !isNullOrUndefined(param.language?.['az']?.positionalKeys) && - Array.isArray(param.language?.['az']?.positionalKeys) - ) { - keys = param.language?.['az']?.positionalKeys; - } - - if ( - keys.length === 0 && - !isNullOrUndefined(param.schema.language?.['cli']?.positionalKeys) && - Array.isArray(param.schema.language?.['cli']?.positionalKeys) - ) { - keys = param.schema.language?.['cli']?.positionalKeys; - } - - const allPossibleKeys = []; - const requiredKeys = []; - for (const subMethodParam of subMethodParams) { - if (subMethodParam['readOnly']) { - continue; - } - if (subMethodParam.schema?.type === SchemaType.Constant) { - continue; - } - allPossibleKeys.push(this.Parameter_NamePython(subMethodParam)); - if (subMethodParam.required || subMethodParam.language?.['cli'].required) { - if (!this.Parameter_IsHidden(subMethodParam)) { - requiredKeys.push(this.Parameter_NamePython(subMethodParam)); - } - } - } - - const coveredResult = keys.every((val) => allPossibleKeys.includes(val)); - const requiredCovered = requiredKeys.every((val) => keys.includes(val)); - - if (keys.length > 0) { - if (coveredResult && requiredCovered) { - return keys; - } else { - let text = ''; - if (!coveredResult) { - text += - 'The defined positional keys for ' + - this.Parameter_CliKey(param) + - ' contains invalid keys. All possible keys are: ' + - allPossibleKeys.join(', ') + - ' \n'; - } - if (!requiredCovered) { - text += - 'The defined positional keys for ' + - this.Parameter_CliKey(param) + - " doesn't contain all required keys. All required keys are: " + - requiredKeys.join(', ') + - ' \n'; - } - this.session.message({ Channel: Channel.Fatal, Text: text }); - return null; - } - } - - return allPossibleKeys; - } - - public get MethodParameter_PositionalKeys(): string[] { - const subMethodParams: Parameter[] = []; - if (this.EnterSubMethodParameters()) { - if (this.SelectFirstMethodParameter(true)) { - do { - subMethodParams.push(this.SubMethodParameter); - } while (this.SelectNextMethodParameter(true)); - } - this.ExitSubMethodParameters(); - } - return this.Parameter_PositionalKeys(this.MethodParameter, subMethodParams); - } - - public Schema_IsList(schema: Schema = this.MethodParameter.schema): boolean { - if (schema.language['cli'].json === true) { - return true; - } - if (this.isComplexSchema(this.Schema_Type(schema), schema)) { - return true; - } - return false; - } - - public get MethodParameter(): Parameter { - return this.MethodParameters[this.currentParameterIndex]; - } - - public get MethodParameters(): Array { - if (isNullOrUndefined(this.Request) || isNullOrUndefined(this.Request.parameters)) { - return this.Method.parameters; - } - return this.Method.parameters.concat(this.Request.parameters); - } - - public MethodParameters_AddPolySubClass(oriParam: Parameter, params: Parameter[]): boolean { - if (isNullOrUndefined(params) || isNullOrUndefined(oriParam) || params.length <= 0) { - return false; - } - if (this.Method.parameters.indexOf(oriParam) > -1) { - this.Method.parameters.splice( - this.Method.parameters.indexOf(oriParam) + 1, - 0, - ...params, - ); - return true; - } - if (!isNullOrUndefined(this.Request) && !isNullOrUndefined(this.Request.parameters)) { - if (this.Request.parameters.indexOf(oriParam) > -1) { - this.Request.parameters.splice( - this.Request.parameters.indexOf(oriParam) + 1, - 0, - ...params, - ); - return true; - } - } - return false; - } - - public get SubMethodParameter(): Parameter { - if (!isNullOrUndefined(this.submethodparameters)) { - return this.submethodparameters[this.currentSubOptionIndex]; - } - return null; - } - - public get MethodParameter_EnumValues(): string[] { - const mtype = this.MethodParameter.schema.type; - if (mtype === SchemaType.Choice || mtype === SchemaType.SealedChoice) { - const enumArray = []; - const schema = this.MethodParameter.schema; - for (const item of schema['choices']) { - enumArray.push(item.value); - } - return enumArray; - } else { - return []; - } - } - - public get MethodParameter_In(): string { - const protocol = this.MethodParameter.protocol; - return protocol !== undefined && - protocol.http !== undefined && - protocol.http.in !== undefined - ? protocol.http.in - : ParameterLocation.Body; - } - - public get MethodParameter_IsHidden(): boolean { - return this.Parameter_IsHidden(this.MethodParameter); - } - - public Parameter_IsHidden(parameter: Parameter): boolean { - if (!Object.prototype.hasOwnProperty.call(parameter.language['az'], 'hidden')) { - // Handle complex - let shouldHidden; - let defaultValue; - let hasDefault = false; - if (this.EnterSubMethodParameters(parameter)) { - shouldHidden = true; - defaultValue = '{'; - if (this.SelectFirstMethodParameter()) { - do { - if ( - this.Parameter_Type(this.SubMethodParameter) !== SchemaType.Constant && - this.SubMethodParameter['readOnly'] !== true - ) { - shouldHidden = false; - break; - } else if ( - this.Parameter_Type(this.SubMethodParameter) === SchemaType.Constant - ) { - defaultValue = - defaultValue + - '"' + - this.Parameter_NameAz(this.SubMethodParameter) + - '": "' + - this.Parameter_DefaultValue(this.SubMethodParameter) + - '"'; - hasDefault = true; - } - } while (this.SelectNextMethodParameter()); - } - if (shouldHidden === true && (hasDefault || this.Schema_IsRequired(parameter))) { - defaultValue = defaultValue + '}'; - } else { - defaultValue = undefined; - } - this.ExitSubMethodParameters(); - } - - // Handle simple parameter - if (parameter?.language?.['cli']?.removed || parameter?.language?.['cli']?.hidden) { - if ( - this.Parameter_DefaultValue(parameter) === undefined && - parameter.required === true - ) { - parameter.language['az'].hidden = false; - this.session.message({ - Channel: Channel.Warning, - Text: - 'OperationGroup ' + - this.CommandGroup.language['az'].name + - ' operation ' + - this.Method_Name + - ' parameter ' + - parameter.language['az'].name + - ' should not be hidden while it is required without default value', - }); - } else { - parameter.language['az'].hidden = true; - } - } else { - parameter.language['az'].hidden = parameter['hidden'] ?? shouldHidden ?? false; - if ( - !Object.prototype.hasOwnProperty.call( - parameter.language['az'], - 'default-value', - ) && - defaultValue !== undefined - ) { - parameter.language['az']['default-value'] = defaultValue; - } - } - } - - return parameter.language['az'].hidden; - } - - public get MethodParameter_DefaultValue(): string | undefined { - return this.Parameter_DefaultValue(this.MethodParameter); - } - - public get MethodParameter_DefaultConfigKey(): string | undefined { - return this.Parameter_DefaultConfigKey(this.MethodParameter); - } - - public Parameter_DefaultValue(parameter: Parameter): string | undefined { - if (!Object.prototype.hasOwnProperty.call(parameter.language['az'], 'default-value')) { - if ( - Object.prototype.hasOwnProperty.call(parameter?.language?.['cli'], 'default-value') - ) { - parameter.language['az']['default-value'] = - parameter.language['cli']['default-value']; - } else if (parameter.schema.type === SchemaType.Constant) { - parameter.language['az']['default-value'] = parameter.schema?.['value']?.value; - } else { - parameter.language['az']['default-value'] = parameter.schema.defaultValue; - } - } - - return parameter.language['az']['default-value']; - } - - public Parameter_DefaultConfigKey(parameter: Parameter): string | undefined { - if (!Object.prototype.hasOwnProperty.call(parameter.language['az'], 'default-config-key')) { - if ( - Object.prototype.hasOwnProperty.call( - parameter?.language?.['cli'], - 'default-config-key', - ) - ) { - parameter.language['az']['default-config-key'] = - parameter.language['cli']['default-config-key']; - } - } - return parameter.language['az']['default-config-key']; - } - - public Parameter_Description(param: Parameter = this.MethodParameter): string { - return param.language['az'].description?.replace(/\r?\n|\r/g, ' '); - } - - public Schema_Description(schema: Schema): string { - return schema.language['az'].description?.replace(/\r?\n|\r/g, ' '); - } - - public Schema_FlattenedFrom(schema: Schema): Schema { - return schema?.language['cli']?.pythonFlattenedFrom; - } - - public Schema_IsPositional(schema: Schema): boolean { - return schema?.language?.['cli']?.positional; - } - - public Parameter_InGlobal(parameter: Parameter): boolean { - if (this.codeModel.globalParameters.indexOf(parameter) > -1) { - return true; - } - return false; - } - - public Parameter_Name(param: Parameter = this.MethodParameter): string { - return param.language['az'].name.replace(/-/g, '_'); - } - - public Parameter_NameAz(param: Parameter = this.MethodParameter): string { - return param.language['az'].name; - } - - public Parameter_CliKey(param: Parameter = this.MethodParameter): string { - return param.language['cli']?.cliKey; - } - - public Parameter_NamePython(param: Parameter = this.MethodParameter): string { - if (this.SDK_IsTrack1 && !isNullOrUndefined(param.language['cli']?.track1_name)) { - return param.language['cli']?.track1_name; - } - return param.language?.python?.name; - } - - public Parameter_IsPositional(param: Parameter = this.MethodParameter): boolean { - if (param?.schema && this.Schema_IsPositional(param.schema)) { - return true; - } - return !!param?.language?.['cli']?.positional; - } - - public get MethodParameter_IsRequired(): boolean { - return this.Parameter_IsRequired(this.MethodParameter); - } - - private Parameter_IsRequired(param: Parameter): boolean { - return param?.required; - } - - private Parameter_IsRequiredOrCLIRequired(param: Parameter): boolean { - return this.Parameter_IsRequired(param) || param?.language?.['cli']?.required; - } - - private Schema_IsRequired(param: Parameter): boolean { - return param?.['targetProperty']?.required; - } - - public get MethodParameter_IsFlattened(): boolean { - return this.Parameter_IsFlattened(this.MethodParameter); - } - - public get MethodParameter_IsCliFlattened(): boolean { - return this.Parameter_IsCliFlattened(this.MethodParameter); - } - - public get MethodParameter_RequiredByMethod(): boolean { - return this.MethodParameter['RequiredByMethod']; - } - - //= ================================================================================================================ - // Top Level Python Related Information - // - // Most of the information included here should be either produced by Python namer, or come from readme.az.md file. - // Detailed descriptions below. - //= ================================================================================================================ - - public GetModuleOperationName(group: OperationGroup = this.CommandGroup): string { - return ToSnakeCase(group.language.default.name); - } - - public GetModuleOperationNamePython(): string { - if (this.CommandGroup_CliKey === '') { - return this.codeModel.info['python_title']; - } - if ( - this.SDK_IsTrack1 && - !isNullOrUndefined(this.CommandGroup.language['cli']?.track1_name) - ) { - return this.CommandGroup.language['cli']?.track1_name; - } - return this.CommandGroup.language.python.name; - } - - public GetModuleOperationNamePythonUpper(): string { - if ( - this.SDK_IsTrack1 && - !isNullOrUndefined(this.CommandGroup.language['cli']?.track1_class_name) - ) { - return this.CommandGroup.language['cli']?.track1_class_name; - } - return this.CommandGroup.language.python.className; - } - - public GetPythonNamespace(): string { - return AzConfiguration.getValue(CodeGenConstants.pythonNamespace); - } - - public GetPythonPackageName(): string { - return this.options['package-name']; - } - - public get PythonMgmtClient(): string { - return this.codeModel.info['pascal_case_title']; - } - - //= ================================================================================================================ - // Example / Test Scenario related interface. - // - // This interface enumerates examples related to currently selected command. - // It should be implemented when example processor implementation is in place. - //= ================================================================================================================ - - public SelectFirstExample(): boolean { - if (this.Method.extensions === undefined) { - return false; - } - - const example = this.Method.extensions['x-ms-examples']; - if (example && example.length > 0) { - this.currentExampleIndex = 0; - return true; - } else { - this.currentExampleIndex = -1; - return false; - } - } - - public SelectNextExample(): boolean { - const example = this.Method.extensions['x-ms-examples']; - if (example && this.currentExampleIndex < example.length - 1) { - this.currentExampleIndex++; - return true; - } else { - this.currentExampleIndex = -1; - return false; - } - } - - public SelectFirstAzExample(): boolean { - if (this.Method.extensions === undefined) { - return false; - } - - const example = this.Method['az-examples']; - if (example && example.length > 0) { - this.currentAzExampleIndex = 0; - return true; - } else { - this.currentAzExampleIndex = -1; - return false; - } - } - - public SelectNextAzExample(): boolean { - const example = this.Method['az-examples']; - if (example && this.currentAzExampleIndex < example.length - 1) { - this.currentAzExampleIndex++; - return true; - } else { - this.currentAzExampleIndex = -1; - return false; - } - } - - public get Examples(): unknown { - const extensions = this.Method.extensions; - return extensions && 'x-ms-examples' in extensions ? extensions['x-ms-examples'] : {}; - } - - public get ExampleAmount(): number { - return Object.keys(this.Examples).length; - } - - public get AzExample(): CommandExample { - if ( - this.currentAzExampleIndex < 0 || - this.currentAzExampleIndex >= this.Method_AzExamples.length - ) { - return undefined; - } - return this.Method_AzExamples[this.currentAzExampleIndex]; - } - - public get AzExample_CommandString(): string { - return this.AzExample.CommandString; - } - - public get AzExample_Id(): string { - return this.AzExample.Id; - } - - public get AzExample_HttpMethod(): string { - return this.AzExample.HttpMethod; - } - - public get AzExample_CommandStringItems(): string[] { - const items = []; - ToMultiLine( - this.AzExample_CommandString, - items, - CodeGenConstants.PYLINT_MAX_CODE_LENGTH, - true, - ); - return items; - } - - public get AzExample_RawCommandStringItems(): string[] { - return this.AzExample.commandStringItems; - } - - public get AzExample_IsGenerated(): boolean { - return isGeneratedExampleId(this.AzExample?.Id); - } - - /** - * Gets method parameters dict - * @returns method parameters dict : key is parameter name, value is the parameter schema - */ - public GetMethodParametersList(): MethodParam[] { - const methodParamList: MethodParam[] = []; - - if (this.SelectFirstMethodParameter()) { - do { - if ( - (this.MethodParameter.implementation === 'Method' || - this.MethodParameter['polyBaseParam']) && - !this.MethodParameter_IsFlattened && - this.MethodParameter?.schema?.type !== 'constant' - ) { - let submethodparameters = null; - if (this.EnterSubMethodParameters()) { - submethodparameters = this.submethodparameters; - this.ExitSubMethodParameters(); - } - methodParamList.push( - new MethodParam( - this.MethodParameter, - this.Parameter_IsList(this.MethodParameter), - this.MethodParameter_IsListOfSimple || - this.MethodParameter_IsSimpleArray, - submethodparameters, - this.currentParameterIndex >= this.Method.parameters.length, - ), - ); - } - } while (this.SelectNextMethodParameter()); - } - return methodParamList; - } - - public GetExampleParameters(exampleObj): ExampleParam[] { - const parameters: ExampleParam[] = []; - const methodParamList: MethodParam[] = this.GetMethodParametersList(); - Object.entries(exampleObj.parameters).forEach(([paramName, paramValue]) => { - this.FlattenExampleParameter(methodParamList, parameters, paramName, paramValue, []); - }); - return parameters; - } - - private isDiscriminator(param: any): boolean { - return this.Command_GetOriginalOperation && param?.targetProperty?.isDiscriminator - ? true - : false; - } - - private AddExampleParameter( - methodParam: MethodParam, - exampleParam: ExampleParam[], - value: any, - polySubParam: MethodParam, - ancestors: string[], - rawValue: any, - ): boolean { - if (isNullOrUndefined(methodParam)) return false; - let isList: boolean = methodParam.isList; - let isSimpleListOrArray: boolean = methodParam.isSimpleListOrArray; - let defaultName: string = methodParam.value.language['cli'].cliKey; - let name: string = this.Parameter_MapsTo(methodParam.value); - if ( - !isNullOrUndefined(methodParam.value.language?.['az']?.alias) && - Array.isArray(methodParam.value.language['az'].alias) && - methodParam.value.language['az'].alias.length > 0 - ) { - name = methodParam.value.language['az'].alias[0]; - } - let realParam = methodParam; - if (polySubParam) { - isList = polySubParam.isList; - isSimpleListOrArray = polySubParam.isSimpleListOrArray; - defaultName = polySubParam.value.language['cli'].cliKey; - name = this.Parameter_MapsTo(polySubParam.value); - if ( - !isNullOrUndefined(polySubParam.value.language?.['az']?.alias) && - Array.isArray(polySubParam.value.language['az'].alias) && - polySubParam.value.language['az'].alias.length > 0 - ) { - name = polySubParam.value.language['az'].alias[0]; - } - realParam = polySubParam; - } - - function toActionString( - model: CodeModelCliImpl, - dict, - seperator = ' ', - initKeys = undefined, - ): [string, string[]] { - let ret = ''; - let keys: string[] = []; - if (!isNullOrUndefined(initKeys)) { - keys = initKeys; - } - for (const k in dict) { - let cliName = null; - for (const param of [methodParam, polySubParam]) { - if (param?.submethodparameters) { - for (const submethodProperty of param.submethodparameters) { - if ( - submethodProperty.language['cli'].cliKey.toLowerCase() === - k.toLowerCase() - ) { - cliName = model.Parameter_NameAz(submethodProperty); - } - } - } - } - if (!cliName) { - // If no submethodparameters, keep all KEYs as the origin name - // This is for type of schema.Dictionary - cliName = k; - } - if (dict[k] instanceof Array) { - for (const v of dict[k]) { - if (ret.length > 0) { - ret += seperator; - } - ret += `${cliName}=${ToJsonString(v)}`; - } - } else { - if (ret.length > 0) { - ret += seperator; - } - const v = ToJsonString(dict[k]); - // if (v.startsWith("\"")) { - // v = v.substr(1, v.length-2); - // } - ret += `${cliName}=${v}`; - } - if (!keys.includes(cliName)) keys.push(cliName); - } - return [ret, keys]; - } - - let handled = false; - if (isList) { - if (isSimpleListOrArray) { - let keys = []; - let ret = ''; - if (value instanceof Array) { - // spread list - handled = true; - if (this.Parameter_IsShorthandSyntax(realParam.value)) { - for (let i = 0; i < value.length; i++) { - let instanceString: string; - [instanceString, keys] = toActionString(this, value[i], ',', keys); - instanceString = instanceString.trim(); - if (ret.length > 0 && instanceString.length > 0) ret += ' '; - ret += instanceString; - } - exampleParam.push( - new ExampleParam( - name, - ret, - false, - KeyValueType.ShorthandSyntax, - keys, - defaultName, - realParam, - ancestors, - value, - ), - ); - } else if (this.Parameter_IsSimpleArray(realParam.value)) { - if (value.length > 0) { - // use value only when it's lenght > 0 - for (let i = 0; i < value.length; i++) { - ret += ToJsonString(value[i]) + ' '; - } - ret = ret.trim(); - exampleParam.push( - new ExampleParam( - name, - ret, - false, - KeyValueType.SimpleArray, - [], - defaultName, - realParam, - ancestors, - value, - ), - ); - } - } else { - for (let i = 0; i < value.length; i++) { - this.AddExampleParameter( - methodParam, - exampleParam, - value[i], - polySubParam, - ancestors, - rawValue[i], - ); - } - } - } else if (typeof rawValue === 'object') { - // KEY=VALUE form - handled = true; - if (this.Parameter_IsPositional(realParam.value)) { - keys = this.Parameter_PositionalKeys( - realParam.value, - realParam.submethodparameters, - ); - for (const k of keys) { - ret += ' '; - FIND_PARAM: for (const param of [polySubParam, methodParam]) { - if (param?.submethodparameters) { - for (const subMethodParam of param.submethodparameters) { - if (this.Parameter_NamePython(subMethodParam) === k) { - ret += ToJsonString( - rawValue[subMethodParam.language['cli'].cliKey], - ); - break FIND_PARAM; - } - } - } - } - } - } - ret = ret.trim(); - if (ret.trim().length > 0) { - exampleParam.push( - new ExampleParam( - name, - ret, - false, - KeyValueType.PositionalKey, - keys, - defaultName, - realParam, - ancestors, - value, - ), - ); - } else { - /// ///////// - [ret, keys] = toActionString(this, value); - if (ret.length > 0) { - exampleParam.push( - new ExampleParam( - name, - ret, - false, - KeyValueType.Classic, - keys, - defaultName, - realParam, - ancestors, - value, - ), - ); - } - } - } - } - if (!handled) { - if (typeof value === 'string') { - exampleParam.push( - new ExampleParam( - name, - value, - false, - KeyValueType.No, - [], - defaultName, - realParam, - ancestors, - value, - ), - ); - } else { - // JSON form - exampleParam.push( - new ExampleParam( - name, - JSON.stringify(value) - .split(/[\r\n]+/) - .join(''), - true, - KeyValueType.No, - [], - defaultName, - realParam, - ancestors, - value, - ), - ); - } - } - } else if (typeof value !== 'object') { - exampleParam.push( - new ExampleParam( - name, - value, - false, - KeyValueType.No, - [], - defaultName, - realParam, - ancestors, - value, - ), - ); - } else { - // ignore object values if not isList. - return false; - } - return true; - } - - private FlattenProperty(paramSchema: any, exampleValue: any) { - if (paramSchema?.type === 'array' && exampleValue instanceof Array) { - return exampleValue.map((x) => this.FlattenProperty(paramSchema?.elementType, x)); - } - if ( - ['object', 'dictionary'].indexOf(paramSchema?.type) >= 0 && - paramSchema?.properties && - typeof exampleValue === 'object' && - !(exampleValue instanceof Array) - ) { - const ret = deepCopy(exampleValue); - for (const subProperty of paramSchema?.properties) { - if (subProperty.flattenedNames && subProperty.flattenedNames.length > 0) { - let subValue = exampleValue; - let i = 0; - for (; i < subProperty.flattenedNames.length; i++) { - if (isNullOrUndefined(subValue)) break; - const k = subProperty.flattenedNames[i]; - const v = subValue[k]; - if (v === undefined) break; - subValue = v; - } - if (i === subProperty.flattenedNames.length) { - ret[subProperty?.language['cli'].cliKey] = subValue; - } - } - } - for (const subProperty of paramSchema?.properties) { - if (subProperty.flattenedNames && subProperty.flattenedNames.length > 0) { - delete ret[subProperty.flattenedNames[0]]; - } - } - for (const subProperty of paramSchema?.properties) { - const k = subProperty?.language['cli'].cliKey; - if (exampleValue && exampleValue[k]) { - exampleValue[k] = this.FlattenProperty(subProperty, exampleValue[k]); - } - } - return ret; - } - return deepCopy(exampleValue); - } - - private checkPathToProperty(methodParam: MethodParam, ancestors: string[]): boolean { - return ( - ancestors.length > 0 && - isEqualStringArray( - methodParam.value.pathToProperty.map((x) => x?.language?.['az']?.name), - ancestors.slice(1), - ) - ); - } - - private checkFlattenedNames(methodParam: MethodParam, ancestors: string[]): boolean { - const flattenedNames = methodParam.value.targetProperty.flattenedNames; - return ( - !isNullOrUndefined(flattenedNames) && - flattenedNames.length === ancestors.length && - isEqualStringArray( - methodParam.value.targetProperty.flattenedNames.slice(0, -1), - ancestors.slice(1), - ) - ); - } - - private matchMethodParam( - methodParamList: MethodParam[], - paramName: string, - ancestors: string[], - ): MethodParam[] { - const ret: MethodParam[] = []; - if (!paramName) return ret; - for (const methodParam of methodParamList) { - let serializedName = methodParam.value.targetProperty?.serializedName; - if (!serializedName) serializedName = methodParam.value.language['cli'].cliKey; - // let methodParam_key = methodParam.value.language['cli'].cliKey; - if (serializedName.toLowerCase() === paramName.toLowerCase()) { - if ( - !('pathToProperty' in methodParam.value) || - this.checkPathToProperty(methodParam, ancestors) || - this.checkFlattenedNames(methodParam, ancestors) - ) { - ret.push(methodParam); - } - } - } - return ret; - } - - public FlattenExampleParameter( - methodParamList: MethodParam[], - exampleParam: ExampleParam[], - name: string, - value: any, - ancestors: string[], - ) { - for (const methodParam of this.matchMethodParam(methodParamList, name, ancestors)) { - let polySubParam: MethodParam = null; - let netValue = - typeof value === 'object' && !isNullOrUndefined(value) ? deepCopy(value) : value; - let rawValue = deepCopy(netValue); - if (methodParam.value['isPolyOfSimple']) { - const keyToMatch = - methodParam.value.schema.discriminator?.property?.language?.cli?.cliKey; - if (keyToMatch) { - for (const methodParam of methodParamList) { - const polySubParamObj = methodParam.value; - if (polySubParamObj.schema.extensions) { - const valueToMatch = - polySubParamObj.schema.extensions['x-ms-discriminator-value']; - if (netValue[keyToMatch] === valueToMatch) { - polySubParam = methodParam; - delete netValue[keyToMatch]; - break; - } - } - } - } - } - if (polySubParam) { - netValue = this.FlattenProperty(polySubParam.value?.schema, netValue); - rawValue = this.FlattenProperty(polySubParam.value?.schema, rawValue); - } else { - netValue = this.FlattenProperty(methodParam.value?.schema, netValue); - rawValue = this.FlattenProperty(methodParam.value?.schema, rawValue); - } - if ( - 'pathToProperty' in methodParam.value && - ancestors.length - methodParam.value.pathToProperty.length === 1 - ) { - // if the method parameter has 'pathToProperty', check the path with example parameter full path. - if (this.checkPathToProperty(methodParam, ancestors)) { - // exampleParam.set(name, value); - this.AddExampleParameter( - methodParam, - exampleParam, - netValue, - polySubParam, - ancestors, - rawValue, - ); - return; - } - } else if ( - 'targetProperty' in methodParam.value && - 'flattenedNames' in methodParam.value.targetProperty && - ancestors.length - methodParam.value.targetProperty.flattenedNames.length === 0 && - ancestors.length > 0 - ) { - // if the method parameter has 'flattenedNames', check the names (except the last name) with example parameter full path. - if (this.checkFlattenedNames(methodParam, ancestors)) { - // exampleParam.set(name, value); - this.AddExampleParameter( - methodParam, - exampleParam, - netValue, - polySubParam, - ancestors, - rawValue, - ); - return; - } - } else if (ancestors.length === 0) { - // exampleParam.set(name, value); - if ( - this.AddExampleParameter( - methodParam, - exampleParam, - netValue, - polySubParam, - ancestors, - rawValue, - ) - ) - return; - } - } - - if (!isNullOrUndefined(value) && typeof value === 'object') { - for (const subName in value) { - this.FlattenExampleParameter( - methodParamList, - exampleParam, - subName, - value[subName], - ancestors.concat(name), - ); - } - } - } - - public ConvertToCliParameters( - exampleParams: ExampleParam[], - commandGroup: string, - ): ExampleParam[] { - const ret: ExampleParam[] = []; - for (const param of exampleParams) { - // Object.entries(exampleParams).forEach(() => { - let paramName = ToSnakeCase(param.name); - if (paramName.endsWith('_name')) { - if (paramName === 'resource_group_name') { - paramName = 'resource_group'; - } - } - paramName = paramName.split('_').join('-'); - ret.push( - new ExampleParam( - '--' + paramName, - param.value, - param.isJson, - param.keyValue, - param.keys, - param.defaultName, - param.methodParam, - param.ancestors, - param.rawValue, - ), - ); - } - return ret; - } - - private filterExampleByPoly(exampleObj: any, example: CommandExample): boolean { - function getPolyClass(model): string { - const cliKey = model.Method.language['cli'].cliKey; - if (cliKey) { - const names = cliKey.split('#'); - if (names && names.length > 1) { - return names[names.length - 1]; - } - } - return ''; - } - const valueToMatch = getPolyClass(this); - if (!valueToMatch) return true; - - function matchPolyClass(example: CommandExample, keyToMatch: string, valueToMatch: string) { - for (const param of example.Parameters) { - if ( - (('--' + keyToMatch).toLowerCase() === param.name.toLowerCase() || - ('--' + keyToMatch + '-').toLowerCase() === param.name.toLowerCase()) && - typeof param.value === 'string' - ) { - return valueToMatch.toLowerCase() === param.value.toLowerCase(); - } - } - return true; - } - - // check polymophism here - const originalOperation = this.Method_GetOriginalOperation; - if (!isNullOrUndefined(originalOperation)) { - if (this.SelectFirstMethodParameter()) { - do { - if ( - !isNullOrUndefined( - this.MethodParameter.extensions?.['cli-poly-as-resource-base-schema'], - ) - ) { - const originalSchema = this.MethodParameter.extensions?.[ - 'cli-poly-as-resource-base-schema' - ]; - const keyToMatch = (originalSchema as any).discriminator.property.language - .default.name; // type - if (!matchPolyClass(example, keyToMatch, valueToMatch)) { - return false; - } - } - } while (this.SelectNextMethodParameter()); - } - } - return true; - } - - public GetExamples(includeGenerated: boolean): CommandExample[] { - if ( - !isNullOrUndefined(this.Method_AzExamples) && - this.Method_AzExamples.length > 0 && - includeGenerated - ) { - return this.Method_AzExamples; - } - const examples: CommandExample[] = []; - if (this.Examples) { - Object.entries(this.Examples).forEach(([id, exampleObj]) => { - if (includeGenerated || !isGeneratedExampleId(id)) { - const example = this.CreateCommandExample(id, exampleObj); - if (!isNullOrUndefined(example)) { - examples.push(example); - if (this.Command_MethodName === 'show') { - this.CommandGroup_ShowExample = example; - } - } - } - }); - } - if (includeGenerated) this.Method_AzExamples = examples; - return examples; - } - - public GetExampleById(id: string, exampleObj: any): CommandExample { - let ret: CommandExample = undefined; - if (this.Examples) { - Object.entries(this.Examples).forEach(([_id, _exampleObj]) => { - if (!isNullOrUndefined(ret)) return; - if (!isNullOrUndefined(id) && id.toLowerCase() !== _id.toLowerCase()) return; - if (!isNullOrUndefined(exampleObj)) _exampleObj = exampleObj; - const example = this.CreateCommandExample(_id, _exampleObj); - if (!isNullOrUndefined(example)) ret = example; - }); - } - return ret; - } - - public CreateCommandExample(id: string, exampleObj: any): CommandExample { - function forUpdate(model: CodeModelCliImpl, exampleName: string): boolean { - const lowercase: string = exampleName.toLowerCase(); - return ( - lowercase.endsWith('_update') || - (model.ExampleAmount > 1 && - lowercase.indexOf('update') >= 0 && - lowercase.indexOf('create') < 0) - ); - } - - const example = new CommandExample(); - example.Method = this.Command_MethodName; - example.Command = this.Command_Name; - example.Id = `/${this.CommandGroup_Key}/${this.Method_HttpMethod}/${id}`; - example.Title = exampleObj.title || id; - example.Path = this.Method_Path; - example.HttpMethod = this.Method_HttpMethod; - example.ResourceClassName = this.CommandGroup_Key; - const params = this.GetExampleParameters(exampleObj); - example.Parameters = this.ConvertToCliParameters(params, this.CommandGroup_Key); - example.MethodResponses = this.Method.responses || []; - example.Method_IsLongRun = !!this.Method.extensions?.['x-ms-long-running-operation']; - example.ExampleObj = exampleObj; - if (this.Method_GetSplitOriginalOperation) { - // filter example by name for generic createorupdate - if (this.Command_MethodName.toLowerCase() === 'update' && !forUpdate(this, id)) { - return; - } - if (this.Command_MethodName.toLowerCase() !== 'update' && forUpdate(this, id)) { - return; - } - } - if (this.filterExampleByPoly(exampleObj, example)) { - for (let i = 0; i < example.Parameters.length; i++) { - if (this.isDiscriminator(example.Parameters[i].methodParam.value)) { - example.Parameters.splice(i, 1); - i--; - } - } - example.commandStringItems = this.GetExampleItems(example, false, undefined); - example.CommandString = example.commandStringItems.join(' '); - return example; - } - return undefined; - } - - public GetExampleChecks(example: CommandExample): string[] { - const ret: string[] = []; - if (!this.GenChecks) return ret; - let resourceObjectName = undefined; - for (const param of example.Parameters) { - if ( - example.ResourceClassName && - this.resourcePool.isResource(param.defaultName, param.rawValue) === - example.ResourceClassName - ) { - resourceObjectName = param.value; - } - } - - const resourceObject = this.resourcePool.findResource( - example.ResourceClassName, - resourceObjectName, - ObjectStatus.Created, - ); - if (resourceObject) { - ret.push(...resourceObject.getCheckers(this.resourcePool, example)); - } - ret.push(...this.resourcePool.getListCheckers(example)); - return ret; - } - - public GetExampleItems( - example: CommandExample, - isTest: boolean, - commandParams: any, - minimum = false, - ): string[] { - const parameters: string[] = []; - parameters.push('az ' + this.Command_Name); - - let hasRG = false; - let resourceObjectName; - for (const param of example.Parameters) { - if (minimum && !this.Parameter_IsRequiredOrCLIRequired(param.methodParam.value)) - continue; - let paramValue = param.value; - if (isTest || this.FormalizeNames) { - let replacedValue = this.resourcePool.addParamResource( - param.defaultName, - paramValue, - param.isJson, - param.keyValue, - isTest, - ); - if (replacedValue === paramValue) { - replacedValue = this.resourcePool.addEndpointResource( - paramValue, - param.isJson, - param.keyValue, - [], - [], - param, - isTest, - ); - } - paramValue = replacedValue; - param.replacedValue = replacedValue; - } - let slp = paramValue; - if (param.keyValue === KeyValueType.No) { - slp = ToJsonString(slp); - } - parameters.push(param.name + ' ' + slp); - - if (['--resource-group', '-g'].indexOf(param.name) >= 0) { - hasRG = true; - } - - if ( - example.ResourceClassName && - this.resourcePool.isResource(param.defaultName, param.rawValue) === - example.ResourceClassName - ) { - resourceObjectName = param.value; - } - } - - if ( - isTest && - !hasRG && - commandParams && - commandParams[this.Command_Name] && - commandParams[this.Command_Name].has('resourceGroupName') - ) { - parameters.push('-g ""'); - } - - if (isTest) { - const resourceObject = this.resourcePool.findResource( - example.ResourceClassName, - resourceObjectName, - undefined, - ); - if (resourceObject) { - const httpMethod = example.HttpMethod.toLowerCase(); - if (['put', 'post', 'patch'].indexOf(httpMethod) >= 0) { - if (httpMethod === 'post') { - resourceObject.exampleParams = []; - } - for (const param of example.Parameters) { - if ( - minimum && - !this.Parameter_IsRequiredOrCLIRequired(param.methodParam.value) - ) - continue; - resourceObject.addOrUpdateParam(param); - } - resourceObject.testStatus = ObjectStatus.Created; - } - if (httpMethod === 'delete') { - resourceObject.testStatus = ObjectStatus.Deleted; - } - } - } - - return parameters; - } - - public GetExampleWait(example: CommandExample): string[] { - const parameters: string[] = []; - let foundResource = false; - if ( - example.HttpMethod.toLowerCase() === 'put' && - example.Method_IsLongRun && - example.MethodResponses.length > 0 && - (example.MethodResponses[0].schema?.properties || []).find((property) => { - return property?.language?.['cli']?.cliKey === 'provisioningState'; - }) - ) { - const showExample = this.CommandGroup_ShowExample; - if (isNullOrUndefined(showExample)) return []; - let words = showExample.Command.split(' '); - words = words.slice(0, words.length - 1); - words.push('wait'); - parameters.push(`az ${words.join(' ')} --created`); - for (const param of example.Parameters) { - const paramKey = param.methodParam.value.language?.['cli']?.cliKey; - if ( - showExample.Parameters.some((showParam) => { - return ( - showParam.methodParam.value.language?.['cli']?.cliKey == - param.methodParam.value.language?.['cli']?.cliKey && - showParam.methodParam.value.language?.['default']?.cliKey == - param.methodParam.value.language?.['default']?.cliKey - ); - }) - ) { - let paramValue = param.value; - let replacedValue = this.resourcePool.addParamResource( - param.defaultName, - paramValue, - param.isJson, - param.keyValue, - ); - if (replacedValue === paramValue) { - replacedValue = this.resourcePool.addEndpointResource( - paramValue, - param.isJson, - param.keyValue, - [], - [], - param, - ); - } - paramValue = replacedValue; - let slp = paramValue; - if (param.keyValue === KeyValueType.No) { - slp = ToJsonString(slp); - } - parameters.push(param.name + ' ' + slp); - } - if ( - this.resourcePool.isResource(paramKey, param.rawValue) === - example.ResourceClassName - ) - foundResource = true; - } - } - return foundResource ? parameters : []; - } - - public GetPreparerEntities(): any[] { - return this.resourcePool.createPreparerEntities(); - } - - public GetSubscriptionKey(): string { - if (this.resourcePool.useSubscription) { - return ResourcePool.KEY_SUBSCRIPTIONID; - } else { - return null; - } - } - - public FindExampleById( - id: string, - commandParams: any, - examples: CommandExample[], - minimum = false, - step: TestStepExampleFileRestCall = undefined, - ): string[][] { - const ret: string[][] = []; - this.GetAllExamples( - id, - (example) => { - examples.push(example); - ret.push(this.GetExampleItems(example, true, commandParams, minimum)); - }, - step?.exampleTemplate, - ); - return ret; - } - - public FindExampleWaitById( - id: string, - step: TestStepExampleFileRestCall = undefined, - ): string[][] { - const ret: string[][] = []; - this.GetAllExamples( - id, - (example) => { - const waitCmd = this.GetExampleWait(example); - if (waitCmd.length > 0) ret.push(waitCmd); - }, - step?.exampleTemplate, - ); - return ret; - } - - public GatherInternalResource() { - const internalResources = {}; // resource_key --> list of resource languages - this.GetAllMethods(null, () => { - if (!(this.CommandGroup_Key in internalResources)) { - internalResources[this.CommandGroup_Key] = [this.CommandGroup_Key]; - } - // let commands = this.CommandGroup_Name.split(" "); - // let resourceName = commands[commands.length - 1] + "-name"; - const resourceName = this.CommandGroup_DefaultName + 'Name'; - if (internalResources[this.CommandGroup_Key].indexOf(resourceName) < 0) { - internalResources[this.CommandGroup_Key].push(resourceName); - } - }); - this.resourcePool.addResourcesInfo(internalResources); - - // find dependency relationships of internalResources - this.GetAllMethods(null, () => { - const dependResources = []; - const dependParameters = []; - - const examples = this.GetExamples(false); - // recognize depends by endpoint in examples - for (const example of examples) { - for (const param of example.Parameters) { - const resources = []; - this.resourcePool.addEndpointResource( - param.value, - param.isJson, - param.keyValue, - [], - resources, - param, - ); - for (const onResource of resources) { - if ( - onResource !== this.CommandGroup_Key && - dependResources.indexOf(onResource) < 0 - ) { - dependResources.push(onResource); - dependParameters.push(param.name); - } - } - this.resourcePool.addParamResource( - param.defaultName, - param.value, - param.isJson, - param.keyValue, - ); - } - } - - // recognize depends by parameter name' - const createdObjectNames = []; - const isCreateMehod = this.Method_HttpMethod === 'put'; - if (this.SelectFirstMethodParameter()) { - do { - if ( - this.MethodParameter.implementation === 'Method' && - !this.MethodParameter_IsFlattened && - this.MethodParameter?.schema?.type !== 'constant' - ) { - const paramName = this.MethodParameter.language['cli'].cliKey; - const onResource = this.resourcePool.isResource(paramName, undefined); - for (const example of examples) { - for (const param of example.Parameters) { - if ( - onResource && - onResource !== this.CommandGroup_Key && - dependResources.indexOf(onResource) < 0 - ) { - // the resource is a dependency only when it's a parameter in an example. - if ( - paramName === param.defaultName && - dependResources.indexOf(onResource) < 0 - ) { - dependResources.push(onResource); - dependParameters.push(paramName); - } - } - if ( - isCreateMehod && - onResource && - onResource === this.CommandGroup_Key && - createdObjectNames.indexOf(param.value) < 0 - ) { - createdObjectNames.push(param.value); - } - } - } - } - } while (this.SelectNextMethodParameter()); - } - - this.resourcePool.setResourceDepends( - this.CommandGroup_Key, - dependResources, - dependParameters, - createdObjectNames, - ); - }); - - if (isNullOrUndefined(this._defaultTestScenario)) { - const allExamples = this.GetAllExamples(); - this._defaultTestScenario = GenerateDefaultTestScenario(allExamples); - this._defaultTestScenario = GenerateDefaultTestScenarioByDependency( - allExamples, - this.resourcePool, - this._defaultTestScenario, - ); - this.SortExamplesByDependency(); - PrintTestScenario(this._defaultTestScenario); - } - - if (!this._configuredScenario && isNullOrUndefined(this._testScenario)) { - this._testScenario = GroupTestScenario( - this._defaultTestScenario, - this.Extension_NameUnderscored, - ); - } - - const commandParams = {}; - this.GetAllMethods(null, () => { - if (!commandParams[this.Command_Name]) commandParams[this.Command_Name] = new Set(); - if (this.SelectFirstMethodParameter()) { - do { - if ( - (this.MethodParameter.implementation === 'Method' || - (this.MethodParameter as any).polyBaseParam) && - !this.MethodParameter_IsFlattened && - this.MethodParameter?.schema?.type !== 'constant' - ) { - commandParams[this.Command_Name].add( - this.MethodParameter.language['cli'].cliKey, - ); - } - } while (this.SelectNextMethodParameter()); - } - }); - return commandParams; - } - - public SortExamplesByDependency() { - const dependOn = (exampleA: CommandExample, exampleB: CommandExample): boolean => { - // TODO: check dependency by object - return this.resourcePool.isDependResource( - exampleA.ResourceClassName, - exampleB.ResourceClassName, - ); - }; - - const isCreate = (example: CommandExample): boolean => { - return example.HttpMethod === 'put'; - }; - - const isDelete = (example: CommandExample): boolean => { - return example.HttpMethod === 'delete'; - }; - - // stable sort - const compare = (examplesA: CommandExample, examplesB: CommandExample): number => { - if (!examplesA || !examplesB) return 0; - - if (examplesA.ResourceClassName === examplesB.ResourceClassName) { - if (isCreate(examplesB) && !isCreate(examplesA)) { - return 1; - } else if (isDelete(examplesB) && !isDelete(examplesA)) { - return -1; - } else if (isCreate(examplesA) && !isCreate(examplesB)) { - return -1; - } else if (isDelete(examplesA) && !isDelete(examplesB)) { - return 1; - } else { - return examplesA.Id.localeCompare(examplesB.Id); - } - } else if (dependOn(examplesA, examplesB)) { - if (isCreate(examplesB)) { - return 1; - } else if (isDelete(examplesB)) { - return -1; - } else { - return 1; - } - } else if (dependOn(examplesB, examplesA)) { - if (isCreate(examplesA)) { - return -1; - } else if (isDelete(examplesA)) { - return 1; - } else { - return -1; - } - } - return examplesA.Id.localeCompare(examplesB.Id); - }; - - const scenarioExamples: Map = new Map(); - const commandExamples = this.GetAllExamples(); - for (let i = 0; i < this._defaultTestScenario.length; i++) { - for (const commandExample of commandExamples) { - if (this.matchExample(commandExample, this._defaultTestScenario[i].name)) { - scenarioExamples.set(this._defaultTestScenario[i].name, commandExample); - break; - } - } - } - - this._defaultTestScenario = MergeSort(this._defaultTestScenario, (exampleA, exampleB) => { - return compare( - scenarioExamples.get(exampleA.name), - scenarioExamples.get(exampleB.name), - ); - }); - } - - public GetAllMethods(commandGroup?: string, callback?: () => void): any[] { - let ret: []; - this.SelectFirstExtension(); - if (this.SelectFirstCommandGroup()) { - do { - // iterate all CommandGroups - if ( - commandGroup && - commandGroup.toLowerCase() !== this.CommandGroup_Key.toLowerCase() - ) - continue; - while (this.currentOperationIndex >= 0) { - // iterate all Commands - this.SelectFirstMethod(); - do { - if (callback) { - callback(); - } - } while (this.SelectNextMethod()); - this.SelectNextCommand(); - } - } while (this.SelectNextCommandGroup()); - } - return ret; - } - - private matchExample(example: CommandExample, id: string) { - if (!id) return false; - return ( - example.Id.toLowerCase() === id.toLowerCase() || - example.Id.toLowerCase().endsWith(`/${id.toLowerCase()}`) - ); - } - - public GetAllExamples( - id?: string, - callback?: (example) => void, - exampleTemplate?: any, - ): CommandExample[] { - const ret: CommandExample[] = []; - let found = false; - this.GetAllMethods(null, () => { - if (found) return; - let examples: CommandExample[]; - if (!isNullOrUndefined(exampleTemplate)) { - const example = this.GetExampleById(id, exampleTemplate); - if (isNullOrUndefined(example)) return; - examples = [example]; - } else { - examples = this.GetExamples(true); - } - for (const example of examples) { - if (id && !this.matchExample(example, id)) continue; - if (callback) { - callback(example); - } - if (ret.indexOf(example) > -1) { - continue; - } - ret.push(example); - if (id) { - found = true; - } - } - }); - return ret; - } - - public get CliCoreLib(): string { - if (isNullOrUndefined(AzConfiguration.getValue(CodeGenConstants.cliCoreLib))) { - return CodeGenConstants.DEFAULT_CLI_CORE_LIB; - } - return AzConfiguration.getValue(CodeGenConstants.cliCoreLib); - } - - public get AzureCliFolder(): string { - return AzConfiguration.getValue(CodeGenConstants.azureCliFolder); - } - - public get AzureCliExtFolder(): string { - return AzConfiguration.getValue(CodeGenConstants.azureCliExtFolder); - } - - public get AzextFolder(): string { - return AzConfiguration.getValue(CodeGenConstants.azextFolder); - } - - public get azOutputFolder(): string { - return AzConfiguration.getValue(CodeGenConstants.azOutputFolder); - } - - public get IsCliCore() { - return AzConfiguration.getValue(CodeGenConstants.isCliCore); - } - - public get minCliCoreVersion(): string { - return CodeGenConstants.minCliCoreVersion; - } - - public get SDK_NeedSDK() { - return AzConfiguration.getValue(CodeGenConstants.sdkNeeded); - } - - public get SDK_IsTrack1() { - return AzConfiguration.getValue(CodeGenConstants.sdkTrack1); - } - - public get SDK_NoFlatten() { - return AzConfiguration.getValue(CodeGenConstants.sdkNoFlatten); - } - - /* - This is trying to get all the model data by passing all the CodeModelTypes and InputProperties and dependencies, - The dependencies is used for describe how the result will look like. For example: In case of report.md, - we basically need all the commandGroups, all the commands, all the methods, all the methodParameters and all the azExamples. - and since the azExamples actually belongs to each methods i.e. the swagger operations, we need the result to be in the format of - extensions: [ - commandGroups : [ - commands: [ - methods: [ - methodParameters: [], - azExample: [], - ] - ] - ] - ] - Then the dependencies would look like - const dependencies = <[CodeModelTypes, CodeModelTypes][]>[ - ['extension', 'commandGroup'], - ['commandGroup', 'command'], - ['command', 'method'], - ['method', 'methodParameter'], - ['method', 'azExample'], - ]; - - Since we need different properties for each of the CodeModelType, we can define our requirements in InputProperties - to specify what kind of CodeModelType properties do we need for rendering, - and what's the order condition - and what's the filter condition - and what's the converter we need after we get the data. - Still take report as an example, - - const converter = new Map unknown>([ - [ - 'mapsTo', - function (item: string) { - if (item.endsWith('_')) { - item = item.substr(0, item.length - 1); - } - item = item.replace(/_/g, '-'); - return item; - }, - ], - ]); - - const inputProperties: Map = new Map< - CodeModelTypes, - RenderInput - >([ - ['extension', new RenderInput(['name'], { name: SortOrder.ASEC })], - ['commandGroup', new RenderInput(['name', 'cliKey'], { name: SortOrder.ASEC })], - ['command', new RenderInput(['name'])], - ['method', new RenderInput(['nameAz', 'cliKey'], { nameAz: SortOrder.ASEC })], - [ - 'methodParameter', - new RenderInput( - ['mapsTo', 'type', 'description', 'cliKey', 'namePython'], - {}, - [ - ['isFlattened', true], - ['type', SchemaType.Constant], - ['isPolyOfSimple', true], - ['isDiscriminator', true], - ], - converter, - ), - ], - ['azExample', new RenderInput(['commandStringItems'], {})], - ]); - - - This means we need extension => properties: name, sort by name - commandGroup => properties: name, cliKey, sort by name - command => properties: name, - method => properties: nameAz, cliKey, sort by nameAz - methodParameter => properties: mapsTo, type, description, cliKey, namePython, and filter those parameters that - isFlattened == true and methodParameter_type != constants, isPolyOfSimple != true, isDiscrminator != true - - and converter - - data = model.getModelData('extension', inputProperties, dependencies); - - */ - - public getModelData( - layer: CodeModelTypes, - inputProperties: Map, - dependencies: DataGraph, - ): unknown | any[] { - if ( - isNullOrUndefined(layer) || - isNullOrUndefined(dependencies) || - dependencies.length < 0 - ) { - return {}; - } - const type: CodeModelTypes = layer; - const Type = Capitalize(type); - const renderInput: RenderInput = inputProperties.get(type); - const sortBy = renderInput.sortBy; - const props = renderInput.properties; - const conditions = renderInput.conditions; - const converter = renderInput.converter; - const selector = renderInput.selector; - const data = {}; - data['has' + Type] = false; - data[Type + 's'] = []; - const items = []; - if (this['SelectFirst' + Type](...selector)) { - data['has' + Type] = true; - do { - let item = {}; - let hasFiltered = false; - if (!isNullOrUndefined(props) && Array.isArray(props) && props.length > 0) { - for (const prop of props) { - if (typeof this[Type + '_' + Capitalize(prop)] === 'function') { - item[prop] = this[Type + '_' + Capitalize(prop)](); - } else { - item[prop] = this[Type + '_' + Capitalize(prop)]; - } - } - for (const condition of conditions) { - if (this[Type + '_' + Capitalize(condition[0])] === condition[1]) { - hasFiltered = true; - break; - } - } - } - if (hasFiltered) { - continue; - } - - if (dependencies.length > 0) { - dependencies - .filter((d) => d[0] === layer) - .forEach((d) => { - const item2: any = this.getModelData( - d[1], - inputProperties, - dependencies, - ); - item = { ...item, ...item2 }; - }); - // const d = dependencies.shift(); - } - if (!isNullOrUndefined(converter)) { - item = converter(item); - } - items.push(item); - } while (this['SelectNext' + Type](...selector)); - if (items.length > 0 && sortBy.length > 0) { - items.sort(function (a, b) { - for (const sortKey in sortBy) { - if ( - a[Type + '_' + Capitalize(sortKey)] > - b[Type + '_' + Capitalize(sortKey)] - ) { - return sortBy[sortKey]; - } else if ( - a[Type + '_' + Capitalize(sortKey)] < - b[Type + '_' + Capitalize(sortKey)] - ) { - return 0 - sortBy[sortKey]; - } - } - return 0; - }); - } - data[Type + 's'] = items; - } - return data; - } - - public getArrayModelData( - layer: CodeModelTypes, - inputProperties: Map, - dependencies: DataGraph, - ): any[] { - const data = this.getModelData(layer, inputProperties, dependencies); - const allTypes = {}; - while (dependencies.length > 0) { - allTypes[dependencies[0][0]] = dependencies[0][1]; - dependencies.shift(); - } - let next = data[Capitalize(layer) + 's']; - delete data['has' + Capitalize(layer)]; - delete data[Capitalize(layer) + 's']; - const preItem = {}; - const traceItem = []; - traceItem.push([preItem, next, layer]); - const ret = []; - while (traceItem.length > 0) { - const front = traceItem.shift(); - next = front[1]; - const currentLayer = front[2]; - const nextLayer = allTypes[currentLayer]; - let mItem = front[0]; - for (const item of next) { - if (!isNullOrUndefined(nextLayer)) { - const mNext = item[Capitalize(nextLayer) + 's']; - delete item['has' + Capitalize(nextLayer)]; - delete item[Capitalize(nextLayer) + 's']; - mItem[currentLayer] = item; - traceItem.push([mItem, mNext, nextLayer]); - } else { - mItem = { ...mItem, ...item }; - ret.push(mItem); - } - } - } - return ret; - } - - /* - [ - { - name: '', - type: '', - extension: { - name: - } - } - ] - */ - public getAllCommandGroups() { - const inputProperties: Map = new Map< - CodeModelTypes, - RenderInput - >([ - ['extension', new RenderInput(['name'], { name: SortOrder.ASEC })], - ['commandGroup', new RenderInput([], { name: SortOrder.ASEC })], - ]); - - const dependencies = <[CodeModelTypes, CodeModelTypes][]>[['extension', 'commandGroup']]; - - return this.getModelData('extension', inputProperties, dependencies); - } - - public CreateCommandGroupModel() { - const commandGroups = this.getAllCommandGroups(); - } - - public CreateCommandModel() { - // - } - - public CreateParameterModel() { - // - } - - public CreateCliModule() { - // - } - - public getAllCommandGroupWithCallback(callback: () => void): void { - const commandGroupCall = () => { - if (this.SelectFirstCommandGroup()) { - do { - callback.bind(this)(); - } while (this.SelectNextCommandGroup()); - } - }; - commandGroupCall(); - } - - public getCommandsWithCallback(callback: () => void, needAll = true): void { - const commandCall = () => { - if (this.SelectFirstCommand()) { - do { - callback.bind(this)(); - } while (this.SelectNextCommand()); - } - }; - if (needAll) { - this.getAllCommandGroupWithCallback(commandCall); - } else { - commandCall(); - } - } - - public getMethodsWithCallback(callback: () => void, needAll = true): void { - const methodCall = () => { - if (this.SelectFirstMethod()) { - do { - callback.bind(this)(); - } while (this.SelectNextMethod()); - } - }; - if (needAll) { - this.getCommandsWithCallback(methodCall); - } else { - methodCall(); - } - } - - public getMethodParametersWithCallback(callback: () => void, needAll = true): void { - const methodParameterCall = () => { - if (this.SelectFirstMethodParameter()) { - do { - callback.bind(this)(); - } while (this.SelectNextMethodParameter()); - } - }; - if (needAll) { - this.getMethodsWithCallback(methodParameterCall); - } else { - methodParameterCall(); - } - } -} diff --git a/src/generate/azgenerator.ts b/src/generate/azgenerator.ts index 6ec52f08a..1e1276621 100644 --- a/src/generate/azgenerator.ts +++ b/src/generate/azgenerator.ts @@ -4,7 +4,7 @@ import { EOL } from 'os'; import * as path from 'path'; import { CodeGenConstants, PathConstants, AzConfiguration } from '../utils/models'; import { AzGeneratorFactory } from './generators/Factory'; -import { CodeModelCliImpl } from './CodeModelAzImpl'; +import { CodeModelCliImpl } from './codemodel/CodeModelAzImpl'; import { openInplaceGen, closeInplaceGen } from '../utils/inplace'; export async function processRequest(host: Host) { @@ -13,10 +13,14 @@ export async function processRequest(host: Host) { const session = await startSession(host, {}, codeModelSchema); const model = new CodeModelCliImpl(session); + const { configHandler, exampleHandler } = model.GetHandler(); if (model.SelectFirstExtension()) { do { - const azextpath = path.join(model.azOutputFolder, model.AzextFolder); + const azextpath = path.join( + configHandler.azOutputFolder, + configHandler.AzextFolder, + ); session.protectFiles(path.join(azextpath, PathConstants.manualFolder)); session.protectFiles( path.join( @@ -26,13 +30,15 @@ export async function processRequest(host: Host) { PathConstants.recordingFolder, ), ); - session.protectFiles(path.join(model.azOutputFolder, PathConstants.readmeFile)); + session.protectFiles( + path.join(configHandler.azOutputFolder, PathConstants.readmeFile), + ); } while (model.SelectNextExtension()); } openInplaceGen(); - await model.resourcePool.loadTestResources(); - model.GenerateTestInit(); + await exampleHandler.GetResourcePool().loadTestResources(); + exampleHandler.GenerateTestInit(); const generator = AzGeneratorFactory.createAzGenerator(model); await generator.generateAll(); const files = generator.files; diff --git a/src/generate/codemodel/AzExample.ts b/src/generate/codemodel/AzExample.ts new file mode 100644 index 000000000..c5d280d89 --- /dev/null +++ b/src/generate/codemodel/AzExample.ts @@ -0,0 +1,59 @@ +import { isGeneratedExampleId, ToMultiLine } from '../../utils/helper'; +import { CodeGenConstants } from '../../utils/models'; +import { CommandExample } from './Example'; +import { CodeModelCliImpl } from './CodeModelAzImpl'; +import { MethodModel } from './Method'; + +export interface AzExampleModel { + AzExample: CommandExample; + AzExample_CommandString: string; + AzExample_CommandStringItems: string[]; +} + +export class AzExampleModelImpl implements AzExampleModel { + private methodHandler: MethodModel; + constructor(public baseHandler: CodeModelCliImpl) { + const { methodHandler } = baseHandler.GetHandler(); + this.methodHandler = methodHandler; + } + public get AzExample(): CommandExample { + if ( + this.baseHandler.currentAzExampleIndex < 0 || + this.baseHandler.currentAzExampleIndex >= this.methodHandler.Method_AzExamples.length + ) { + return undefined; + } + return this.methodHandler.Method_AzExamples[this.baseHandler.currentAzExampleIndex]; + } + + public get AzExample_CommandString(): string { + return this.AzExample.CommandString; + } + + public get AzExample_Id(): string { + return this.AzExample.Id; + } + + public get AzExample_HttpMethod(): string { + return this.AzExample.HttpMethod; + } + + public get AzExample_CommandStringItems(): string[] { + const items = []; + ToMultiLine( + this.AzExample_CommandString, + items, + CodeGenConstants.PYLINT_MAX_CODE_LENGTH, + true, + ); + return items; + } + + public get AzExample_RawCommandStringItems(): string[] { + return this.AzExample.commandStringItems; + } + + public get AzExample_IsGenerated(): boolean { + return isGeneratedExampleId(this.AzExample?.Id); + } +} diff --git a/src/generate/codemodel/CodeModelAz.ts b/src/generate/codemodel/CodeModelAz.ts new file mode 100644 index 000000000..0d71ce74d --- /dev/null +++ b/src/generate/codemodel/CodeModelAz.ts @@ -0,0 +1,74 @@ +/* --------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *-------------------------------------------------------------------------------------------- */ + +import { Operation, OperationGroup, Parameter } from '@azure-tools/codemodel'; +import { CodeModelTypes, DataGraph, RenderInput } from '../../utils/models'; +import { ExtensionModel } from './Extension'; +import { CommandGroupModel } from './CommandGroup'; +import { CommandModel } from './Command'; +import { MethodModel } from './Method'; +import { MethodParameterModel } from './MethodParameter'; +import { ParameterModel } from './Parameter'; +import { SchemaModel } from './Schema'; +import { ConfigModel } from './Config'; +import { ExampleModel } from './Example'; +export class Handler { + public constructor( + public extensionHandler: ExtensionModel, + public commandGroupHandler: CommandGroupModel, + public commandHandler: CommandModel, + public methodHandler: MethodModel, + public methodParameterHandler: MethodParameterModel, + public parameterHandler: ParameterModel, + public schemaHandler: SchemaModel, + public configHandler: ConfigModel, + public exampleHandler: ExampleModel, + ) {} +} +export interface CodeModelAz { + init(): any; + SelectFirstExtension(): boolean; + SelectNextExtension(): boolean; + + isComplexSchema(type: string, param: any): boolean; + + SelectFirstCommandGroup(needRefer?: boolean): boolean; + SelectNextCommandGroup(needRefer?: boolean): boolean; + + SelectFirstCommand(): boolean; + SelectNextCommand(): boolean; + + SelectFirstMethod(): boolean; + SelectNextMethod(): boolean; + + // Method_SetAzExamples(examples: CommandExample[]): void; + Operation_IsHidden(op?: Operation): boolean; + + SelectFirstMethodParameter(containHidden?: boolean): boolean; + SelectNextMethodParameter(containHidden?: boolean): boolean; + EnterSubMethodParameters(param?: Parameter): boolean; + ExitSubMethodParameters(): boolean; + + MethodParameters: Array; + SubMethodParameter: Parameter; + GetModuleOperationName(group?: OperationGroup): string; + GetModuleOperationNamePython(): string; + GetModuleOperationNamePythonUpper(): string; + + // Python + PythonMgmtClient: string; + + SelectFirstExample(): boolean; + SelectNextExample(): boolean; + SelectFirstAzExample(): boolean; + SelectNextAzExample(): boolean; + getModelData( + layer: CodeModelTypes, + inputProperties: Map, + dependencies: DataGraph, + ); + GetActionData(): any[]; + GetHandler(): Handler; +} diff --git a/src/generate/codemodel/CodeModelAzImpl.ts b/src/generate/codemodel/CodeModelAzImpl.ts new file mode 100644 index 000000000..7ab1664d5 --- /dev/null +++ b/src/generate/codemodel/CodeModelAzImpl.ts @@ -0,0 +1,1758 @@ +/* --------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *-------------------------------------------------------------------------------------------- */ +import { Channel, Session } from '@autorest/extension-base'; +import { + CodeModel, + Operation, + OperationGroup, + Parameter, + Property, + Request, + Schema, + SchemaType, +} from '@azure-tools/codemodel'; +import { values } from '@azure-tools/linq'; +import { + Capitalize, + parseResourceId, + ToCamelCase, + ToSnakeCase, + changeCamelToDash, + ToSentence, + isNullOrUndefined, +} from '../../utils/helper'; +import { + CodeGenConstants, + EXCLUDED_PARAMS, + GenerationMode, + AzConfiguration, + CodeModelTypes, + RenderInput, + DataGraph, +} from '../../utils/models'; +import { CodeModelAz, Handler } from './CodeModelAz'; +import { ConfigModel, ConfigModelImpl } from './Config'; +import { ExtensionModel, ExtensionModelImpl } from './Extension'; +import { CommandGroupModel, CommandGroupModelImpl } from './CommandGroup'; +import { CommandModel, CommandModelImpl } from './Command'; +import { MethodModel, MethodModelImpl } from './Method'; +import { MethodParameterModel, MethodParameterModelImpl } from './MethodParameter'; +import { ParameterModel, ParameterModelImpl } from './Parameter'; +import { SchemaModel, SchemaModelImpl } from './Schema'; +import { AzExampleModel, AzExampleModelImpl } from './AzExample'; +import { ExampleModel, ExampleModelImpl } from './Example'; +class ActionParam { + public constructor( + public groupOpActionName: string, + public groupActionName: string, + public actionName: string, + public action: Parameter, + ) {} +} + +export class CodeModelCliImpl implements CodeModelAz { + codeModel: CodeModel; + options: any; + extensionName: string; + parentExtension: string; + currentOperationGroupIndex: number; + currentSubOperationGroupIndex: number; + currentOperationIndex: number; + currentParameterIndex: number; + currentExampleIndex: number; + currentAzExampleIndex: number; + preMethodIndex: number; + currentMethodIndex: number; + + suboptions: Property[]; + protected subOperationGroups: Operation[]; + submethodparameters: Parameter[]; + protected substack: Array<[Parameter[], number]>; + currentSubOptionIndex: number; + paramActionNameReference: Map; + protected allActions: Map; + _clientSubscriptionBound: boolean; + _clientBaseUrlBound: boolean; + _clientAuthenticationPolicy: string; + protected _generationMode: GenerationMode = GenerationMode.Full; + protected _outputPath: string; + configHandler: ConfigModel; + extensionHandler: ExtensionModel; + commandGroupHandler: CommandGroupModel; + commandHandler: CommandModel; + methodHandler: MethodModel; + methodParameterHandler: MethodParameterModel; + parameterHandler: ParameterModel; + schemaHandler: SchemaModel; + azExampleHandler: AzExampleModel; + exampleHandler: ExampleModel; + + init(): void { + this.options = AzConfiguration.getValue(CodeGenConstants.az); + this.extensionName = this.options.extensions; + this.parentExtension = this.options[CodeGenConstants.parentExtension]; + this.currentOperationGroupIndex = -1; + this.currentSubOperationGroupIndex = -1; + this.currentOperationIndex = -1; + this.currentParameterIndex = -1; + this.currentExampleIndex = -1; + this.currentAzExampleIndex = -1; + this.preMethodIndex = -1; + this.currentMethodIndex = -1; + this.suboptions = null; + this.currentSubOptionIndex = -1; + this.submethodparameters = null; + this.substack = new Array<[Parameter[], number]>(); + this._clientBaseUrlBound = this.options[CodeGenConstants.clientBaseUrlBound]; + this._clientSubscriptionBound = this.options[CodeGenConstants.clientSubscriptionBound]; + this._clientAuthenticationPolicy = this.options[ + CodeGenConstants.clientAuthenticationPolicy + ]; + // this.sortOperationByAzCommand(); + } + + public constructor(public session: Session) { + this.init(); + this.codeModel = session.model; + this.initHandler(); + this.dealingSimplePolymorphism(); + this.setParamAzUniqueNames(); + this.sortOperationByAzCommand(); + this.calcOptionRequiredByMethod(); + this.dealingParameterAlias(); + } + + private initHandler() { + this.configHandler = new ConfigModelImpl(this); + this.extensionHandler = new ExtensionModelImpl(this); + this.schemaHandler = new SchemaModelImpl(this); + this.commandGroupHandler = new CommandGroupModelImpl(this); + this.methodHandler = new MethodModelImpl(this); + this.azExampleHandler = new AzExampleModelImpl(this); + this.parameterHandler = new ParameterModelImpl(this); + this.commandHandler = new CommandModelImpl(this); + this.methodParameterHandler = new MethodParameterModelImpl(this); + this.exampleHandler = new ExampleModelImpl(this); + } + + private sortOperationByAzCommand() { + for (const [idx, operationGroup] of this.codeModel.operationGroups.entries()) { + operationGroup.operations.sort(function (a, b) { + function getOrder(op: string) { + if (op.indexOf(' ') > -1) { + op = op.split(' ').last; + } + const opOrder = ['list', 'show', 'create', 'update', 'delete']; + let order = opOrder.indexOf(op.toLowerCase()) + 1; + if (order === 0) { + order = opOrder.length + 1; + } + return order; + } + function requiredParamLength(parameters) { + let ret = 0; + for (let i = 0; i < parameters.length; ++i) { + if (parameters[i].required) ret++; + } + return ret; + } + const oa = getOrder(a.language['az'].name); + const ob = getOrder(b.language['az'].name); + if (oa < ob) { + return -1; + } else if (oa > ob) { + return 1; + } else { + const la = a.language['az'].name; + const lb = b.language['az'].name; + if (la !== lb) { + return la.localeCompare(lb); + } + const requiredLenA = requiredParamLength(a.parameters); + const requiredLenB = requiredParamLength(b.parameters); + if (requiredLenA !== requiredLenB) return requiredLenA > requiredLenB ? -1 : 1; + return a.parameters.length > b.parameters.length ? -1 : 1; + } + }); + this.codeModel.operationGroups[idx] = operationGroup; + } + } + + private calcOptionRequiredByMethod() { + if (this.SelectFirstCommandGroup()) { + do { + if (this.SelectFirstCommand()) { + do { + let paramTime = 0; + const paramRequired: Map = new Map(); + if (this.SelectFirstMethod()) { + paramTime++; + if (this.SelectFirstMethodParameter()) { + do { + if ( + !paramRequired.has( + this.methodParameterHandler.MethodParameter_Name, + ) + ) { + paramRequired.set( + this.methodParameterHandler.MethodParameter_Name, + this.methodParameterHandler.MethodParameter_IsRequired + ? 1 + : 0, + ); + } else if ( + this.methodParameterHandler.MethodParameter_IsRequired + ) { + paramRequired.set( + this.methodParameterHandler.MethodParameter_Name, + paramRequired.get( + this.methodParameterHandler.MethodParameter_Name, + ) + 1, + ); + } + } while (this.SelectNextMethodParameter()); + } + while (this.SelectNextMethod()) { + paramTime++; + if (this.SelectFirstMethodParameter()) { + do { + if ( + !paramRequired.has( + this.methodParameterHandler.MethodParameter_Name, + ) + ) { + paramRequired.set( + this.methodParameterHandler.MethodParameter_Name, + this.methodParameterHandler + .MethodParameter_IsRequired + ? 1 + : 0, + ); + } else if ( + this.methodParameterHandler.MethodParameter_IsRequired + ) { + paramRequired.set( + this.methodParameterHandler.MethodParameter_Name, + paramRequired.get( + this.methodParameterHandler + .MethodParameter_Name, + ) + 1, + ); + } + } while (this.SelectNextMethodParameter()); + } + } + } + if (this.SelectFirstMethod()) { + let idGroups = new Map(); + idGroups = parseResourceId(this.Request.protocol.http.path); + let hasName = false; + if (this.SelectFirstMethodParameter()) { + do { + const parameters = this.methodParameterHandler.MethodParameter; + const defaultName = parameters.language['cli'].cliKey; + const defaultToMatch = '{' + defaultName + '}'; + if (!isNullOrUndefined(idGroups)) { + for (const k of idGroups.entries()) { + if ( + k[1] === defaultToMatch && + defaultName !== 'resourceGroupName' + ) { + this.methodParameterHandler.MethodParameter.language[ + 'az' + ].id_part = k[0]; + } + } + } + if (parameters.language['cli'].required) { + this.methodParameterHandler.MethodParameter[ + 'RequiredByMethod' + ] = true; + } else { + this.methodParameterHandler.MethodParameter[ + 'RequiredByMethod' + ] = + paramRequired.get( + this.methodParameterHandler.MethodParameter_Name, + ) === paramTime; + } + if ( + this.methodParameterHandler.MethodParameter_MapsTo === + 'name' + ) { + hasName = true; + } + } while (this.SelectNextMethodParameter()); + if (hasName) { + this.methodHandler.Method['hasName'] = true; + } + } + while (this.SelectNextMethod()) { + let idGroups = new Map(); + idGroups = parseResourceId(this.Request.protocol.http.path); + let hasName = false; + if (this.SelectFirstMethodParameter()) { + do { + const parameters = this.methodParameterHandler + .MethodParameter; + const defaultName = parameters.language['cli'].cliKey; + const defaultToMatch = '{' + defaultName + '}'; + if (!isNullOrUndefined(idGroups)) { + for (const k of idGroups.entries()) { + if ( + k[1] === defaultToMatch && + defaultName !== 'resourceGroupName' + ) { + this.methodParameterHandler.MethodParameter.language[ + 'az' + ].id_part = k[0]; + } + } + } + if (parameters.language['cli'].required) { + this.methodParameterHandler.MethodParameter[ + 'RequiredByMethod' + ] = true; + } else { + this.methodParameterHandler.MethodParameter[ + 'RequiredByMethod' + ] = + paramRequired.get( + this.methodParameterHandler + .MethodParameter_Name, + ) === paramTime; + } + if ( + this.methodParameterHandler.MethodParameter_MapsTo === + 'name' + ) { + hasName = true; + } + } while (this.SelectNextMethodParameter()); + if (hasName) { + this.methodHandler.Method['hasName'] = true; + } + } + } + } + } while (this.SelectNextCommand()); + } + } while (this.SelectNextCommandGroup()); + } + } + + private dealingSimplePolymorphism() { + if (this.SelectFirstCommandGroup()) { + do { + if (this.SelectFirstCommand()) { + do { + if (this.SelectFirstMethod()) { + do { + if (this.SelectFirstMethodParameter()) { + do { + if ( + this.methodParameterHandler.MethodParameter_IsFlattened + ) { + continue; + } + if ( + this.methodParameterHandler + .MethodParameter_IsPolyOfSimple + ) { + const polyBaseParam = this.methodParameterHandler + .MethodParameter; + const allChildParam: Array = []; + for (const child of this.methodParameterHandler + .MethodParameter.schema['children'].all) { + const childParam = new Parameter( + child.language.default.name, + child.language.default.description, + child, + child.language, + ); + childParam.language = child.language; + if ( + !isNullOrUndefined(child.language['cli']?.alias) + ) { + if ( + isNullOrUndefined( + childParam.language['az'].alias, + ) + ) { + childParam.language['az'].alias = []; + } + if ( + typeof child.language['cli'].alias === + 'string' + ) { + if ( + EXCLUDED_PARAMS.indexOf( + child.language['cli'].alias, + ) > -1 + ) { + child.language['cli'].alias = + 'gen_' + + child.language['cli'].alias; + } + childParam.language['az'].alias.push( + changeCamelToDash( + child.language['cli'].alias, + ), + ); + } else if ( + Array.isArray(child.language['cli'].alias) + ) { + for (let alias of child.language['cli'] + .alias) { + if ( + EXCLUDED_PARAMS.indexOf(alias) > -1 + ) { + alias = 'gen_' + alias; + } + childParam.language['az'].alias.push( + changeCamelToDash(alias), + ); + } + } + } + childParam['polyBaseParam'] = polyBaseParam; + allChildParam.push(childParam); + } + const addResult = this.MethodParameters_AddPolySubClass( + this.methodParameterHandler.MethodParameter, + allChildParam, + ); + if (!addResult) { + this.session.message({ + Channel: Channel.Warning, + Text: + 'dealingSimplePolymorphisme error! baseClass: ' + + this.methodParameterHandler + .MethodParameter_MapsTo, + }); + } + } + } while (this.SelectNextMethodParameter()); + } + } while (this.SelectNextMethod()); + } + } while (this.SelectNextCommand()); + } + } while (this.SelectNextCommandGroup()); + } + } + + private setParamAzUniqueNames() { + this.paramActionNameReference = new Map(); + this.allActions = new Map(); + const nameActionReference: Map = new Map(); + const pythonReserveWord = ['all', 'id', 'format', 'type', 'filter']; + if (this.SelectFirstCommandGroup()) { + do { + if (this.SelectFirstCommand()) { + do { + const nameParamReference: Map = new Map< + string, + Parameter + >(); + if (this.SelectFirstMethod()) { + do { + if (this.SelectFirstMethodParameter()) { + do { + const paramName = this.methodParameterHandler + .MethodParameter_MapsTo; + const param = this.methodParameterHandler.MethodParameter; + const originParam = this.methodParameterHandler + .MethodParameter; + let flattenedNames = + param?.['targetProperty']?.flattenedNames; + if ( + isNullOrUndefined(flattenedNames) && + !isNullOrUndefined(param.language['cli'].flattenedNames) + ) { + flattenedNames = param.language['cli'].flattenedNames; + } + const mapName: Array = []; + let paramFlattenedName = this.parameterHandler.Parameter_MapsTo( + param, + ); + const names = this.methodHandler.Method_NameAz.split(' '); + if (flattenedNames && flattenedNames.length > 0) { + for (const item of flattenedNames) { + mapName.push(item); + } + mapName.pop(); + mapName.reverse(); + if ( + mapName[mapName.length - 1] === 'properties' || + mapName[mapName.length - 1] === 'parameters' + ) { + mapName.pop(); + } else if ( + names.length > 1 && + mapName[mapName.length - 1] === + names[0].replace(/-/g, '_') + ) { + mapName.pop(); + } + if (mapName.length > 0) { + const argGroupName = mapName + .reverse() + .map((item) => { + return ToSentence(item); + }) + .join(' '); + this.methodParameterHandler.MethodParameter.language[ + 'az' + ].arg_group = argGroupName; + } + paramFlattenedName = paramName; + } + if (names.length > 1) { + let subgroup: string = names[0]; + subgroup = subgroup.replace(/-/g, '_'); + if (paramFlattenedName.startsWith(subgroup)) { + paramFlattenedName = paramFlattenedName.substr( + subgroup.length + 1, + ); + } + } + if ( + nameParamReference.has(paramFlattenedName) && + nameParamReference.get(paramFlattenedName)[ + 'targetProperty' + ] !== param['targetPropert'] + ) { + let tmpName = paramFlattenedName; + const preParam = nameParamReference.get( + paramFlattenedName, + ); + const preFlattenedNames = + preParam?.['targetProperty']?.flattenedNames; + let preParamFlattenedName = this.parameterHandler.Parameter_MapsTo( + preParam, + ); + let preTmpName = preParamFlattenedName; + if (preFlattenedNames && preFlattenedNames.length > 0) { + preTmpName = preFlattenedNames + .map((pfn) => ToSnakeCase(pfn)) + .join('_'); + } + if (flattenedNames && flattenedNames.length > 0) { + tmpName = flattenedNames + .map((fn) => ToSnakeCase(fn)) + .join('_'); + } + if (preTmpName !== preParamFlattenedName) { + preParamFlattenedName = preTmpName; + } else if (tmpName !== paramFlattenedName) { + paramFlattenedName = tmpName; + } + if ( + pythonReserveWord.indexOf(paramFlattenedName) > -1 + ) { + paramFlattenedName += '_'; + } + if ( + pythonReserveWord.indexOf(preParamFlattenedName) > + -1 + ) { + preParamFlattenedName += '_'; + } + if (paramFlattenedName !== preParamFlattenedName) { + this.parameterHandler.Parameter_SetAzNameMapsTo( + preParamFlattenedName, + preParam, + ); + nameParamReference.set( + preParamFlattenedName, + preParam, + ); + this.parameterHandler.Parameter_SetAzNameMapsTo( + paramFlattenedName, + param, + ); + nameParamReference.set(paramName, param); + } else { + // if the full flattenedName within one command is the same but has two different reference. there's no way to split them. + this.session.message({ + Channel: Channel.Warning, + Text: + 'parameter ' + + paramFlattenedName + + ' has two different references but they have the same flattened name', + }); + } + } else { + // nameParamReference doesn't have the parameter + // or nameParamReference has the parameter and they are the same. + if ( + pythonReserveWord.indexOf(paramFlattenedName) > -1 + ) { + paramFlattenedName += '_'; + } + this.parameterHandler.Parameter_SetAzNameMapsTo( + paramFlattenedName, + param, + ); + nameParamReference.set(paramFlattenedName, param); + } + if ( + this.methodParameterHandler.MethodParameter_Name === + 'tags' + ) { + continue; + } + if (this.parameterHandler.Parameter_IsPolyOfSimple(param)) { + continue; + } + if ( + this.methodParameterHandler.MethodParameter_IsList && + this.methodParameterHandler + .MethodParameter_IsListOfSimple && + !this.methodParameterHandler + .MethodParameter_IsSimpleArray + ) { + const groupOpParamName: string = + 'Add' + + Capitalize( + ToCamelCase( + this.commandHandler.Command_FunctionName + + '_' + + this.methodParameterHandler + .MethodParameter_MapsTo, + ), + ); + const groupParamName: string = + 'Add' + + Capitalize( + ToCamelCase( + this.commandGroupHandler.CommandGroup_Key + + '_' + + this.methodParameterHandler + .MethodParameter_MapsTo, + ), + ); + const actionName: string = + 'Add' + + Capitalize( + ToCamelCase( + this.methodParameterHandler + .MethodParameter_MapsTo, + ), + ); + const action = new ActionParam( + groupOpParamName, + groupParamName, + actionName, + param, + ); + if ( + nameActionReference.has(actionName) && + nameActionReference.get(actionName).action + .schema !== originParam.schema + ) { + const preAction = nameActionReference.get( + actionName, + ); + nameActionReference.delete(actionName); + let preActionUniqueName = preAction.actionName; + let actionUniqueName = actionName; + if ( + preAction.groupActionName !== + action.groupActionName + ) { + actionUniqueName = action.groupActionName; + preActionUniqueName = preAction.groupActionName; + } else if ( + preAction.groupOpActionName !== + action.groupOpActionName + ) { + actionUniqueName = action.groupOpActionName; + preActionUniqueName = + preAction.groupOpActionName; + } + this.paramActionNameReference.set( + preAction.action.schema, + preActionUniqueName, + ); + this.allActions.set( + preAction.action, + preActionUniqueName, + ); + this.paramActionNameReference.set( + param.schema, + actionUniqueName, + ); + this.allActions.set(param, actionUniqueName); + nameActionReference.set( + preActionUniqueName, + preAction, + ); + nameActionReference.set(actionUniqueName, action); + } else if ( + !this.paramActionNameReference.has( + originParam.schema, + ) + ) { + nameActionReference.set(actionName, action); + this.paramActionNameReference.set( + param.schema, + actionName, + ); + this.allActions.set(param, actionName); + } + } + } while (this.SelectNextMethodParameter()); + } + } while (this.SelectNextMethod()); + } + } while (this.SelectNextCommand()); + } + } while (this.SelectNextCommandGroup()); + } + } + + private dealingParameterAlias() { + this.getMethodParametersWithCallback(() => { + const parameterName = this.methodParameterHandler.MethodParameter_MapsTo; + // this is to handle names like "format", "type", etc + if (parameterName.endsWith('_')) { + if ( + isNullOrUndefined( + this.methodParameterHandler.MethodParameter.language['az'].alias, + ) + ) { + this.methodParameterHandler.MethodParameter.language['az'].alias = []; + } + this.methodParameterHandler.MethodParameter.language['az'].alias.push( + parameterName.substr(0, parameterName.length - 1), + ); + } else if ( + parameterName.endsWith('name') && + !this.methodHandler.Method['hasName'] && + parameterName.replace(/_name$|_/g, '') === + this.commandGroupHandler.CommandGroup_DefaultName.toLowerCase() + ) { + if ( + isNullOrUndefined( + this.methodParameterHandler.MethodParameter.language['az'].alias, + ) || + this.methodParameterHandler.MethodParameter.language['az'].alias.length <= 0 + ) { + this.methodParameterHandler.MethodParameter.language['az'].alias = []; + this.methodParameterHandler.MethodParameter.language['az'].alias.push('name'); + this.methodParameterHandler.MethodParameter.language['az'].alias.push('n'); + this.methodParameterHandler.MethodParameter.language['az'].alias.push( + parameterName, + ); + } + } + }); + } + + public GetActionData() { + const actions = []; + SchemaType.Array; + this.allActions.forEach((actionName: string, param: Parameter) => { + if (actionName === 'AddEventGridDataConnection') { + param; + } + const action = { + actionName: actionName, + actionType: 'KeyValue', + }; + action.actionType = this.parameterHandler.Parameter_IsPositional(param) + ? 'Positional' + : action.actionType; + action.actionType = this.parameterHandler.Parameter_IsShorthandSyntax(param) + ? 'ShortHandSyntax' + : action.actionType; + action['mapsTo'] = this.parameterHandler.Parameter_MapsTo(param); + action['type'] = this.schemaHandler.Schema_Type(param.schema); + action['nameAz'] = this.parameterHandler.Parameter_NameAz(param); + if (action['type'] === SchemaType.Array) { + action['baseClass'] = '_AppendAction'; + } else { + action['baseClass'] = 'Action'; + } + action['subProperties'] = []; + action['subPropertiesMapsTo'] = []; + action['subPropertiesNamePython'] = []; + action['subPropertiesNameAz'] = []; + action['constants'] = {}; + const baseParam = param['polyBaseParam']; + const keyToMatch = baseParam?.schema?.discriminator?.property?.language.python?.name; + const valueToMatch = param.schema?.['discriminatorValue']; + const allSubParameters = []; + if (this.EnterSubMethodParameters(param) && this.SelectFirstMethodParameter(true)) { + do { + const tmpParam = this.SubMethodParameter; + allSubParameters.push(tmpParam); + const pythonName = this.parameterHandler.Parameter_NamePython(tmpParam); + const mapsTo = this.parameterHandler.Parameter_MapsTo(tmpParam); + const nameAz = this.parameterHandler.Parameter_NameAz(tmpParam); + const subType = this.parameterHandler.Parameter_Type(tmpParam); + if ( + this.parameterHandler.Parameter_Type(tmpParam) === SchemaType.Constant && + !isNullOrUndefined(tmpParam.schema['value']?.['value']) + ) { + action['constants'][ + `'${pythonName}'` + ] = `'${tmpParam.schema['value']['value']}'`; + } else if (tmpParam['readOnly']) { + continue; + } else if ( + keyToMatch === pythonName && + !isNullOrUndefined(keyToMatch) && + !isNullOrUndefined(valueToMatch) && + tmpParam['isDiscriminator'] + ) { + action['constants'][`'${keyToMatch}'`] = `'${valueToMatch}'`; + } else { + action['subProperties'].push({ + namePython: pythonName, + nameAz: nameAz, + type: subType, + }); + action['subPropertiesMapsTo'].push(mapsTo); + action['subPropertiesNamePython'].push(pythonName); + action['subPropertiesNameAz'].push(nameAz); + } + } while (this.SelectNextMethodParameter(true)); + if (action['actionType'] === 'Positional') { + const keys = this.parameterHandler.Parameter_PositionalKeys( + param, + allSubParameters, + ); + action['subPropertiesNamePython'] = keys; + } + } + SchemaType.Dictionary; + actions.push(action); + this.ExitSubMethodParameters(); + }); + return actions; + } + //= ================================================================================================================ + // Extension level information + // autorest.az will have support for multiple extensions from single swagger file. + // Following formats in readme.az.md shall be supported: + // + // For single extension: + // + // az: + // extensions: + // + // Multiple extensions: + // + // az: + // extensions: + // - + // - + // + // Multiple extensions with additional parameters: + // + // az: + // extensions: + // - name: + // something-else: value + // - name: + // something-else: value + // + // Initially single extension without additional parameters should be supported, however all formats should + // be handled correctly. + // + //= ================================================================================================================ + + public SelectFirstExtension(): boolean { + // support only one initially + return true; + } + + public SelectNextExtension(): boolean { + return false; + } + + //= ================================================================================================================ + // Command Groups + // + // This interface provides enumeration of command groups assigned to currently selected extension. + // Currently all the command groups should be assigned to default extension (first one on the list). + // Users will be able to assign command groups to specific extension via readme.az.md file. + // Specification will be updated accordingly. + //= ================================================================================================================ + + public SelectFirstCommandGroup(needRefer = false): boolean { + // just enumerate through command groups in code-model-v4 + if (this.codeModel.operationGroups.length > 0) { + this.currentOperationGroupIndex = 0; + if ( + this.commandGroupHandler.CommandGroup.language['cli'].hidden || + this.commandGroupHandler.CommandGroup.language['cli'].removed + ) { + if (needRefer && this.commandGroupHandler.CommandGroup_Referenced) { + return true; + } else if (this.SelectNextCommandGroup()) { + if (!this.SelectFirstCommand()) { + return this.SelectNextCommandGroup(); + } + return true; + } else { + return false; + } + } + if (needRefer && this.commandGroupHandler.CommandGroup_Referenced) { + return true; + } else if (!this.SelectFirstCommand()) { + return this.SelectNextCommandGroup(needRefer); + } + return true; + } else { + this.currentOperationGroupIndex = -1; + return false; + } + } + + public SelectNextCommandGroup(needRefer = false): boolean { + if (this.currentOperationGroupIndex < this.codeModel.operationGroups.length - 1) { + this.currentOperationGroupIndex++; + if ( + this.commandGroupHandler.CommandGroup.language['cli'].hidden || + this.commandGroupHandler.CommandGroup.language['cli'].removed + ) { + if (needRefer && this.commandGroupHandler.CommandGroup_Referenced) { + return true; + } else if (this.SelectNextCommandGroup()) { + if (!this.SelectFirstCommand()) { + return this.SelectNextCommandGroup(); + } + return true; + } else { + return false; + } + } + if (needRefer && this.commandGroupHandler.CommandGroup_Referenced) { + return true; + } else if (!this.SelectFirstCommand()) { + return this.SelectNextCommandGroup(needRefer); + } + return true; + } else { + this.currentOperationGroupIndex = -1; + return false; + } + } + + // ----------------------------------------------------------------------------------------------------------------- + // Commands + // + // This interface provides enumeration of commands in selected command group. + // Note that it doesn't map directly into operations from code-model-v4 + // Azure CLI usually provides following commands to operate on single resource: + // (1) "az create" -> PUT + // (2) "az update" -> PUT or PATCH + // (3) "az show" -> GET + // (4) "az list" -> GET + // (5) "az delete" -> DELETE + // (6) "az any-other-specific operation" -> POST or GET + // + // NOTE: It would be nice if the implementation enumerates commands in the sequence as above. + // + // Commands (1) - (5) represent basic CRUD operations and "create" / "update" / "show" / "list" / "delete" follow + // standard naming conventions in Azure CLI + // + // Commands (6) are custom and operation name should be used to generate command name. + // Note that some GET operations may be also custom operations (not "list"). + // This can be recognised by URL - it will be longer than "base" PUT URL. + // + // In all the cases except of (4) mapping of command to operation in code-model-v4 is one to one. + // In case (4) several operations shall be grouped into a single command called "list", for instance: + // "list", "list-by-resource-group", "list-by-something" + // + // In case (1) and (2) there may be seveal patterns. + // (A) single "create_or_update" (PUT) method + // (B) create_or_update (PUT) and "update" (PATCH) method + // (C) "create" (PUT) method and "update" (PATCH) method + // + // In case (A) single method will be mapped into 2 Azure CLI commands: + // "az create" -> create_or_update (PUT) + // "az update" -> create_or_update (PUT) + // as there's no separate "update" method available. + // + // In case (B) we have one to one mapping: + // "az create" -> create_or_update (PUT) + // "az update" -> update (PATCH) + // + // In case (C) we have one to one mapping as well: + // "az create" -> create (PUT) + // "az update" -> update (PATCH) + // ----------------------------------------------------------------------------------------------------------------- + + public SelectFirstCommand(): boolean { + // just enumerate through commands in command group + if (this.commandGroupHandler.CommandGroup.operations.length > 0) { + this.currentOperationIndex = 0; + const operation = this.commandHandler.Command; + this.preMethodIndex = this.currentOperationIndex; + let needNext = false; + if (this.Operation_IsHidden(operation)) { + needNext = true; + } + while ( + this.currentOperationIndex + 1 < + this.commandGroupHandler.CommandGroup.operations.length + ) { + const tmpOperation = this.commandGroupHandler.CommandGroup.operations[ + this.currentOperationIndex + 1 + ]; + if (tmpOperation.language['az'].command === operation.language['az'].command) { + this.currentOperationIndex++; + if (!this.Operation_IsHidden(tmpOperation)) { + needNext = false; + } + } else { + break; + } + } + if (needNext && !this.SelectNextCommand()) { + return false; + } + this.SelectFirstMethod(); + this.SelectFirstMethodParameter(); + return true; + } else { + this.currentOperationIndex = -1; + return false; + } + } + + public SelectNextCommand(): boolean { + if ( + this.currentOperationIndex < + this.commandGroupHandler.CommandGroup.operations.length - 1 + ) { + this.currentOperationIndex++; + this.preMethodIndex = this.currentOperationIndex; + const operation = this.commandHandler.Command; + let needNext = false; + if (this.Operation_IsHidden(operation)) { + needNext = true; + } + while ( + this.currentOperationIndex < + this.commandGroupHandler.CommandGroup.operations.length - 1 + ) { + const tmpOperation = this.commandGroupHandler.CommandGroup.operations[ + this.currentOperationIndex + 1 + ]; + if (operation.language['az'].command === tmpOperation.language['az'].command) { + this.currentOperationIndex++; + if (!this.Operation_IsHidden(tmpOperation)) { + needNext = false; + } + } else { + break; + } + } + if (needNext && !this.SelectNextCommand()) { + return false; + } + this.SelectFirstMethod(); + this.SelectFirstMethodParameter(); + return true; + } else { + this.currentOperationIndex = -1; + return false; + } + } + + public Operation_IsHidden(op: Operation = this.methodHandler.Method): boolean { + if ( + op.language['cli'].hidden || + op.language['cli'].removed || + op.language['cli']['cli-operation-splitted'] + ) { + return true; + } + return false; + } + + public formResourceType(config: string | undefined): string { + if (isNullOrUndefined(config) || config.startsWith('ResourceType.')) return config; + else return 'ResourceType.' + config; + } + + //= ================================================================================================================ + // Methods / Operations associated with the command. + // + // Usually there will be one to one relationship between command and method. + // However in one case described above ("az list"), several methods may be assigned with single + // command, for instance "list", "list-by-resource-group", "list-by-someting-else". + // list + // In case of "list" command all the GET operations associated with the resource should be enumerated here, + // except of GET operation that returns particular instance of a resource and is associated to "show" command. + // + // There is also additional requirement for sort order of returned methods. They should be sorted by number + // of arguments. Those with more arguments should be listed first. + //= ================================================================================================================ + + public SelectFirstMethod(): boolean { + if (this.currentOperationIndex >= this.preMethodIndex) { + this.currentMethodIndex = this.preMethodIndex; + const method = this.methodHandler.Method; + if (this.Operation_IsHidden(method)) { + if (!this.SelectNextMethod()) { + return false; + } + } + this.SelectFirstMethodParameter(); + return true; + } else { + this.currentMethodIndex = -1; + return false; + } + } + + public SelectNextMethod(): boolean { + if (this.currentMethodIndex < this.currentOperationIndex) { + this.currentMethodIndex++; + const method = this.methodHandler.Method; + if (this.Operation_IsHidden(method)) { + if (!this.SelectNextMethod()) { + return false; + } + } + this.SelectFirstMethodParameter(); + return true; + } else { + this.currentMethodIndex = -1; + return false; + } + } + + public get Request(): Request { + return this.methodHandler.Method.requests[0]; + } + + //= ================================================================================================================ + // Methods Parameters. + // + // This interface is designed to enumerate all parameters of the selected method and their mapping to Python SDK. + //= ================================================================================================================ + public SelectFirstMethodParameter(containHidden = false): boolean { + if (!isNullOrUndefined(this.submethodparameters)) { + this.currentSubOptionIndex = 0; + const parameter = this.submethodparameters[this.currentSubOptionIndex]; + if (this.parameterHandler.Parameter_IsHidden(parameter) && !containHidden) { + if (!this.SelectNextMethodParameter(containHidden)) { + return false; + } + } + return true; + } + if (this.MethodParameters.length > 0) { + this.currentParameterIndex = 0; + if ( + (this.methodParameterHandler.MethodParameter_IsHidden && !containHidden) || + this.codeModel.globalParameters.indexOf( + this.methodParameterHandler.MethodParameter, + ) > -1 + ) { + if (this.SelectNextMethodParameter(containHidden)) { + return true; + } else { + return false; + } + } + return true; + } else { + return false; + } + } + + public SelectNextMethodParameter(containHidden = false): boolean { + if (!isNullOrUndefined(this.submethodparameters)) { + this.currentSubOptionIndex++; + + if (this.currentSubOptionIndex >= this.submethodparameters.length) { + return false; + } + const parameter = this.submethodparameters[this.currentSubOptionIndex]; + if (this.parameterHandler.Parameter_IsHidden(parameter) && !containHidden) { + if (!this.SelectNextMethodParameter(containHidden)) { + return false; + } + } + return true; + } + if (this.currentParameterIndex < this.MethodParameters.length - 1) { + this.currentParameterIndex++; + if ( + (this.methodParameterHandler.MethodParameter_IsHidden && !containHidden) || + this.codeModel.globalParameters.indexOf( + this.methodParameterHandler.MethodParameter, + ) > -1 + ) { + if (this.SelectNextMethodParameter(containHidden)) { + return true; + } else { + return false; + } + } + return true; + } else { + return false; + } + } + + public EnterSubMethodParameters( + param: Parameter = this.methodParameterHandler.MethodParameter, + ): boolean { + const subParams = this.GetSubParameters(param); + if (isNullOrUndefined(subParams)) { + return false; + } else { + if (isNullOrUndefined(this.substack)) { + this.substack = new Array<[Parameter[], number]>(); + } + // reserve previous status + if (!isNullOrUndefined(this.submethodparameters)) { + this.substack.push([this.submethodparameters, this.currentSubOptionIndex]); + } + this.submethodparameters = subParams; + this.currentSubOptionIndex = 0; + return true; + } + } + + public GetSubParameters( + param: Parameter = this.methodParameterHandler.MethodParameter, + ): Parameter[] { + // this should only works for + // 1. objects with simple properties + // 2. or objects with arrays as properties but has simple element type + // 3. or arrays with simple element types + // 4. or arrays with object element types but has simple properties + if (!this.parameterHandler.Parameter_IsList(param)) { + return null; + } + if (!this.parameterHandler.Parameter_IsListOfSimple(param)) { + return null; + } + + let submethodparameters = []; + if ( + this.parameterHandler.Parameter_Type(param) === SchemaType.Array || + this.parameterHandler.Parameter_Type(param) === SchemaType.Dictionary + ) { + if (param.schema['elementType'].type === SchemaType.Object) { + if (!isNullOrUndefined(param.schema?.['elementType']?.properties)) { + submethodparameters = param.schema?.['elementType']?.properties; + } + for (const parent of values(param.schema?.['elementType']?.parents?.all)) { + if (isNullOrUndefined(parent['properties'])) { + continue; + } + submethodparameters = submethodparameters.concat(parent['properties']); + } + } + } else if (this.parameterHandler.Parameter_Type(param) === SchemaType.Object) { + if (!isNullOrUndefined(param.schema['properties'])) { + submethodparameters = param.schema['properties']; + } + for (const parent of values(param.schema?.['parents']?.all)) { + if (isNullOrUndefined(parent['properties'])) { + continue; + } + submethodparameters = submethodparameters.concat(parent['properties']); + } + } + if (submethodparameters.length === 0) { + return null; + } + return submethodparameters; + } + + public ExitSubMethodParameters(): boolean { + if (!isNullOrUndefined(this.submethodparameters)) { + if (this.substack.length > 0) { + const lastsub = this.substack.last; + this.submethodparameters = lastsub[0]; + this.currentSubOptionIndex = lastsub[1]; + this.substack.pop(); + } else { + this.submethodparameters = null; + this.currentSubOptionIndex = -1; + } + return true; + } + return false; + } + + public isComplexSchema(type: string, param: any): boolean { + if ( + type === SchemaType.Array || + type === SchemaType.Object || + type === SchemaType.Dictionary || + type === SchemaType.Any || + param?.language?.['cli']?.json === true + ) { + return true; + } else { + return false; + } + } + + public get MethodParameters(): Array { + if (isNullOrUndefined(this.Request) || isNullOrUndefined(this.Request.parameters)) { + return this.methodHandler.Method.parameters; + } + return this.methodHandler.Method.parameters.concat(this.Request.parameters); + } + + public MethodParameters_AddPolySubClass(oriParam: Parameter, params: Parameter[]): boolean { + if (isNullOrUndefined(params) || isNullOrUndefined(oriParam) || params.length <= 0) { + return false; + } + if (this.methodHandler.Method.parameters.indexOf(oriParam) > -1) { + this.methodHandler.Method.parameters.splice( + this.methodHandler.Method.parameters.indexOf(oriParam) + 1, + 0, + ...params, + ); + return true; + } + if (!isNullOrUndefined(this.Request) && !isNullOrUndefined(this.Request.parameters)) { + if (this.Request.parameters.indexOf(oriParam) > -1) { + this.Request.parameters.splice( + this.Request.parameters.indexOf(oriParam) + 1, + 0, + ...params, + ); + return true; + } + } + return false; + } + + public get SubMethodParameter(): Parameter { + if (!isNullOrUndefined(this.submethodparameters)) { + return this.submethodparameters[this.currentSubOptionIndex]; + } + return null; + } + + //= ================================================================================================================ + // Top Level Python Related Information + // + // Most of the information included here should be either produced by Python namer, or come from readme.az.md file. + // Detailed descriptions below. + //= ================================================================================================================ + + public GetModuleOperationName( + group: OperationGroup = this.commandGroupHandler.CommandGroup, + ): string { + return ToSnakeCase(group.language.default.name); + } + + public GetModuleOperationNamePython(): string { + if (this.commandGroupHandler.CommandGroup_CliKey === '') { + return this.codeModel.info['python_title']; + } + if ( + this.configHandler.SDK_IsTrack1 && + !isNullOrUndefined(this.commandGroupHandler.CommandGroup.language['cli']?.track1_name) + ) { + return this.commandGroupHandler.CommandGroup.language['cli']?.track1_name; + } + return this.commandGroupHandler.CommandGroup.language.python.name; + } + + public GetModuleOperationNamePythonUpper(): string { + if ( + this.configHandler.SDK_IsTrack1 && + !isNullOrUndefined( + this.commandGroupHandler.CommandGroup.language['cli']?.track1_class_name, + ) + ) { + return this.commandGroupHandler.CommandGroup.language['cli']?.track1_class_name; + } + return this.commandGroupHandler.CommandGroup.language.python.className; + } + + public get PythonMgmtClient(): string { + return this.codeModel.info['pascal_case_title']; + } + + //= ================================================================================================================ + // Example / Test Scenario related interface. + // + // This interface enumerates examples related to currently selected command. + // It should be implemented when example processor implementation is in place. + //= ================================================================================================================ + + public SelectFirstExample(): boolean { + if (this.methodHandler.Method.extensions === undefined) { + return false; + } + + const example = this.methodHandler.Method.extensions['x-ms-examples']; + if (example && example.length > 0) { + this.currentExampleIndex = 0; + return true; + } else { + this.currentExampleIndex = -1; + return false; + } + } + + public SelectNextExample(): boolean { + const example = this.methodHandler.Method.extensions['x-ms-examples']; + if (example && this.currentExampleIndex < example.length - 1) { + this.currentExampleIndex++; + return true; + } else { + this.currentExampleIndex = -1; + return false; + } + } + + public SelectFirstAzExample(): boolean { + if (this.methodHandler.Method.extensions === undefined) { + return false; + } + + const example = this.methodHandler.Method['az-examples']; + if (example && example.length > 0) { + this.currentAzExampleIndex = 0; + return true; + } else { + this.currentAzExampleIndex = -1; + return false; + } + } + + public SelectNextAzExample(): boolean { + const example = this.methodHandler.Method['az-examples']; + if (example && this.currentAzExampleIndex < example.length - 1) { + this.currentAzExampleIndex++; + return true; + } else { + this.currentAzExampleIndex = -1; + return false; + } + } + + public GetAllMethods(commandGroup?: string, callback?: () => void): any[] { + let ret: []; + this.SelectFirstExtension(); + if (this.SelectFirstCommandGroup()) { + do { + // iterate all CommandGroups + if ( + commandGroup && + commandGroup.toLowerCase() !== + this.commandGroupHandler.CommandGroup_Key.toLowerCase() + ) + continue; + while (this.currentOperationIndex >= 0) { + // iterate all Commands + this.SelectFirstMethod(); + do { + if (callback) { + callback(); + } + } while (this.SelectNextMethod()); + this.SelectNextCommand(); + } + } while (this.SelectNextCommandGroup()); + } + return ret; + } + + /* + This is trying to get all the model data by passing all the CodeModelTypes and InputProperties and dependencies, + The dependencies is used for describe how the result will look like. For example: In case of report.md, + we basically need all the commandGroups, all the commands, all the methods, all the methodParameters and all the azExamples. + and since the azExamples actually belongs to each methods i.e. the swagger operations, we need the result to be in the format of + extensions: [ + commandGroups : [ + commands: [ + methods: [ + methodParameters: [], + azExample: [], + ] + ] + ] + ] + Then the dependencies would look like + const dependencies = <[CodeModelTypes, CodeModelTypes][]>[ + ['extension', 'commandGroup'], + ['commandGroup', 'command'], + ['command', 'method'], + ['method', 'methodParameter'], + ['method', 'azExample'], + ]; + + Since we need different properties for each of the CodeModelType, we can define our requirements in InputProperties + to specify what kind of CodeModelType properties do we need for rendering, + and what's the order condition + and what's the filter condition + and what's the converter we need after we get the data. + Still take report as an example, + + const converter = new Map unknown>([ + [ + 'mapsTo', + function (item: string) { + if (item.endsWith('_')) { + item = item.substr(0, item.length - 1); + } + item = item.replace(/_/g, '-'); + return item; + }, + ], + ]); + + const inputProperties: Map = new Map< + CodeModelTypes, + RenderInput + >([ + ['extension', new RenderInput(['name'], { name: SortOrder.ASEC })], + ['commandGroup', new RenderInput(['name', 'cliKey'], { name: SortOrder.ASEC })], + ['command', new RenderInput(['name'])], + ['method', new RenderInput(['nameAz', 'cliKey'], { nameAz: SortOrder.ASEC })], + [ + 'methodParameter', + new RenderInput( + ['mapsTo', 'type', 'description', 'cliKey', 'namePython'], + {}, + [ + ['isFlattened', true], + ['type', SchemaType.Constant], + ['isPolyOfSimple', true], + ['isDiscriminator', true], + ], + converter, + ), + ], + ['azExample', new RenderInput(['commandStringItems'], {})], + ]); + + + This means we need extension => properties: name, sort by name + commandGroup => properties: name, cliKey, sort by name + command => properties: name, + method => properties: nameAz, cliKey, sort by nameAz + methodParameter => properties: mapsTo, type, description, cliKey, namePython, and filter those parameters that + isFlattened == true and methodParameter_type != constants, isPolyOfSimple != true, isDiscrminator != true + + and converter + + data = model.getModelData('extension', inputProperties, dependencies); + + */ + + public getModelData( + layer: CodeModelTypes, + inputProperties: Map, + dependencies: DataGraph, + ): unknown | any[] { + if ( + isNullOrUndefined(layer) || + isNullOrUndefined(dependencies) || + dependencies.length < 0 + ) { + return {}; + } + const type: CodeModelTypes = layer; + const handler = type + 'Handler'; + const Type = Capitalize(type); + const renderInput: RenderInput = inputProperties.get(type); + const sortBy = renderInput.sortBy; + const props = renderInput.properties; + const conditions = renderInput.conditions; + const converter = renderInput.converter; + const selector = renderInput.selector; + const data = {}; + data['has' + Type] = false; + data[Type + 's'] = []; + const items = []; + if (this['SelectFirst' + Type](...selector)) { + data['has' + Type] = true; + do { + let item = {}; + let hasFiltered = false; + if (!isNullOrUndefined(props) && Array.isArray(props) && props.length > 0) { + for (const prop of props) { + if (typeof this[handler][Type + '_' + Capitalize(prop)] === 'function') { + item[prop] = this[handler][Type + '_' + Capitalize(prop)](); + } else { + item[prop] = this[handler][Type + '_' + Capitalize(prop)]; + } + } + for (const condition of conditions) { + if (this[handler][Type + '_' + Capitalize(condition[0])] === condition[1]) { + hasFiltered = true; + break; + } + } + } + if (hasFiltered) { + continue; + } + + if (dependencies.length > 0) { + dependencies + .filter((d) => d[0] === layer) + .forEach((d) => { + const item2: any = this.getModelData( + d[1], + inputProperties, + dependencies, + ); + item = { ...item, ...item2 }; + }); + // const d = dependencies.shift(); + } + if (!isNullOrUndefined(converter)) { + item = converter(item); + } + items.push(item); + } while (this['SelectNext' + Type](...selector)); + if (items.length > 0 && sortBy.length > 0) { + items.sort(function (a, b) { + for (const sortKey in sortBy) { + if ( + a[Type + '_' + Capitalize(sortKey)] > + b[Type + '_' + Capitalize(sortKey)] + ) { + return sortBy[sortKey]; + } else if ( + a[Type + '_' + Capitalize(sortKey)] < + b[Type + '_' + Capitalize(sortKey)] + ) { + return 0 - sortBy[sortKey]; + } + } + return 0; + }); + } + data[Type + 's'] = items; + } + return data; + } + + public getArrayModelData( + layer: CodeModelTypes, + inputProperties: Map, + dependencies: DataGraph, + ): any[] { + const data = this.getModelData(layer, inputProperties, dependencies); + const allTypes = {}; + while (dependencies.length > 0) { + allTypes[dependencies[0][0]] = dependencies[0][1]; + dependencies.shift(); + } + let next = data[Capitalize(layer) + 's']; + delete data['has' + Capitalize(layer)]; + delete data[Capitalize(layer) + 's']; + const preItem = {}; + const traceItem = []; + traceItem.push([preItem, next, layer]); + const ret = []; + while (traceItem.length > 0) { + const front = traceItem.shift(); + next = front[1]; + const currentLayer = front[2]; + const nextLayer = allTypes[currentLayer]; + let mItem = front[0]; + for (const item of next) { + if (!isNullOrUndefined(nextLayer)) { + const mNext = item[Capitalize(nextLayer) + 's']; + delete item['has' + Capitalize(nextLayer)]; + delete item[Capitalize(nextLayer) + 's']; + mItem[currentLayer] = item; + traceItem.push([mItem, mNext, nextLayer]); + } else { + mItem = { ...mItem, ...item }; + ret.push(mItem); + } + } + } + return ret; + } + + public getAllCommandGroupWithCallback(callback: () => void): void { + const commandGroupCall = () => { + if (this.SelectFirstCommandGroup()) { + do { + callback.bind(this)(); + } while (this.SelectNextCommandGroup()); + } + }; + commandGroupCall(); + } + + public getCommandsWithCallback(callback: () => void, needAll = true): void { + const commandCall = () => { + if (this.SelectFirstCommand()) { + do { + callback.bind(this)(); + } while (this.SelectNextCommand()); + } + }; + if (needAll) { + this.getAllCommandGroupWithCallback(commandCall); + } else { + commandCall(); + } + } + + public getMethodsWithCallback(callback: () => void, needAll = true): void { + const methodCall = () => { + if (this.SelectFirstMethod()) { + do { + callback.bind(this)(); + } while (this.SelectNextMethod()); + } + }; + if (needAll) { + this.getCommandsWithCallback(methodCall); + } else { + methodCall(); + } + } + + public getMethodParametersWithCallback(callback: () => void, needAll = true): void { + const methodParameterCall = () => { + if (this.SelectFirstMethodParameter()) { + do { + callback.bind(this)(); + } while (this.SelectNextMethodParameter()); + } + }; + if (needAll) { + this.getMethodsWithCallback(methodParameterCall); + } else { + methodParameterCall(); + } + } + + public GetHandler(): Handler { + return new Handler( + this.extensionHandler, + this.commandGroupHandler, + this.commandHandler, + this.methodHandler, + this.methodParameterHandler, + this.parameterHandler, + this.schemaHandler, + this.configHandler, + this.exampleHandler, + ); + } +} diff --git a/src/generate/codemodel/Command.ts b/src/generate/codemodel/Command.ts new file mode 100644 index 000000000..43daff867 --- /dev/null +++ b/src/generate/codemodel/Command.ts @@ -0,0 +1,180 @@ +import { Operation, OperationGroup, Parameter } from '@azure-tools/codemodel'; +import { isNullOrUndefined } from '../../utils/helper'; +import { CliCommandType } from '../../utils/models'; +import { CodeModelCliImpl } from './CodeModelAzImpl'; +import { CommandGroupModel } from './CommandGroup'; +import { ParameterModel } from './Parameter'; + +export interface CommandModel { + Command: Operation; + Command_Name: string; + Command_MethodName: string; + Command_FunctionName: string; + Command_GetOriginalOperation: any; + Command_OriginalCommandGroup: OperationGroup; + Command_ClientFactoryName: string; + Command_NeedGeneric: boolean; + Command_MaxApi: string; + Command_MinApi: string; + Command_ResourceType: string | undefined; + Command_GenericSetterParameter(Operation): Parameter; + + Command_Help: string; + Command_IsLongRun: boolean; + Command_SubGroupName: string; + Command_Mode: string; + Command_Type: string; + Command_GenericSetterArgName: string; + Command_Features: Record; + Command_Imports: Record; +} + +export class CommandModelImpl implements CommandModel { + private commandGroupHandler: CommandGroupModel; + private parameterHandler: ParameterModel; + + constructor(public baseModel: CodeModelCliImpl) { + const { commandGroupHandler, parameterHandler } = baseModel.GetHandler(); + this.commandGroupHandler = commandGroupHandler; + this.parameterHandler = parameterHandler; + } + + public get Command(): Operation { + if ( + this.baseModel.currentOperationIndex < 0 || + this.baseModel.currentOperationIndex >= + this.commandGroupHandler.CommandGroup.operations.length + ) { + return undefined; + } + return this.commandGroupHandler.CommandGroup.operations[ + this.baseModel.currentOperationIndex + ]; + } + + public get Command_FunctionName(): string { + return this.Command_Name.replace(/( |-)/g, '_'); + } + + public get Command_Name(): string { + return this.Command.language['az'].command; + } + + public get Command_MethodName(): string { + return this.Command.language['az'].name; + } + + public Command_GenericSetterParameter(op: Operation = this.Command): Parameter { + if (isNullOrUndefined(op)) { + return null; + } + return op['genericSetterParam']; + } + + public get Command_Help(): string { + return this.Command.language['az'].description.replace(/\n/g, ' ').replace(/"/g, '\\\\"'); + } + + public get Command_GetOriginalOperation(): any { + const polyOriginal = this.Command.extensions?.['cli-poly-as-resource-original-operation']; + if ( + !isNullOrUndefined(polyOriginal) && + !isNullOrUndefined(polyOriginal.extensions?.['cli-split-operation-original-operation']) + ) { + const splitOriginal = + polyOriginal.extensions?.['cli-split-operation-original-operation']; + return splitOriginal; + } + const splittedOriginal = this.Command.extensions?.[ + 'cli-split-operation-original-operation' + ]; + if (!isNullOrUndefined(splittedOriginal)) { + return splittedOriginal; + } + return polyOriginal; + } + + public get Command_OriginalCommandGroup(): OperationGroup { + if (!isNullOrUndefined(this.Command.language?.['az']?.['originalOperationGroup'])) { + return this.Command.language?.['az']?.['originalOperationGroup']; + } + return undefined; + } + + public get Command_ClientFactoryName(): string { + if (!isNullOrUndefined(this.Command_OriginalCommandGroup)) { + return this.commandGroupHandler.CommandGroup_ClientFactoryName( + this.Command_OriginalCommandGroup, + ); + } + return undefined; + } + + public get Command_NeedGeneric(): boolean { + if ( + this.Command.language['az'].isSplitUpdate && + this.commandGroupHandler.CommandGroup_HasShowCommand && + !isNullOrUndefined( + this.Command_GenericSetterParameter(this.Command_GetOriginalOperation), + ) + ) { + return true; + } + return false; + } + + public get Command_IsLongRun(): boolean { + return !!this.Command.extensions?.['x-ms-long-running-operation']; + } + + public get Command_SubGroupName(): string { + const subCommandGroupName = this.Command.language['az'].subCommandGroup; + return isNullOrUndefined(subCommandGroupName) ? '' : subCommandGroupName; + } + + public get Command_Mode(): string { + if (isNullOrUndefined(this.Command?.language?.['cli']?.extensionMode)) { + return this.commandGroupHandler.CommandGroup_Mode; + } + return this.Command?.language?.['cli']?.extensionMode; + } + + public get Command_Type(): string { + if (this.Command_MethodName === 'show') { + return CliCommandType.CUSTOM_SHOW_COMMAND; + } else if (this.Command_NeedGeneric) { + if (!isNullOrUndefined(this.Command_GenericSetterArgName)) { + return CliCommandType.GENERIC_UPDATE_COMMAND; + } + } + return CliCommandType.CUSTOM_COMMAND; + } + + public get Command_GenericSetterArgName(): string { + const genericParam = this.Command_GenericSetterParameter(this.Command_GetOriginalOperation); + if (isNullOrUndefined(genericParam)) { + return undefined; + } + return this.parameterHandler.Parameter_NamePython(genericParam); + } + + public get Command_MaxApi(): string { + return this.Command.language['cli']?.['max-api']; + } + + public get Command_MinApi(): string { + return this.Command.language['cli']?.['min-api']; + } + + public get Command_ResourceType(): string | undefined { + return this.baseModel.formResourceType(this.Command.language['cli']?.['resource-type']); + } + + public get Command_Features(): Record { + return this.Command.language['az']['features']; + } + + public get Command_Imports(): Record { + return this.Command.language['az']['imports']; + } +} diff --git a/src/generate/codemodel/CommandGroup.ts b/src/generate/codemodel/CommandGroup.ts new file mode 100644 index 000000000..1873767f9 --- /dev/null +++ b/src/generate/codemodel/CommandGroup.ts @@ -0,0 +1,172 @@ +import { EnglishPluralizationService } from '@azure-tools/codegen'; +import { OperationGroup } from '@azure-tools/codemodel'; +import { changeCamelToDash, isNullOrUndefined } from '../../utils/helper'; +import { ExtensionMode } from '../../utils/models'; +import { CodeModelCliImpl } from './CodeModelAzImpl'; +import { ConfigModel } from './Config'; +import { CommandExample } from './Example'; +import { ExtensionModel } from './Extension'; + +export interface CommandGroupModel { + CommandGroup: OperationGroup; + CommandGroup_Name: string; + CommandGroup_Help: string; + CommandGroup_DefaultName: string; + CommandGroup_Key: string; + CommandGroup_HasShowCommand: boolean; + CommandGroup_HasCommand: boolean; + CommandGroup_CliKey: string; + CommandGroup_MaxApi: string; + CommandGroup_MinApi: string; + CommandGroup_ResourceType: string | undefined; + CommandGroup_Mode: string; + CommandGroup_ClientFactoryName(group?: OperationGroup): string; + CommandGroup_OperationTmplName: string; + CommandGroup_CustomCommandTypeName(group?: OperationGroup): string; + CommandGroup_Referenced: boolean; + CommandGroup_ShowExample: CommandExample; + CommandGroup_Features: Record; + CommandGroup_Imports: Record; +} + +export class CommandGroupModelImpl implements CommandGroupModel { + private extensionHandler: ExtensionModel; + private configHandler: ConfigModel; + constructor(public baseHandler: CodeModelCliImpl) { + const { extensionHandler, configHandler } = baseHandler.GetHandler(); + this.extensionHandler = extensionHandler; + this.configHandler = configHandler; + } + public get CommandGroup(): OperationGroup { + if ( + this.baseHandler.currentOperationGroupIndex < 0 || + this.baseHandler.currentOperationGroupIndex >= + this.baseHandler.codeModel.operationGroups.length + ) { + return undefined; + } + return this.baseHandler.codeModel.operationGroups[ + this.baseHandler.currentOperationGroupIndex + ]; + } + + public get CommandGroup_Name(): string { + return this.CommandGroup.language['az'].command; + } + + public get CommandGroup_Help(): string { + const groupDescription = this.CommandGroup.language['az']?.['description']; + if (!isNullOrUndefined(groupDescription) && groupDescription !== '') { + return groupDescription; + } + const extensionPart = this.extensionHandler.Extension_Name.replace(/-/g, ' '); + const groupPart = changeCamelToDash(this.CommandGroup.language['az']?.name)?.replace( + /-/g, + ' ', + ); + if (groupPart === '') { + return ''; + } + if (extensionPart !== groupPart) { + return 'Manage ' + groupPart + ' with ' + extensionPart; + } else { + return 'Manage ' + groupPart; + } + } + + public get CommandGroup_ShowExample(): CommandExample { + return this.CommandGroup?.['az-show-example']; + } + + public set CommandGroup_ShowExample(example: CommandExample) { + if (this.CommandGroup) this.CommandGroup['az-show-example'] = example; + } + + public get CommandGroup_Key(): string { + return this.CommandGroup.$key || this.CommandGroup_Name; + } + + public get CommandGroup_HasShowCommand(): boolean { + return this.CommandGroup.language['az'].hasShowCommand; + } + + public get CommandGroup_HasCommand(): boolean { + return this.baseHandler.SelectFirstCommand(); + } + + public get CommandGroup_Referenced(): boolean { + return this.CommandGroup.language['az']['referenced']; + } + + public get CommandGroup_DefaultName(): string { + const eps = new EnglishPluralizationService(); + return eps.singularize(this.CommandGroup.language['cli'].cliKey); + } + + public get CommandGroup_MaxApi(): string { + return this.CommandGroup.language['cli']?.['max-api']; + } + + public get CommandGroup_MinApi(): string { + return this.CommandGroup.language['cli']?.['min-api']; + } + + public get CommandGroup_ResourceType(): string | undefined { + return this.baseHandler.formResourceType( + this.CommandGroup.language['cli']?.['resource-type'], + ); + } + + public get CommandGroup_CliKey(): string { + return this.CommandGroup.language['cli']?.cliKey; + } + + public get CommandGroup_Mode(): string { + if (isNullOrUndefined(this.CommandGroup?.language?.['cli']?.extensionMode)) { + if ( + this.configHandler.IsCliCore && + this.extensionHandler.Extension_Mode === ExtensionMode.Stable + ) { + return ExtensionMode.Experimental; + } + return this.extensionHandler.Extension_Mode; + } + return this.CommandGroup?.language?.['cli']?.extensionMode; + } + + public CommandGroup_ClientFactoryName(group: OperationGroup = this.CommandGroup): string { + const cfName: string = + 'cf_' + + (this.baseHandler.GetModuleOperationName(group) !== '' + ? this.baseHandler.GetModuleOperationName(group) + : this.extensionHandler.Extension_NameUnderscored + '_cl'); + return cfName; + } + + public get CommandGroup_OperationTmplName(): string { + const operationTmpl = + this.configHandler.GetPythonNamespace() + + '.operations._' + + this.baseHandler.GetModuleOperationNamePython() + + '_operations#' + + this.baseHandler.GetModuleOperationNamePythonUpper() + + '.{}'; + return operationTmpl; + } + + public CommandGroup_CustomCommandTypeName(group: OperationGroup = this.CommandGroup): string { + const customName = + this.extensionHandler.Extension_NameUnderscored + + '_' + + this.baseHandler.GetModuleOperationName(group); + return customName; + } + + public get CommandGroup_Features(): Record { + return this.CommandGroup.language['az']['features']; + } + + public get CommandGroup_Imports(): Record { + return this.CommandGroup.language['az']['imports']; + } +} diff --git a/src/generate/codemodel/Config.ts b/src/generate/codemodel/Config.ts new file mode 100644 index 000000000..e33880b0f --- /dev/null +++ b/src/generate/codemodel/Config.ts @@ -0,0 +1,119 @@ +import { isNullOrUndefined } from '../../utils/helper'; +import { AzConfiguration, CodeGenConstants, GenerationMode } from '../../utils/models'; +import { CodeModelCliImpl } from './CodeModelAzImpl'; + +export interface ConfigModel { + CliGenerationMode: GenerationMode; + AzextFolder: string; + CliCoreLib: string; + IsCliCore: boolean; + minCliCoreVersion: string; + SDK_NeedSDK: boolean; + SDK_IsTrack1: boolean; + SDK_NoFlatten: boolean; + AzureCliFolder: string; + AzureCliExtFolder: string; + azOutputFolder: string; + ResourceType: string | undefined; + GetPythonNamespace(): string; + GetPythonPackageName(): string; + RandomizeNames: boolean; + FormalizeNames: boolean; + GetTestUniqueResource: boolean; + GenChecks: boolean; + + // readme config + GenMinTest: boolean; +} + +export class ConfigModelImpl implements ConfigModel { + constructor(public baseHandler: CodeModelCliImpl) {} + public get CliGenerationMode(): GenerationMode { + return AzConfiguration.getValue(CodeGenConstants.generationMode); + } + + public get CliCoreLib(): string { + if (isNullOrUndefined(AzConfiguration.getValue(CodeGenConstants.cliCoreLib))) { + return CodeGenConstants.DEFAULT_CLI_CORE_LIB; + } + return AzConfiguration.getValue(CodeGenConstants.cliCoreLib); + } + + public get AzureCliFolder(): string { + return AzConfiguration.getValue(CodeGenConstants.azureCliFolder); + } + + public get AzureCliExtFolder(): string { + return AzConfiguration.getValue(CodeGenConstants.azureCliExtFolder); + } + + public get AzextFolder(): string { + return AzConfiguration.getValue(CodeGenConstants.azextFolder); + } + + public get azOutputFolder(): string { + return AzConfiguration.getValue(CodeGenConstants.azOutputFolder); + } + + public get IsCliCore() { + return AzConfiguration.getValue(CodeGenConstants.isCliCore); + } + + public get minCliCoreVersion(): string { + return CodeGenConstants.minCliCoreVersion; + } + + public get SDK_NeedSDK() { + return AzConfiguration.getValue(CodeGenConstants.sdkNeeded); + } + + public get SDK_IsTrack1() { + return AzConfiguration.getValue(CodeGenConstants.sdkTrack1); + } + + public get SDK_NoFlatten() { + return AzConfiguration.getValue(CodeGenConstants.sdkNoFlatten); + } + + public get ResourceType(): string | undefined { + return this.baseHandler.formResourceType(this.baseHandler.options?.['resource-type']); + } + + public get GenChecks(): boolean { + const disableChecks = this.baseHandler.options?.['disable-checks']; + if (disableChecks) return false; + return true; + } + + public get GetTestUniqueResource(): boolean { + const ret = this.baseHandler.options?.[CodeGenConstants.testUniqueResource]; + if (ret) return true; + return false; + } + + public get GenMinTest(): boolean { + const genMinTest = this.baseHandler.options?.['gen-min-test']; + if (genMinTest) return true; + return false; + } + + public GetPythonNamespace(): string { + return AzConfiguration.getValue(CodeGenConstants.pythonNamespace); + } + + public GetPythonPackageName(): string { + return this.baseHandler.options['package-name']; + } + + public get RandomizeNames(): boolean { + const randomizeNames = this.baseHandler.options?.['randomize-names']; + if (randomizeNames) return true; + return false; + } + + public get FormalizeNames(): boolean { + const formalizeNames = this.baseHandler.options?.['formalize-names']; + if (formalizeNames) return true; + return false; + } +} diff --git a/src/generate/codemodel/Example.ts b/src/generate/codemodel/Example.ts new file mode 100644 index 000000000..e712d7c87 --- /dev/null +++ b/src/generate/codemodel/Example.ts @@ -0,0 +1,1458 @@ +import { + deepCopy, + getGitStatus, + isEqualStringArray, + isGeneratedExampleId, + isNullOrUndefined, + MergeSort, + ToJsonString, + ToSnakeCase, +} from '../../utils/helper'; +import { + azOptions, + GenerateDefaultTestScenario, + GenerateDefaultTestScenarioByDependency, + PrintTestScenario, + ResourcePool, + ObjectStatus, + GroupTestScenario, + LoadPreparesConfig, +} from '../renders/tests/ScenarioTool'; +import { TestStepExampleFileRestCall } from 'oav/dist/lib/testScenario/testResourceTypes'; +import { CodeModelCliImpl } from './CodeModelAzImpl'; +import { CommandModel } from './Command'; +import { CommandGroupModel } from './CommandGroup'; +import { ConfigModel } from './Config'; +import { ExtensionModel } from './Extension'; +import { MethodModel } from './Method'; +import { MethodParameterModel } from './MethodParameter'; +import { ParameterModel } from './Parameter'; +import { AzConfiguration, CodeGenConstants } from '../../utils/models'; +import { readFile } from '@azure-tools/async-io'; +import * as process from 'process'; +import * as path from 'path'; +import { Property } from '@azure-tools/codemodel'; + +export class MethodParam { + public value: any; + public isList: boolean; + public isSimpleListOrArray: boolean; + public submethodparameters: Property[]; + public inBody: boolean; + public constructor(value, isList, isSimpleListOrArray, submethodparameters, inBody) { + this.value = value; + this.isList = isList; + this.isSimpleListOrArray = isSimpleListOrArray; + this.submethodparameters = submethodparameters; + this.inBody = inBody; + } +} + +export enum KeyValueType { + No, + Classic, + PositionalKey, + ShorthandSyntax, + SimpleArray, +} + +export class ExampleParam { + name: string; + value: any; + isJson: boolean; + keyValue: KeyValueType; + keys: string[]; + defaultName: string; + methodParam: MethodParam; + ancestors: string[]; + replacedValue: any; + rawValue: any; + public constructor( + name: string, + value: any, + isJson: boolean, + keyValue: KeyValueType, + keys: string[], + defaultName: string, + methodParam: MethodParam, + ancestors: string[], + rawValue: any, + ) { + this.name = name; + this.value = value; + this.isJson = isJson; + this.keyValue = keyValue; + this.keys = keys; + this.defaultName = defaultName; + this.methodParam = methodParam; + this.ancestors = ancestors; + this.rawValue = rawValue; + } +} + +export class CommandExample { + // this should be "create", "update", "list", "show", or custom name + public Method: string; + public Command: string; + public Id: string; + public Title: string; + public Parameters: ExampleParam[]; + // public MethodName: string; + public Path: string; + public ResourceClassName: string; + public HttpMethod: string; // Get, Post, Put ... + public MethodResponses: any[]; + public Method_IsLongRun: boolean; + public MethodParams: MethodParam[]; + public ExampleObj: any; + public commandStringItems: string[]; + public CommandString: string; +} + +export interface ExampleModel { + GetExamples(includeGenerated: boolean): CommandExample[]; + GetExampleWait(example: CommandExample): string[]; + GetSubscriptionKey(): string; + GetPreparerEntities(): any[]; + GatherInternalResource(); + FindExampleWaitById(id: string, step?: TestStepExampleFileRestCall): string[][]; + GetExampleItems(example: CommandExample, isTest: boolean, commandParams: any): string[]; + GetExampleChecks(example: CommandExample): string[]; + + GetMetaData(): { [key: string]: any }; + GetResourcePool(): ResourcePool; + FindExampleById( + id: string, + commandParams: any, + examples: any[], + minimum: boolean, + step?: TestStepExampleFileRestCall, + ): string[][]; + GenerateTestInit(): void; + Example_TestScenario: any; + Example_DefaultTestScenario: any; + ExampleAmount: number; +} + +export class ExampleModelImpl implements ExampleModel { + private commandGroupHandler: CommandGroupModel; + private methodHandler: MethodModel; + private methodParameterHandler: MethodParameterModel; + private parameterHandler: ParameterModel; + private commandHandler: CommandModel; + private configHandler: ConfigModel; + private extensionHandler: ExtensionModel; + protected resourcePool: ResourcePool; + _testScenario: any; + _configuredScenario: boolean; + _defaultTestScenario: any[]; + protected _useOptions: string[]; + protected _parentOptions: any; + constructor(public baseHandler: CodeModelCliImpl) { + const { + commandGroupHandler, + commandHandler, + methodHandler, + methodParameterHandler, + parameterHandler, + configHandler, + extensionHandler, + } = baseHandler.GetHandler(); + this.commandGroupHandler = commandGroupHandler; + this.methodHandler = methodHandler; + this.methodParameterHandler = methodParameterHandler; + this.parameterHandler = parameterHandler; + this.configHandler = configHandler; + this.extensionHandler = extensionHandler; + this.commandHandler = commandHandler; + Object.assign(azOptions, this.baseHandler.options); + this.resourcePool = new ResourcePool(); + this._parentOptions = AzConfiguration.getValue(CodeGenConstants.parents); + this._useOptions = AzConfiguration.getValue(CodeGenConstants.use); + LoadPreparesConfig(this.baseHandler.options[CodeGenConstants.preparers]); + } + public get Examples(): unknown { + const extensions = this.baseHandler.methodHandler.Method.extensions; + return extensions && 'x-ms-examples' in extensions ? extensions['x-ms-examples'] : {}; + } + + public get ExampleAmount(): number { + return Object.keys(this.Examples).length; + } + + public GetResourcePool(): ResourcePool { + return this.resourcePool; + } + + public get ConfiguredScenario(): boolean { + // judge test-scenario whether have value + return this._configuredScenario; + } + + public get Example_TestScenario(): any { + return this._testScenario; + } + + public get Example_DefaultTestScenario(): any { + return this._defaultTestScenario; + } + + public async GetMetaData(): Promise<{ [key: string]: any }> { + function getSwaggerFolder(parentsOptions: { [key: string]: any }) { + for (const k in parentsOptions) { + const v: string = parentsOptions[k]; + if ( + k.endsWith('.json') && + typeof v === 'string' && + v.startsWith('file:///') && + v.indexOf('specification') > 0 + ) { + const p = v.indexOf('specification'); + if (process.platform.toLowerCase().startsWith('win')) { + return v.slice('file:///'.length, p - 1); + } + return v.slice('file:///'.length - 1, p - 1); + } + } + return undefined; + } + const ret = {}; + ret['--use'] = this._useOptions; + + const swaggerFolder = getSwaggerFolder(this._parentOptions); + if (swaggerFolder) { + ret['swagger git status'] = getGitStatus(swaggerFolder).split('\n'); + } + + const azpkg = path.join(__dirname, '..', '..', '..', '..', 'package.json'); + const pjson = JSON.parse(await readFile(azpkg)); + ret['package info'] = `${pjson.name} ${pjson.version}`; + return ret; + } + + public GenerateTestInit(): void { + if (this.GetResourcePool().hasTestResourceScenario) { + this._testScenario = GroupTestScenario( + this.GetResourcePool().generateTestScenario(), + this.extensionHandler.Extension_NameUnderscored, + ); + this._configuredScenario = true; + } else if (this.baseHandler.codeModel['test-scenario']) { + this._testScenario = GroupTestScenario( + this.baseHandler.codeModel['test-scenario'], + this.extensionHandler.Extension_NameUnderscored, + ); + this._configuredScenario = true; + } else { + this._testScenario = undefined; + this._configuredScenario = false; + } + this.GatherInternalResource(); + this.GetAllExamples(); + } + /** + * Gets method parameters dict + * @returns method parameters dict : key is parameter name, value is the parameter schema + */ + public GetMethodParametersList(): MethodParam[] { + const methodParamList: MethodParam[] = []; + + if (this.baseHandler.SelectFirstMethodParameter()) { + do { + if ( + (this.methodParameterHandler.MethodParameter.implementation === 'Method' || + this.methodParameterHandler.MethodParameter['polyBaseParam']) && + !this.methodParameterHandler.MethodParameter_IsFlattened && + this.methodParameterHandler.MethodParameter?.schema?.type !== 'constant' + ) { + let submethodparameters = null; + if (this.baseHandler.EnterSubMethodParameters()) { + submethodparameters = this.baseHandler.submethodparameters; + this.baseHandler.ExitSubMethodParameters(); + } + methodParamList.push( + new MethodParam( + this.methodParameterHandler.MethodParameter, + this.parameterHandler.Parameter_IsList( + this.methodParameterHandler.MethodParameter, + ), + this.methodParameterHandler.MethodParameter_IsListOfSimple || + this.methodParameterHandler.MethodParameter_IsSimpleArray, + submethodparameters, + this.baseHandler.currentParameterIndex >= + this.methodHandler.Method.parameters.length, + ), + ); + } + } while (this.baseHandler.SelectNextMethodParameter()); + } + return methodParamList; + } + + public GetExampleParameters(exampleObj): ExampleParam[] { + const parameters: ExampleParam[] = []; + const methodParamList: MethodParam[] = this.GetMethodParametersList(); + Object.entries(exampleObj.parameters).forEach(([paramName, paramValue]) => { + this.FlattenExampleParameter(methodParamList, parameters, paramName, paramValue, []); + }); + return parameters; + } + + private isDiscriminator(param: any): boolean { + return this.commandHandler.Command_GetOriginalOperation && + param?.targetProperty?.isDiscriminator + ? true + : false; + } + + private AddExampleParameter( + methodParam: MethodParam, + exampleParam: ExampleParam[], + value: any, + polySubParam: MethodParam, + ancestors: string[], + rawValue: any, + ): boolean { + if (isNullOrUndefined(methodParam)) return false; + let isList: boolean = methodParam.isList; + let isSimpleListOrArray: boolean = methodParam.isSimpleListOrArray; + let defaultName: string = methodParam.value.language['cli'].cliKey; + let name: string = this.parameterHandler.Parameter_MapsTo(methodParam.value); + if ( + !isNullOrUndefined(methodParam.value.language?.['az']?.alias) && + Array.isArray(methodParam.value.language['az'].alias) && + methodParam.value.language['az'].alias.length > 0 + ) { + name = methodParam.value.language['az'].alias[0]; + } + let realParam = methodParam; + if (polySubParam) { + isList = polySubParam.isList; + isSimpleListOrArray = polySubParam.isSimpleListOrArray; + defaultName = polySubParam.value.language['cli'].cliKey; + name = this.parameterHandler.Parameter_MapsTo(polySubParam.value); + if ( + !isNullOrUndefined(polySubParam.value.language?.['az']?.alias) && + Array.isArray(polySubParam.value.language['az'].alias) && + polySubParam.value.language['az'].alias.length > 0 + ) { + name = polySubParam.value.language['az'].alias[0]; + } + realParam = polySubParam; + } + + function toActionString( + model: CodeModelCliImpl, + dict, + seperator = ' ', + initKeys = undefined, + ): [string, string[]] { + let ret = ''; + let keys: string[] = []; + if (!isNullOrUndefined(initKeys)) { + keys = initKeys; + } + for (const k in dict) { + let cliName = null; + for (const param of [methodParam, polySubParam]) { + if (param?.submethodparameters) { + for (const submethodProperty of param.submethodparameters) { + if ( + submethodProperty.language['cli'].cliKey.toLowerCase() === + k.toLowerCase() + ) { + cliName = model.parameterHandler.Parameter_NameAz( + submethodProperty, + ); + } + } + } + } + if (!cliName) { + // If no submethodparameters, keep all KEYs as the origin name + // This is for type of schema.Dictionary + cliName = k; + } + if (dict[k] instanceof Array) { + for (const v of dict[k]) { + if (ret.length > 0) { + ret += seperator; + } + ret += `${cliName}=${ToJsonString(v)}`; + } + } else { + if (ret.length > 0) { + ret += seperator; + } + const v = ToJsonString(dict[k]); + // if (v.startsWith("\"")) { + // v = v.substr(1, v.length-2); + // } + ret += `${cliName}=${v}`; + } + if (!keys.includes(cliName)) keys.push(cliName); + } + return [ret, keys]; + } + + let handled = false; + if (isList) { + if (isSimpleListOrArray) { + let keys = []; + let ret = ''; + if (value instanceof Array) { + // spread list + handled = true; + if (this.parameterHandler.Parameter_IsShorthandSyntax(realParam.value)) { + for (let i = 0; i < value.length; i++) { + let instanceString: string; + [instanceString, keys] = toActionString( + this.baseHandler, + value[i], + ',', + keys, + ); + instanceString = instanceString.trim(); + if (ret.length > 0 && instanceString.length > 0) ret += ' '; + ret += instanceString; + } + exampleParam.push( + new ExampleParam( + name, + ret, + false, + KeyValueType.ShorthandSyntax, + keys, + defaultName, + realParam, + ancestors, + value, + ), + ); + } else if (this.parameterHandler.Parameter_IsSimpleArray(realParam.value)) { + if (value.length > 0) { + // use value only when it's lenght > 0 + for (let i = 0; i < value.length; i++) { + ret += ToJsonString(value[i]) + ' '; + } + ret = ret.trim(); + exampleParam.push( + new ExampleParam( + name, + ret, + false, + KeyValueType.SimpleArray, + [], + defaultName, + realParam, + ancestors, + value, + ), + ); + } + } else { + for (let i = 0; i < value.length; i++) { + this.AddExampleParameter( + methodParam, + exampleParam, + value[i], + polySubParam, + ancestors, + rawValue[i], + ); + } + } + } else if (typeof rawValue === 'object') { + // KEY=VALUE form + handled = true; + if (this.parameterHandler.Parameter_IsPositional(realParam.value)) { + keys = this.parameterHandler.Parameter_PositionalKeys( + realParam.value, + realParam.submethodparameters, + ); + for (const k of keys) { + ret += ' '; + FIND_PARAM: for (const param of [polySubParam, methodParam]) { + if (param?.submethodparameters) { + for (const subMethodParam of param.submethodparameters) { + if ( + this.parameterHandler.Parameter_NamePython( + subMethodParam, + ) === k + ) { + ret += ToJsonString( + rawValue[subMethodParam.language['cli'].cliKey], + ); + break FIND_PARAM; + } + } + } + } + } + } + ret = ret.trim(); + if (ret.trim().length > 0) { + exampleParam.push( + new ExampleParam( + name, + ret, + false, + KeyValueType.PositionalKey, + keys, + defaultName, + realParam, + ancestors, + value, + ), + ); + } else { + /// ///////// + [ret, keys] = toActionString(this.baseHandler, value); + if (ret.length > 0) { + exampleParam.push( + new ExampleParam( + name, + ret, + false, + KeyValueType.Classic, + keys, + defaultName, + realParam, + ancestors, + value, + ), + ); + } + } + } + } + if (!handled) { + if (typeof value === 'string') { + exampleParam.push( + new ExampleParam( + name, + value, + false, + KeyValueType.No, + [], + defaultName, + realParam, + ancestors, + value, + ), + ); + } else { + // JSON form + exampleParam.push( + new ExampleParam( + name, + JSON.stringify(value) + .split(/[\r\n]+/) + .join(''), + true, + KeyValueType.No, + [], + defaultName, + realParam, + ancestors, + value, + ), + ); + } + } + } else if (typeof value !== 'object') { + exampleParam.push( + new ExampleParam( + name, + value, + false, + KeyValueType.No, + [], + defaultName, + realParam, + ancestors, + value, + ), + ); + } else { + // ignore object values if not isList. + return false; + } + return true; + } + + private FlattenProperty(paramSchema: any, exampleValue: any) { + if (paramSchema?.type === 'array' && exampleValue instanceof Array) { + return exampleValue.map((x) => this.FlattenProperty(paramSchema?.elementType, x)); + } + if ( + ['object', 'dictionary'].indexOf(paramSchema?.type) >= 0 && + paramSchema?.properties && + typeof exampleValue === 'object' && + !(exampleValue instanceof Array) + ) { + const ret = deepCopy(exampleValue); + for (const subProperty of paramSchema?.properties) { + if (subProperty.flattenedNames && subProperty.flattenedNames.length > 0) { + let subValue = exampleValue; + let i = 0; + for (; i < subProperty.flattenedNames.length; i++) { + if (isNullOrUndefined(subValue)) break; + const k = subProperty.flattenedNames[i]; + const v = subValue[k]; + if (v === undefined) break; + subValue = v; + } + if (i === subProperty.flattenedNames.length) { + ret[subProperty?.language['cli'].cliKey] = subValue; + } + } + } + for (const subProperty of paramSchema?.properties) { + if (subProperty.flattenedNames && subProperty.flattenedNames.length > 0) { + delete ret[subProperty.flattenedNames[0]]; + } + } + for (const subProperty of paramSchema?.properties) { + const k = subProperty?.language['cli'].cliKey; + if (exampleValue && exampleValue[k]) { + exampleValue[k] = this.FlattenProperty(subProperty, exampleValue[k]); + } + } + return ret; + } + return deepCopy(exampleValue); + } + + private checkPathToProperty(methodParam: MethodParam, ancestors: string[]): boolean { + return ( + ancestors.length > 0 && + isEqualStringArray( + methodParam.value.pathToProperty.map((x) => x?.language?.['az']?.name), + ancestors.slice(1), + ) + ); + } + + private checkFlattenedNames(methodParam: MethodParam, ancestors: string[]): boolean { + const flattenedNames = methodParam.value.targetProperty.flattenedNames; + return ( + !isNullOrUndefined(flattenedNames) && + flattenedNames.length === ancestors.length && + isEqualStringArray( + methodParam.value.targetProperty.flattenedNames.slice(0, -1), + ancestors.slice(1), + ) + ); + } + + private matchMethodParam( + methodParamList: MethodParam[], + paramName: string, + ancestors: string[], + ): MethodParam[] { + const ret: MethodParam[] = []; + if (!paramName) return ret; + for (const methodParam of methodParamList) { + let serializedName = methodParam.value.targetProperty?.serializedName; + if (!serializedName) serializedName = methodParam.value.language['cli'].cliKey; + // let methodParam_key = methodParam.value.language['cli'].cliKey; + if (serializedName.toLowerCase() === paramName.toLowerCase()) { + if ( + !('pathToProperty' in methodParam.value) || + this.checkPathToProperty(methodParam, ancestors) || + this.checkFlattenedNames(methodParam, ancestors) + ) { + ret.push(methodParam); + } + } + } + return ret; + } + + public FlattenExampleParameter( + methodParamList: MethodParam[], + exampleParam: ExampleParam[], + name: string, + value: any, + ancestors: string[], + ) { + for (const methodParam of this.matchMethodParam(methodParamList, name, ancestors)) { + let polySubParam: MethodParam = null; + let netValue = + typeof value === 'object' && !isNullOrUndefined(value) ? deepCopy(value) : value; + let rawValue = deepCopy(netValue); + if (methodParam.value['isPolyOfSimple']) { + const keyToMatch = + methodParam.value.schema.discriminator?.property?.language?.cli?.cliKey; + if (keyToMatch) { + for (const methodParam of methodParamList) { + const polySubParamObj = methodParam.value; + if (polySubParamObj.schema.extensions) { + const valueToMatch = + polySubParamObj.schema.extensions['x-ms-discriminator-value']; + if (netValue[keyToMatch] === valueToMatch) { + polySubParam = methodParam; + delete netValue[keyToMatch]; + break; + } + } + } + } + } + if (polySubParam) { + netValue = this.FlattenProperty(polySubParam.value?.schema, netValue); + rawValue = this.FlattenProperty(polySubParam.value?.schema, rawValue); + } else { + netValue = this.FlattenProperty(methodParam.value?.schema, netValue); + rawValue = this.FlattenProperty(methodParam.value?.schema, rawValue); + } + if ( + 'pathToProperty' in methodParam.value && + ancestors.length - methodParam.value.pathToProperty.length === 1 + ) { + // if the method parameter has 'pathToProperty', check the path with example parameter full path. + if (this.checkPathToProperty(methodParam, ancestors)) { + // exampleParam.set(name, value); + this.AddExampleParameter( + methodParam, + exampleParam, + netValue, + polySubParam, + ancestors, + rawValue, + ); + return; + } + } else if ( + 'targetProperty' in methodParam.value && + 'flattenedNames' in methodParam.value.targetProperty && + ancestors.length - methodParam.value.targetProperty.flattenedNames.length === 0 && + ancestors.length > 0 + ) { + // if the method parameter has 'flattenedNames', check the names (except the last name) with example parameter full path. + if (this.checkFlattenedNames(methodParam, ancestors)) { + // exampleParam.set(name, value); + this.AddExampleParameter( + methodParam, + exampleParam, + netValue, + polySubParam, + ancestors, + rawValue, + ); + return; + } + } else if (ancestors.length === 0) { + // exampleParam.set(name, value); + if ( + this.AddExampleParameter( + methodParam, + exampleParam, + netValue, + polySubParam, + ancestors, + rawValue, + ) + ) + return; + } + } + + if (!isNullOrUndefined(value) && typeof value === 'object') { + for (const subName in value) { + this.FlattenExampleParameter( + methodParamList, + exampleParam, + subName, + value[subName], + ancestors.concat(name), + ); + } + } + } + + public ConvertToCliParameters( + exampleParams: ExampleParam[], + commandGroup: string, + ): ExampleParam[] { + const ret: ExampleParam[] = []; + for (const param of exampleParams) { + // Object.entries(exampleParams).forEach(() => { + let paramName = ToSnakeCase(param.name); + if (paramName.endsWith('_name')) { + if (paramName === 'resource_group_name') { + paramName = 'resource_group'; + } + } + paramName = paramName.split('_').join('-'); + ret.push( + new ExampleParam( + '--' + paramName, + param.value, + param.isJson, + param.keyValue, + param.keys, + param.defaultName, + param.methodParam, + param.ancestors, + param.rawValue, + ), + ); + } + return ret; + } + + private filterExampleByPoly(exampleObj: any, example: CommandExample): boolean { + function getPolyClass(model): string { + const cliKey = model.methodHandler.Method.language['cli'].cliKey; + if (cliKey) { + const names = cliKey.split('#'); + if (names && names.length > 1) { + return names[names.length - 1]; + } + } + return ''; + } + const valueToMatch = getPolyClass(this); + if (!valueToMatch) return true; + + function matchPolyClass(example: CommandExample, keyToMatch: string, valueToMatch: string) { + for (const param of example.Parameters) { + if ( + (('--' + keyToMatch).toLowerCase() === param.name.toLowerCase() || + ('--' + keyToMatch + '-').toLowerCase() === param.name.toLowerCase()) && + typeof param.value === 'string' + ) { + return valueToMatch.toLowerCase() === param.value.toLowerCase(); + } + } + return true; + } + + // check polymophism here + const originalOperation = this.methodHandler.Method_GetOriginalOperation; + if (!isNullOrUndefined(originalOperation)) { + if (this.baseHandler.SelectFirstMethodParameter()) { + do { + if ( + !isNullOrUndefined( + this.methodParameterHandler.MethodParameter.extensions?.[ + 'cli-poly-as-resource-base-schema' + ], + ) + ) { + const originalSchema = this.methodParameterHandler.MethodParameter + .extensions?.['cli-poly-as-resource-base-schema']; + const keyToMatch = (originalSchema as any).discriminator.property.language + .default.name; // type + if (!matchPolyClass(example, keyToMatch, valueToMatch)) { + return false; + } + } + } while (this.baseHandler.SelectNextMethodParameter()); + } + } + return true; + } + + public GetExamples(includeGenerated: boolean): CommandExample[] { + if ( + !isNullOrUndefined(this.methodHandler.Method_AzExamples) && + this.methodHandler.Method_AzExamples.length > 0 && + includeGenerated + ) { + return this.methodHandler.Method_AzExamples; + } + const examples: CommandExample[] = []; + if (this.Examples) { + Object.entries(this.Examples).forEach(([id, exampleObj]) => { + if (includeGenerated || !isGeneratedExampleId(id)) { + const example = this.CreateCommandExample(id, exampleObj); + if (!isNullOrUndefined(example)) { + examples.push(example); + if (this.commandHandler.Command_MethodName === 'show') { + this.commandGroupHandler.CommandGroup_ShowExample = example; + } + } + } + }); + } + if (includeGenerated) this.methodHandler.Method_AzExamples = examples; + return examples; + } + + public GetExampleById(id: string, exampleObj: any): CommandExample { + let ret: CommandExample = undefined; + if (this.Examples) { + Object.entries(this.Examples).forEach(([_id, _exampleObj]) => { + if (!isNullOrUndefined(ret)) return; + if (!isNullOrUndefined(id) && id.toLowerCase() !== _id.toLowerCase()) return; + if (!isNullOrUndefined(exampleObj)) _exampleObj = exampleObj; + const example = this.CreateCommandExample(_id, _exampleObj); + if (!isNullOrUndefined(example)) ret = example; + }); + } + return ret; + } + + public CreateCommandExample(id: string, exampleObj: any): CommandExample { + function forUpdate(model: CodeModelCliImpl, exampleName: string): boolean { + const { exampleHandler } = model.GetHandler(); + const lowercase: string = exampleName.toLowerCase(); + return ( + lowercase.endsWith('_update') || + (exampleHandler.ExampleAmount > 1 && + lowercase.indexOf('update') >= 0 && + lowercase.indexOf('create') < 0) + ); + } + + const example = new CommandExample(); + example.Method = this.commandHandler.Command_MethodName; + example.Command = this.commandHandler.Command_Name; + example.Id = `/${this.commandGroupHandler.CommandGroup_Key}/${this.methodHandler.Method_HttpMethod}/${id}`; + example.Title = exampleObj.title || id; + example.Path = this.methodHandler.Method_Path; + example.HttpMethod = this.methodHandler.Method_HttpMethod; + example.ResourceClassName = this.commandGroupHandler.CommandGroup_Key; + const params = this.GetExampleParameters(exampleObj); + example.Parameters = this.ConvertToCliParameters( + params, + this.commandGroupHandler.CommandGroup_Key, + ); + example.MethodResponses = this.methodHandler.Method.responses || []; + example.Method_IsLongRun = !!this.methodHandler.Method.extensions?.[ + 'x-ms-long-running-operation' + ]; + example.ExampleObj = exampleObj; + if (this.methodHandler.Method_GetSplitOriginalOperation) { + // filter example by name for generic createorupdate + if ( + this.commandHandler.Command_MethodName.toLowerCase() === 'update' && + !forUpdate(this.baseHandler, id) + ) { + return; + } + if ( + this.commandHandler.Command_MethodName.toLowerCase() !== 'update' && + forUpdate(this.baseHandler, id) + ) { + return; + } + } + if (this.filterExampleByPoly(exampleObj, example)) { + for (let i = 0; i < example.Parameters.length; i++) { + if (this.isDiscriminator(example.Parameters[i].methodParam.value)) { + example.Parameters.splice(i, 1); + i--; + } + } + example.commandStringItems = this.GetExampleItems(example, false, undefined); + example.CommandString = example.commandStringItems.join(' '); + return example; + } + return undefined; + } + + public GetExampleChecks(example: CommandExample): string[] { + const ret: string[] = []; + if (!this.configHandler.GenChecks) return ret; + let resourceObjectName = undefined; + for (const param of example.Parameters) { + if ( + example.ResourceClassName && + this.resourcePool.isResource(param.defaultName, param.rawValue) === + example.ResourceClassName + ) { + resourceObjectName = param.value; + } + } + + const resourceObject = this.resourcePool.findResource( + example.ResourceClassName, + resourceObjectName, + ObjectStatus.Created, + ); + if (resourceObject) { + ret.push(...resourceObject.getCheckers(this.resourcePool, example)); + } + ret.push(...this.resourcePool.getListCheckers(example)); + return ret; + } + + public GetExampleItems( + example: CommandExample, + isTest: boolean, + commandParams: any, + minimum = false, + ): string[] { + const parameters: string[] = []; + parameters.push('az ' + this.commandHandler.Command_Name); + + let hasRG = false; + let resourceObjectName; + for (const param of example.Parameters) { + if ( + minimum && + !this.parameterHandler.Parameter_IsRequiredOrCLIRequired(param.methodParam.value) + ) + continue; + let paramValue = param.value; + if (isTest || this.configHandler.FormalizeNames) { + let replacedValue = this.resourcePool.addParamResource( + param.defaultName, + paramValue, + param.isJson, + param.keyValue, + isTest, + ); + if (replacedValue === paramValue) { + replacedValue = this.resourcePool.addEndpointResource( + paramValue, + param.isJson, + param.keyValue, + [], + [], + param, + isTest, + ); + } + paramValue = replacedValue; + param.replacedValue = replacedValue; + } + let slp = paramValue; + if (param.keyValue === KeyValueType.No) { + slp = ToJsonString(slp); + } + parameters.push(param.name + ' ' + slp); + + if (['--resource-group', '-g'].indexOf(param.name) >= 0) { + hasRG = true; + } + + if ( + example.ResourceClassName && + this.resourcePool.isResource(param.defaultName, param.rawValue) === + example.ResourceClassName + ) { + resourceObjectName = param.value; + } + } + + if ( + isTest && + !hasRG && + commandParams && + commandParams[this.commandHandler.Command_Name] && + commandParams[this.commandHandler.Command_Name].has('resourceGroupName') + ) { + parameters.push('-g ""'); + } + + if (isTest) { + const resourceObject = this.resourcePool.findResource( + example.ResourceClassName, + resourceObjectName, + undefined, + ); + if (resourceObject) { + const httpMethod = example.HttpMethod.toLowerCase(); + if (['put', 'post', 'patch'].indexOf(httpMethod) >= 0) { + if (httpMethod === 'post') { + resourceObject.exampleParams = []; + } + for (const param of example.Parameters) { + if ( + minimum && + !this.parameterHandler.Parameter_IsRequiredOrCLIRequired( + param.methodParam.value, + ) + ) + continue; + resourceObject.addOrUpdateParam(param); + } + resourceObject.testStatus = ObjectStatus.Created; + } + if (httpMethod === 'delete') { + resourceObject.testStatus = ObjectStatus.Deleted; + } + } + } + + return parameters; + } + + public GetExampleWait(example: CommandExample): string[] { + const parameters: string[] = []; + let foundResource = false; + if ( + example.HttpMethod.toLowerCase() === 'put' && + example.Method_IsLongRun && + example.MethodResponses.length > 0 && + (example.MethodResponses[0].schema?.properties || []).find((property) => { + return property?.language?.['cli']?.cliKey === 'provisioningState'; + }) + ) { + const showExample = this.commandGroupHandler.CommandGroup_ShowExample; + if (isNullOrUndefined(showExample)) return []; + let words = showExample.Command.split(' '); + words = words.slice(0, words.length - 1); + words.push('wait'); + parameters.push(`az ${words.join(' ')} --created`); + for (const param of example.Parameters) { + const paramKey = param.methodParam.value.language?.['cli']?.cliKey; + if ( + showExample.Parameters.some((showParam) => { + return ( + showParam.methodParam.value.language?.['cli']?.cliKey == + param.methodParam.value.language?.['cli']?.cliKey && + showParam.methodParam.value.language?.['default']?.cliKey == + param.methodParam.value.language?.['default']?.cliKey + ); + }) + ) { + let paramValue = param.value; + let replacedValue = this.resourcePool.addParamResource( + param.defaultName, + paramValue, + param.isJson, + param.keyValue, + ); + if (replacedValue === paramValue) { + replacedValue = this.resourcePool.addEndpointResource( + paramValue, + param.isJson, + param.keyValue, + [], + [], + param, + ); + } + paramValue = replacedValue; + let slp = paramValue; + if (param.keyValue === KeyValueType.No) { + slp = ToJsonString(slp); + } + parameters.push(param.name + ' ' + slp); + } + if ( + this.resourcePool.isResource(paramKey, param.rawValue) === + example.ResourceClassName + ) + foundResource = true; + } + } + return foundResource ? parameters : []; + } + + public GetPreparerEntities(): any[] { + return this.resourcePool.createPreparerEntities(); + } + + public GetSubscriptionKey(): string { + if (this.resourcePool.useSubscription) { + return ResourcePool.KEY_SUBSCRIPTIONID; + } else { + return null; + } + } + + public FindExampleById( + id: string, + commandParams: any, + examples: CommandExample[], + minimum = false, + step: TestStepExampleFileRestCall = undefined, + ): string[][] { + const ret: string[][] = []; + this.GetAllExamples( + id, + (example) => { + examples.push(example); + ret.push(this.GetExampleItems(example, true, commandParams, minimum)); + }, + step?.exampleTemplate, + ); + return ret; + } + + public FindExampleWaitById( + id: string, + step: TestStepExampleFileRestCall = undefined, + ): string[][] { + const ret: string[][] = []; + this.GetAllExamples( + id, + (example) => { + const waitCmd = this.GetExampleWait(example); + if (waitCmd.length > 0) ret.push(waitCmd); + }, + step?.exampleTemplate, + ); + return ret; + } + + public GatherInternalResource() { + const internalResources = {}; // resource_key --> list of resource languages + this.baseHandler.GetAllMethods(null, () => { + if (!(this.commandGroupHandler.CommandGroup_Key in internalResources)) { + internalResources[this.commandGroupHandler.CommandGroup_Key] = [ + this.commandGroupHandler.CommandGroup_Key, + ]; + } + // let commands = this.CommandGroup_Name.split(" "); + // let resourceName = commands[commands.length - 1] + "-name"; + const resourceName = this.commandGroupHandler.CommandGroup_DefaultName + 'Name'; + if ( + internalResources[this.commandGroupHandler.CommandGroup_Key].indexOf(resourceName) < + 0 + ) { + internalResources[this.commandGroupHandler.CommandGroup_Key].push(resourceName); + } + }); + this.resourcePool.addResourcesInfo(internalResources); + + // find dependency relationships of internalResources + this.baseHandler.GetAllMethods(null, () => { + const dependResources = []; + const dependParameters = []; + + const examples = this.GetExamples(false); + // recognize depends by endpoint in examples + for (const example of examples) { + for (const param of example.Parameters) { + const resources = []; + this.resourcePool.addEndpointResource( + param.value, + param.isJson, + param.keyValue, + [], + resources, + param, + ); + for (const onResource of resources) { + if ( + onResource !== this.commandGroupHandler.CommandGroup_Key && + dependResources.indexOf(onResource) < 0 + ) { + dependResources.push(onResource); + dependParameters.push(param.name); + } + } + this.resourcePool.addParamResource( + param.defaultName, + param.value, + param.isJson, + param.keyValue, + ); + } + } + + // recognize depends by parameter name' + const createdObjectNames = []; + const isCreateMehod = this.methodHandler.Method_HttpMethod === 'put'; + if (this.baseHandler.SelectFirstMethodParameter()) { + do { + if ( + this.methodParameterHandler.MethodParameter.implementation === 'Method' && + !this.methodParameterHandler.MethodParameter_IsFlattened && + this.methodParameterHandler.MethodParameter?.schema?.type !== 'constant' + ) { + const paramName = this.methodParameterHandler.MethodParameter.language[ + 'cli' + ].cliKey; + const onResource = this.resourcePool.isResource(paramName, undefined); + for (const example of examples) { + for (const param of example.Parameters) { + if ( + onResource && + onResource !== this.commandGroupHandler.CommandGroup_Key && + dependResources.indexOf(onResource) < 0 + ) { + // the resource is a dependency only when it's a parameter in an example. + if ( + paramName === param.defaultName && + dependResources.indexOf(onResource) < 0 + ) { + dependResources.push(onResource); + dependParameters.push(paramName); + } + } + if ( + isCreateMehod && + onResource && + onResource === this.commandGroupHandler.CommandGroup_Key && + createdObjectNames.indexOf(param.value) < 0 + ) { + createdObjectNames.push(param.value); + } + } + } + } + } while (this.baseHandler.SelectNextMethodParameter()); + } + + this.resourcePool.setResourceDepends( + this.commandGroupHandler.CommandGroup_Key, + dependResources, + dependParameters, + createdObjectNames, + ); + }); + + if (isNullOrUndefined(this._defaultTestScenario)) { + const allExamples = this.GetAllExamples(); + this._defaultTestScenario = GenerateDefaultTestScenario(allExamples); + this._defaultTestScenario = GenerateDefaultTestScenarioByDependency( + allExamples, + this.resourcePool, + this._defaultTestScenario, + ); + this.SortExamplesByDependency(); + PrintTestScenario(this._defaultTestScenario); + } + + if (!this._configuredScenario && isNullOrUndefined(this._testScenario)) { + this._testScenario = GroupTestScenario( + this._defaultTestScenario, + this.extensionHandler.Extension_NameUnderscored, + ); + } + + const commandParams = {}; + this.baseHandler.GetAllMethods(null, () => { + if (!commandParams[this.commandHandler.Command_Name]) + commandParams[this.commandHandler.Command_Name] = new Set(); + if (this.baseHandler.SelectFirstMethodParameter()) { + do { + if ( + (this.methodParameterHandler.MethodParameter.implementation === 'Method' || + (this.methodParameterHandler.MethodParameter as any).polyBaseParam) && + !this.methodParameterHandler.MethodParameter_IsFlattened && + this.methodParameterHandler.MethodParameter?.schema?.type !== 'constant' + ) { + commandParams[this.commandHandler.Command_Name].add( + this.methodParameterHandler.MethodParameter.language['cli'].cliKey, + ); + } + } while (this.baseHandler.SelectNextMethodParameter()); + } + }); + return commandParams; + } + + public SortExamplesByDependency() { + const dependOn = (exampleA: CommandExample, exampleB: CommandExample): boolean => { + // TODO: check dependency by object + return this.resourcePool.isDependResource( + exampleA.ResourceClassName, + exampleB.ResourceClassName, + ); + }; + + const isCreate = (example: CommandExample): boolean => { + return example.HttpMethod === 'put'; + }; + + const isDelete = (example: CommandExample): boolean => { + return example.HttpMethod === 'delete'; + }; + + // stable sort + const compare = (examplesA: CommandExample, examplesB: CommandExample): number => { + if (!examplesA || !examplesB) return 0; + + if (examplesA.ResourceClassName === examplesB.ResourceClassName) { + if (isCreate(examplesB) && !isCreate(examplesA)) { + return 1; + } else if (isDelete(examplesB) && !isDelete(examplesA)) { + return -1; + } else if (isCreate(examplesA) && !isCreate(examplesB)) { + return -1; + } else if (isDelete(examplesA) && !isDelete(examplesB)) { + return 1; + } else { + return examplesA.Id.localeCompare(examplesB.Id); + } + } else if (dependOn(examplesA, examplesB)) { + if (isCreate(examplesB)) { + return 1; + } else if (isDelete(examplesB)) { + return -1; + } else { + return 1; + } + } else if (dependOn(examplesB, examplesA)) { + if (isCreate(examplesA)) { + return -1; + } else if (isDelete(examplesA)) { + return 1; + } else { + return -1; + } + } + return examplesA.Id.localeCompare(examplesB.Id); + }; + + const scenarioExamples: Map = new Map(); + const commandExamples = this.GetAllExamples(); + for (let i = 0; i < this._defaultTestScenario.length; i++) { + for (const commandExample of commandExamples) { + if (this.matchExample(commandExample, this._defaultTestScenario[i].name)) { + scenarioExamples.set(this._defaultTestScenario[i].name, commandExample); + break; + } + } + } + + this._defaultTestScenario = MergeSort(this._defaultTestScenario, (exampleA, exampleB) => { + return compare( + scenarioExamples.get(exampleA.name), + scenarioExamples.get(exampleB.name), + ); + }); + } + + private matchExample(example: CommandExample, id: string) { + if (!id) return false; + return ( + example.Id.toLowerCase() === id.toLowerCase() || + example.Id.toLowerCase().endsWith(`/${id.toLowerCase()}`) + ); + } + + public GetAllExamples( + id?: string, + callback?: (example) => void, + exampleTemplate?: any, + ): CommandExample[] { + const ret: CommandExample[] = []; + let found = false; + this.baseHandler.GetAllMethods(null, () => { + if (found) return; + let examples: CommandExample[]; + if (!isNullOrUndefined(exampleTemplate)) { + const example = this.GetExampleById(id, exampleTemplate); + if (isNullOrUndefined(example)) return; + examples = [example]; + } else { + examples = this.GetExamples(true); + } + for (const example of examples) { + if (id && !this.matchExample(example, id)) continue; + if (callback) { + callback(example); + } + if (ret.indexOf(example) > -1) { + continue; + } + ret.push(example); + if (id) { + found = true; + } + } + }); + return ret; + } +} diff --git a/src/generate/codemodel/Extension.ts b/src/generate/codemodel/Extension.ts new file mode 100644 index 000000000..561a590e9 --- /dev/null +++ b/src/generate/codemodel/Extension.ts @@ -0,0 +1,69 @@ +import { isNullOrUndefined, ToSentence } from '../../utils/helper'; +import { AzConfiguration, CodeGenConstants } from '../../utils/models'; +import { CodeModelCliImpl } from './CodeModelAzImpl'; + +export interface ExtensionModel { + Extension_Name: string; + Extension_Parent: string; + Extension_Description: string; + Extension_NameUnderscored: string; + Extension_NameClass: string; + Extension_ClientSubscriptionBound: boolean; + Extension_ClientBaseUrlBound: boolean; + Extension_ClientAuthenticationPolicy: string; + Extension_Mode: string; +} + +export class ExtensionModelImpl implements ExtensionModel { + constructor(public baseHandler: CodeModelCliImpl) {} + public get Extension_Name(): string { + return this.baseHandler.extensionName; + } + + public get Extension_Parent(): string { + return this.baseHandler.parentExtension; + } + + public get Extension_Description(): string { + if (!isNullOrUndefined(AzConfiguration.getValue(CodeGenConstants.extensionDescription))) { + return 'Manage ' + AzConfiguration.getValue(CodeGenConstants.extensionDescription); + } + return ( + 'Manage ' + + ToSentence(this.Extension_NameClass.replace(/ManagementClient|Client/gi, '')) + ); + } + + public get Extension_Mode(): string { + let extensionMode = AzConfiguration.getValue(CodeGenConstants.extensionMode); + this.baseHandler.codeModel.operationGroups.forEach((operationGroup) => { + if ( + operationGroup.language['az'].command === this.Extension_Name && + !isNullOrUndefined(operationGroup.language?.['cli']?.extensionMode) + ) { + extensionMode = operationGroup.language?.['cli']?.extensionMode; + } + }); + return extensionMode; + } + + public get Extension_NameUnderscored(): string { + return this.Extension_Name.replace(/-/g, '_'); + } + + public get Extension_NameClass(): string { + return this.baseHandler.codeModel.info['pascal_case_title']; + } + + public get Extension_ClientSubscriptionBound(): boolean { + return this.baseHandler._clientSubscriptionBound; + } + + public get Extension_ClientBaseUrlBound(): boolean { + return this.baseHandler._clientBaseUrlBound; + } + + public get Extension_ClientAuthenticationPolicy(): string { + return this.baseHandler._clientAuthenticationPolicy; + } +} diff --git a/src/generate/codemodel/Method.ts b/src/generate/codemodel/Method.ts new file mode 100644 index 000000000..f40c870b7 --- /dev/null +++ b/src/generate/codemodel/Method.ts @@ -0,0 +1,187 @@ +import { Operation, Parameter } from '@azure-tools/codemodel'; +import { isNullOrUndefined } from '../../utils/helper'; +import { CommandExample } from './Example'; +import { CodeModelCliImpl } from './CodeModelAzImpl'; +import { CommandGroupModel } from './CommandGroup'; + +export interface MethodModel { + Method: Operation; + Method_IsFirst: boolean; + Method_IsLast: boolean; + Method_Name: string; + Method_NameAz: string; + Method_NameCli: string; + Method_Help: string; + Method_CliKey: string; + Method_MaxApi: string; + Method_MinApi: string; + Method_ResourceType: string | undefined; + Method_BodyParameterName: string; + Method_IsLongRun: boolean; + Method_GetOriginalOperation: any; + Method_GetSplitOriginalOperation: any; + Method_GenericSetterParameter(Operation): Parameter; + Method_NeedGeneric: boolean; + Method_Mode: string; + Method_AzExamples: CommandExample[]; + Method_HttpMethod: string; + Method_Path: string; + // Method_Features: [string, string]; + // Method_Imports: [string, string[]]; +} + +export class MethodModelImpl implements MethodModel { + private commandGroupHandler: CommandGroupModel; + constructor(public baseHandler: CodeModelCliImpl) { + const { commandGroupHandler } = baseHandler.GetHandler(); + this.commandGroupHandler = commandGroupHandler; + } + + public get Method(): Operation { + if ( + this.baseHandler.currentMethodIndex < 0 || + this.baseHandler.currentMethodIndex >= + this.commandGroupHandler.CommandGroup.operations.length + ) { + return undefined; + } + return this.commandGroupHandler.CommandGroup.operations[ + this.baseHandler.currentMethodIndex + ]; + } + + public get Method_IsFirst(): boolean { + if (this.baseHandler.currentMethodIndex === this.baseHandler.preMethodIndex) { + return true; + } else { + return false; + } + } + + public get Method_IsLast(): boolean { + if (this.baseHandler.currentMethodIndex === this.baseHandler.currentOperationIndex) { + return true; + } else { + let curIndex = this.baseHandler.currentMethodIndex + 1; + let hasNext = false; + while (curIndex <= this.baseHandler.currentOperationIndex) { + if ( + !this.baseHandler.Operation_IsHidden( + this.commandGroupHandler.CommandGroup.operations[curIndex], + ) + ) { + hasNext = true; + break; + } + curIndex++; + } + return !hasNext; + } + } + + public get Method_IsLongRun(): boolean { + return !!this.Method.extensions?.['x-ms-long-running-operation']; + } + + public get Method_Name(): string { + return this.Method.language.python.name; + } + + public get Method_NameAz(): string { + return this.Method.language['az'].name; + } + + public get Method_NameCli(): string { + return this.Method.language['cli'].name; + } + + public get Method_CliKey(): string { + return this.Method.language['cli']?.cliKey; + } + + public get Method_MaxApi(): string { + return this.Method.language['cli']?.['max-api']; + } + + public get Method_MinApi(): string { + return this.Method.language['cli']?.['min-api']; + } + + public get Method_ResourceType(): string | undefined { + return this.baseHandler.formResourceType(this.Method.language['cli']?.['resource-type']); + } + + public get Method_BodyParameterName(): string { + return null; + } + + public get Method_Path(): string { + return this.Method.requests[0].protocol?.http?.path; + } + + public get Method_Help(): string { + return this.Method.language['az'].description.replace(/\n/g, ' ').replace(/"/g, '\\\\"'); + } + + public get Method_HttpMethod(): string { + const ret = this.Method.requests[0].protocol?.http?.method || 'unknown'; + return ret.toLowerCase(); + } + + public Method_GenericSetterParameter(op: Operation = this.Method): Parameter { + if (isNullOrUndefined(op)) { + return null; + } + return op['genericSetterParam']; + } + + public get Method_NeedGeneric(): boolean { + if ( + this.Method.language['az'].isSplitUpdate && + this.commandGroupHandler.CommandGroup_HasShowCommand && + !isNullOrUndefined(this.Method_GenericSetterParameter(this.Method_GetOriginalOperation)) + ) { + return true; + } + return false; + } + + public Get_Method_Name(language = 'az'): string { + return this.Method.language[language].name; + } + + public get Method_GetOriginalOperation(): any { + const polyOriginal = this.Method.extensions?.['cli-poly-as-resource-original-operation']; + if ( + !isNullOrUndefined(polyOriginal) && + !isNullOrUndefined(polyOriginal.extensions?.['cli-split-operation-original-operation']) + ) { + const splitOriginal = + polyOriginal.extensions?.['cli-split-operation-original-operation']; + return splitOriginal; + } + const splittedOriginal = this.Method.extensions?.['cli-split-operation-original-operation']; + if (!isNullOrUndefined(splittedOriginal)) { + return splittedOriginal; + } + return polyOriginal; + } + + public get Method_GetSplitOriginalOperation(): any { + return this.Method.extensions?.['cli-split-operation-original-operation']; + } + + public get Method_Mode(): string { + return this.Method?.language?.['cli']?.extensionMode; + } + + public get Method_AzExamples(): CommandExample[] { + return this.Method?.['az-examples']; + } + + public set Method_AzExamples(examples: CommandExample[]) { + if (isNullOrUndefined(this.Method_AzExamples) || this.Method_AzExamples.length === 0) { + this.Method['az-examples'] = examples; + } + } +} diff --git a/src/generate/codemodel/MethodParameter.ts b/src/generate/codemodel/MethodParameter.ts new file mode 100644 index 000000000..717052237 --- /dev/null +++ b/src/generate/codemodel/MethodParameter.ts @@ -0,0 +1,336 @@ +import { Channel } from '@autorest/extension-base'; +import { Parameter, ParameterLocation, SchemaType } from '@azure-tools/codemodel'; +import { isNullOrUndefined } from '../../utils/helper'; +import { CodeModelCliImpl } from './CodeModelAzImpl'; +import { CommandGroupModel } from './CommandGroup'; +import { MethodModel } from './Method'; +import { ParameterModel } from './Parameter'; +import { SchemaModel } from './Schema'; + +export interface MethodParameterModel { + MethodParameter_Name: string; + MethodParameter_NameAz: string; + MethodParameter_ActionName: string; + MethodParameter_CliKey: string; + MethodParameter_MaxApi: string; + MethodParameter_MinApi: string; + MethodParameter_ResourceType: string | undefined; + MethodParameter_IsArray: boolean; + MethodParameter_NamePython: string; + MethodParameter_MapsTo: string; + MethodParameter_Description: string; + MethodParameter_Type: string; + MethodParameter_IsList: boolean; + MethodParameter_IsSimpleArray: boolean; + MethodParameter_IsListOfSimple: boolean; + MethodParameter_IsPolyOfSimple: boolean; + MethodParameter_IsDiscriminator: boolean; + MethodParameter_IdPart: string; + MethodParameter_ArgGroup: string; + MethodParameter: Parameter; + SubMethodParameter: Parameter; + + MethodParameter_In: string; + MethodParameter_IsHidden: boolean; + MethodParameter_IsRequired: boolean; + MethodParameter_IsFlattened: boolean; + MethodParameter_IsCliFlattened: boolean; + MethodParameter_RequiredByMethod: boolean; + MethodParameter_EnumValues: string[]; + MethodParameter_DefaultValue: any | undefined; + MethodParameter_DefaultConfigKey: string | undefined; + MethodParameter_Mode: string; + MethodParameter_IsPositional: boolean; + MethodParameter_IsShorthandSyntax: boolean; + MethodParameter_PositionalKeys: string[]; + MethodParameter_Features: Record; + MethodParameter_Imports: Record; +} + +export class MethodParameterModelImpl implements MethodParameterModel { + private commandGroupHandler: CommandGroupModel; + private methodHandler: MethodModel; + private parameterHandler: ParameterModel; + constructor(public baseHandler: CodeModelCliImpl) { + const { commandGroupHandler, methodHandler, parameterHandler } = baseHandler.GetHandler(); + this.commandGroupHandler = commandGroupHandler; + this.methodHandler = methodHandler; + this.parameterHandler = parameterHandler; + } + public get MethodParameter(): Parameter { + return this.baseHandler.MethodParameters[this.baseHandler.currentParameterIndex]; + } + + public get MethodParameter_ActionName() { + const schema = this.MethodParameter.schema; + if (this.baseHandler.paramActionNameReference.has(schema)) { + return this.baseHandler.paramActionNameReference.get(schema); + } + return undefined; + } + + public get MethodParameter_Name(): string { + return this.parameterHandler.Parameter_Name(this.MethodParameter); + } + + public get MethodParameter_NameAz(): string { + return this.parameterHandler.Parameter_NameAz(this.MethodParameter); + } + + public get MethodParameter_CliKey(): string { + return this.parameterHandler.Parameter_CliKey(this.MethodParameter); + } + + public get MethodParameter_MaxApi(): string { + return this.MethodParameter.language['cli']?.['max-api']; + } + + public get MethodParameter_MinApi(): string { + return this.MethodParameter.language['cli']?.['min-api']; + } + + public get MethodParameter_ResourceType(): string | undefined { + return this.baseHandler.formResourceType( + this.MethodParameter.language['cli']?.['resource-type'], + ); + } + + public get MethodParameter_IdPart(): string { + return this.MethodParameter.language['az'].id_part; + } + + public get MethodParameter_IsArray(): boolean { + if (!isNullOrUndefined(this.baseHandler.submethodparameters)) { + return ( + this.baseHandler.submethodparameters[this.baseHandler.currentSubOptionIndex].schema + ?.type === SchemaType.Array + ); + } else { + return this.MethodParameter.schema?.type === SchemaType.Array; + } + } + + public get MethodParameter_NamePython(): string { + return this.parameterHandler.Parameter_NamePython(this.MethodParameter); + } + + public get MethodParameter_MapsTo(): string { + return this.parameterHandler.Parameter_MapsTo(this.MethodParameter); + } + public get MethodParameter_Description(): string { + return this.parameterHandler.Parameter_Description(this.MethodParameter); + } + + public get MethodParameter_Type(): string { + return this.parameterHandler.Parameter_Type(this.MethodParameter); + } + + public get MethodParameter_IsList(): boolean { + return this.parameterHandler.Parameter_IsList(this.MethodParameter); + } + + public get MethodParameter_ArgGroup(): string { + return this.MethodParameter.language['az']?.arg_group; + } + + public get MethodParameter_Mode() { + if (isNullOrUndefined(this.MethodParameter?.language?.['cli']?.extensionMode)) { + return this.methodHandler.Method_Mode; + } + return this.MethodParameter?.language?.['cli']?.extensionMode; + } + + public get MethodParameter_IsPositional(): boolean { + return this.parameterHandler.Parameter_IsPositional(this.MethodParameter); + } + + public get MethodParameter_IsShorthandSyntax(): boolean { + return this.parameterHandler.Parameter_IsShorthandSyntax(this.MethodParameter); + } + + public get MethodParameter_IsListOfSimple(): boolean { + return this.parameterHandler.Parameter_IsListOfSimple(this.MethodParameter); + } + + public get MethodParameter_IsPolyOfSimple(): boolean { + return this.parameterHandler.Parameter_IsPolyOfSimple(this.MethodParameter); + } + + public get MethodParameter_IsDiscriminator(): boolean { + return ( + this.methodHandler.Method_GetOriginalOperation && + this.MethodParameter['targetProperty'] && + this.MethodParameter['targetProperty']['isDiscriminator'] + ); + } + + public get SubMethodParameter(): Parameter { + if (!isNullOrUndefined(this.baseHandler.submethodparameters)) { + return this.baseHandler.submethodparameters[this.baseHandler.currentSubOptionIndex]; + } + return null; + } + + public get MethodParameter_EnumValues(): string[] { + const mtype = this.MethodParameter.schema.type; + if (mtype === SchemaType.Choice || mtype === SchemaType.SealedChoice) { + const enumArray = []; + const schema = this.MethodParameter.schema; + for (const item of schema['choices']) { + enumArray.push(item.value); + } + return enumArray; + } else { + return []; + } + } + + public get MethodParameter_In(): string { + const protocol = this.MethodParameter.protocol; + return protocol !== undefined && + protocol.http !== undefined && + protocol.http.in !== undefined + ? protocol.http.in + : ParameterLocation.Body; + } + + public get MethodParameter_IsHidden(): boolean { + return this.Parameter_IsHidden(this.MethodParameter); + } + + public Parameter_IsHidden(parameter: Parameter): boolean { + if (!Object.prototype.hasOwnProperty.call(parameter.language['az'], 'hidden')) { + // Handle complex + let shouldHidden; + let defaultValue; + let hasDefault = false; + if (this.baseHandler.EnterSubMethodParameters(parameter)) { + shouldHidden = true; + defaultValue = '{'; + if (this.baseHandler.SelectFirstMethodParameter()) { + do { + if ( + this.parameterHandler.Parameter_Type(this.SubMethodParameter) !== + SchemaType.Constant && + this.SubMethodParameter['readOnly'] !== true + ) { + shouldHidden = false; + break; + } else if ( + this.parameterHandler.Parameter_Type(this.SubMethodParameter) === + SchemaType.Constant + ) { + defaultValue = + defaultValue + + '"' + + this.parameterHandler.Parameter_NameAz(this.SubMethodParameter) + + '": "' + + this.parameterHandler.Parameter_DefaultValue( + this.SubMethodParameter, + ) + + '"'; + hasDefault = true; + } + } while (this.baseHandler.SelectNextMethodParameter()); + } + if ( + shouldHidden === true && + (hasDefault || this.parameterHandler.Parameter_IsRequired(parameter)) + ) { + defaultValue = defaultValue + '}'; + } else { + defaultValue = undefined; + } + this.baseHandler.ExitSubMethodParameters(); + } + + // Handle simple parameter + if (parameter?.language?.['cli']?.removed || parameter?.language?.['cli']?.hidden) { + if ( + this.parameterHandler.Parameter_DefaultValue(parameter) === undefined && + parameter.required === true + ) { + parameter.language['az'].hidden = false; + this.baseHandler.session.message({ + Channel: Channel.Warning, + Text: + 'OperationGroup ' + + this.commandGroupHandler.CommandGroup.language['az'].name + + ' operation ' + + this.methodHandler.Method_Name + + ' parameter ' + + parameter.language['az'].name + + ' should not be hidden while it is required without default value', + }); + } else { + parameter.language['az'].hidden = true; + } + } else { + parameter.language['az'].hidden = parameter['hidden'] ?? shouldHidden ?? false; + if ( + !Object.prototype.hasOwnProperty.call( + parameter.language['az'], + 'default-value', + ) && + defaultValue !== undefined + ) { + parameter.language['az']['default-value'] = defaultValue; + } + } + } + + return parameter.language['az'].hidden; + } + + public get MethodParameter_DefaultValue(): string | undefined { + return this.parameterHandler.Parameter_DefaultValue(this.MethodParameter); + } + + public get MethodParameter_DefaultConfigKey(): string | undefined { + return this.parameterHandler.Parameter_DefaultConfigKey(this.MethodParameter); + } + + public get MethodParameter_IsRequired(): boolean { + return this.parameterHandler.Parameter_IsRequired(this.MethodParameter); + } + + public get MethodParameter_IsFlattened(): boolean { + return this.parameterHandler.Parameter_IsFlattened(this.MethodParameter); + } + + public get MethodParameter_IsCliFlattened(): boolean { + return this.parameterHandler.Parameter_IsCliFlattened(this.MethodParameter); + } + + public get MethodParameter_RequiredByMethod(): boolean { + return this.MethodParameter['RequiredByMethod']; + } + + public get MethodParameter_IsSimpleArray(): boolean { + return this.parameterHandler.Parameter_IsSimpleArray(this.MethodParameter); + } + + public get MethodParameter_PositionalKeys(): string[] { + const subMethodParams: Parameter[] = []; + if (this.baseHandler.EnterSubMethodParameters()) { + if (this.baseHandler.SelectFirstMethodParameter(true)) { + do { + subMethodParams.push(this.SubMethodParameter); + } while (this.baseHandler.SelectNextMethodParameter(true)); + } + this.baseHandler.ExitSubMethodParameters(); + } + return this.parameterHandler.Parameter_PositionalKeys( + this.baseHandler.methodParameterHandler.MethodParameter, + subMethodParams, + ); + } + + public get MethodParameter_Features(): Record { + return this.MethodParameter.language['az']['features']; + } + + public get MethodParameter_Imports(): Record { + return this.MethodParameter.language['az']['imports']; + } +} diff --git a/src/generate/codemodel/Parameter.ts b/src/generate/codemodel/Parameter.ts new file mode 100644 index 000000000..e134007e2 --- /dev/null +++ b/src/generate/codemodel/Parameter.ts @@ -0,0 +1,401 @@ +import { Channel } from '@autorest/extension-base'; +import { Parameter, SchemaType } from '@azure-tools/codemodel'; +import { isNullOrUndefined } from '../../utils/helper'; +import { EXCLUDED_PARAMS } from '../../utils/models'; +import { CodeModelCliImpl } from './CodeModelAzImpl'; +import { CommandGroupModel } from './CommandGroup'; +import { ConfigModel } from './Config'; +import { MethodModel } from './Method'; +import { SchemaModel } from './Schema'; + +export interface ParameterModel { + Parameter_Type(Parameter): string; + Parameter_IsList(Parameter): boolean; + Parameter_IsListOfSimple(Parameter): boolean; + Parameter_IsPolyOfSimple(Parameter?): boolean; + Parameter_SetAzNameMapsTo(string, Parameter): void; + Parameter_InGlobal(Parameter): boolean; + Parameter_IsHidden(Parameter): boolean; + Parameter_IsFlattened(Parameter): boolean; + Parameter_IsCliFlattened(Parameter): boolean; + Parameter_MapsTo(Parameter): string; + Parameter_SubMapsTo(subMethodName, Parameter): string; + Parameter_Name(Parameter?): string; + Parameter_NameAz(Parameter): string; + Parameter_CliKey(Parameter): string; + Parameter_NamePython(Parameter): string; + Parameter_Description(Parameter): string; + Parameter_DefaultValue(Parameter): any | undefined; + Parameter_DefaultConfigKey(Parameter): string | undefined; + Parameter_IsPositional(Parameter): boolean; + Parameter_IsShorthandSyntax(Parameter): boolean; + Parameter_PositionalKeys(param: Parameter, subMethodParams: Parameter[]): string[]; + Parameter_IsSimpleArray(param: Parameter): boolean; + Parameter_IsRequired(param: Parameter): boolean; + Parameter_IsRequiredOrCLIRequired(param: Parameter): boolean; +} + +export class ParameterModelImpl implements ParameterModel { + private commandGroupHandler: CommandGroupModel; + private methodHandler: MethodModel; + private schemaHandler: SchemaModel; + private configHandler: ConfigModel; + constructor(public baseHandler: CodeModelCliImpl) { + const { + commandGroupHandler, + methodHandler, + schemaHandler, + configHandler, + } = baseHandler.GetHandler(); + this.commandGroupHandler = commandGroupHandler; + this.methodHandler = methodHandler; + this.schemaHandler = schemaHandler; + this.configHandler = configHandler; + } + public Parameter_IsHidden(parameter: Parameter): boolean { + if (!Object.prototype.hasOwnProperty.call(parameter.language['az'], 'hidden')) { + // Handle complex + let shouldHidden; + let defaultValue; + let hasDefault = false; + if (this.baseHandler.EnterSubMethodParameters(parameter)) { + shouldHidden = true; + defaultValue = '{'; + if (this.baseHandler.SelectFirstMethodParameter()) { + do { + if ( + this.Parameter_Type(this.baseHandler.SubMethodParameter) !== + SchemaType.Constant && + this.baseHandler.SubMethodParameter['readOnly'] !== true + ) { + shouldHidden = false; + break; + } else if ( + this.Parameter_Type(this.baseHandler.SubMethodParameter) === + SchemaType.Constant + ) { + defaultValue = + defaultValue + + '"' + + this.Parameter_NameAz(this.baseHandler.SubMethodParameter) + + '": "' + + this.Parameter_DefaultValue(this.baseHandler.SubMethodParameter) + + '"'; + hasDefault = true; + } + } while (this.baseHandler.SelectNextMethodParameter()); + } + if (shouldHidden === true && (hasDefault || this.Parameter_IsRequired(parameter))) { + defaultValue = defaultValue + '}'; + } else { + defaultValue = undefined; + } + this.baseHandler.ExitSubMethodParameters(); + } + + // Handle simple parameter + if (parameter?.language?.['cli']?.removed || parameter?.language?.['cli']?.hidden) { + if ( + this.Parameter_DefaultValue(parameter) === undefined && + parameter.required === true + ) { + parameter.language['az'].hidden = false; + this.baseHandler.session.message({ + Channel: Channel.Warning, + Text: + 'OperationGroup ' + + this.commandGroupHandler.CommandGroup.language['az'].name + + ' operation ' + + this.methodHandler.Method_Name + + ' parameter ' + + parameter.language['az'].name + + ' should not be hidden while it is required without default value', + }); + } else { + parameter.language['az'].hidden = true; + } + } else { + parameter.language['az'].hidden = parameter['hidden'] ?? shouldHidden ?? false; + if ( + !Object.prototype.hasOwnProperty.call( + parameter.language['az'], + 'default-value', + ) && + defaultValue !== undefined + ) { + parameter.language['az']['default-value'] = defaultValue; + } + } + } + + return parameter.language['az'].hidden; + } + + public Parameter_DefaultValue(parameter: Parameter): string | undefined { + if (!Object.prototype.hasOwnProperty.call(parameter.language['az'], 'default-value')) { + if ( + Object.prototype.hasOwnProperty.call(parameter?.language?.['cli'], 'default-value') + ) { + parameter.language['az']['default-value'] = + parameter.language['cli']['default-value']; + } else if (parameter.schema.type === SchemaType.Constant) { + parameter.language['az']['default-value'] = parameter.schema?.['value']?.value; + } else { + parameter.language['az']['default-value'] = parameter.schema.defaultValue; + } + } + + return parameter.language['az']['default-value']; + } + + public Parameter_DefaultConfigKey(parameter: Parameter): string | undefined { + if (!Object.prototype.hasOwnProperty.call(parameter.language['az'], 'default-config-key')) { + if ( + Object.prototype.hasOwnProperty.call( + parameter?.language?.['cli'], + 'default-config-key', + ) + ) { + parameter.language['az']['default-config-key'] = + parameter.language['cli']['default-config-key']; + } + } + return parameter.language['az']['default-config-key']; + } + + public Parameter_Description(param: Parameter): string { + return param.language['az'].description?.replace(/\r?\n|\r/g, ' '); + } + + public Parameter_InGlobal(parameter: Parameter): boolean { + if (this.baseHandler.codeModel.globalParameters.indexOf(parameter) > -1) { + return true; + } + return false; + } + + public Parameter_Name(param: Parameter): string { + return param.language['az'].name.replace(/-/g, '_'); + } + + public Parameter_NameAz(param: Parameter): string { + return param.language['az'].name; + } + + public Parameter_CliKey(param: Parameter): string { + return param.language['cli']?.cliKey; + } + + public Parameter_NamePython(param: Parameter): string { + if ( + this.configHandler.SDK_IsTrack1 && + !isNullOrUndefined(param.language['cli']?.track1_name) + ) { + return param.language['cli']?.track1_name; + } + return param.language?.python?.name; + } + + public Parameter_IsPositional(param: Parameter): boolean { + if (param?.schema && this.schemaHandler.Schema_IsPositional(param.schema)) { + return true; + } + return !!param?.language?.['cli']?.positional; + } + + public Parameter_IsRequired(param: Parameter): boolean { + return param?.required || param?.['targetProperty']?.required; + } + + public Parameter_IsRequiredOrCLIRequired(param: Parameter): boolean { + return this.Parameter_IsRequired(param) || param?.language?.['cli']?.required; + } + + public Parameter_SetAzNameMapsTo(newName: string, param: Parameter): void { + if (!isNullOrUndefined(param['nameBaseParam'])) { + param['nameBaseParam'].subParams[ + this.methodHandler.Method.language['cli'].name + ] = newName; + } + param.language['az'].mapsto = newName; + } + + public Parameter_MapsTo(param: Parameter): string { + if (EXCLUDED_PARAMS.indexOf(param.language['az'].mapsto) > -1) { + param.language['az'].mapsto = 'gen_' + param.language['az'].mapsto; + } + return param.language['az'].mapsto; + } + + public Parameter_SubMapsTo(subMethodName: string, param: Parameter) { + if (!isNullOrUndefined(param?.['subParams']?.[subMethodName])) { + return param['subParams'][subMethodName]; + } + return this.Parameter_MapsTo(param); + } + + public Parameter_Type(param: Parameter): string { + return this.schemaHandler.Schema_Type(param?.schema); + } + + public Parameter_IsFlattened(param: Parameter): boolean { + return !!param.flattened; + } + + public Parameter_IsShorthandSyntax(param: Parameter): boolean { + return !!param.language['cli']?.shorthandSyntax; + } + + public Parameter_IsCliFlattened(param: Parameter): boolean { + if ( + param?.language?.['cli']?.['cli-flattened'] && + !param.language['cli']['cli-m4-flattened'] + ) { + if (param['nameBaseParam']?.language?.['cli']?.['cli-m4-flattened']) { + return false; + } + return true; + } + return false; + } + + public Parameter_IsListOfSimple(param: Parameter): boolean { + // objects that is not base class of polymorphic and satisfy one of the four conditions + // 1. objects with simple properties + // 2. or objects with arrays as properties but has simple element type + // 3. or arrays with simple element types + // 4. or arrays with object element types but has simple properties + // 5. or dicts with simple element properties + // 6. or dicts with arrays as element properties but has simple element type + if (this.Parameter_Type(param) === SchemaType.Any) { + return false; + } + if (this.Parameter_IsFlattened(param)) { + return false; + } + if (param.language['cli'].json === true) { + return false; + } + return this.schemaHandler.Schema_IsListOfSimple(param.schema); + } + + public Parameter_IsList(param: Parameter): boolean { + if (this.Parameter_IsFlattened(param)) { + return false; + } + + if (this.baseHandler.isComplexSchema(this.Parameter_Type(param), param)) { + return true; + } + return false; + } + + public Parameter_PositionalKeys(param: Parameter, subMethodParams: Parameter[]): string[] { + let keys = []; + if (!(this.Parameter_IsList(param) && this.Parameter_IsListOfSimple(param))) { + return null; + } + if ( + !isNullOrUndefined(param.language?.['az']?.positionalKeys) && + Array.isArray(param.language?.['az']?.positionalKeys) + ) { + keys = param.language?.['az']?.positionalKeys; + } + + if ( + keys.length === 0 && + !isNullOrUndefined(param.schema.language?.['cli']?.positionalKeys) && + Array.isArray(param.schema.language?.['cli']?.positionalKeys) + ) { + keys = param.schema.language?.['cli']?.positionalKeys; + } + + const allPossibleKeys = []; + const requiredKeys = []; + for (const subMethodParam of subMethodParams) { + if (subMethodParam['readOnly']) { + continue; + } + if (subMethodParam.schema?.type === SchemaType.Constant) { + continue; + } + allPossibleKeys.push(this.Parameter_NamePython(subMethodParam)); + if (subMethodParam.required || subMethodParam.language?.['cli'].required) { + if (!this.Parameter_IsHidden(subMethodParam)) { + requiredKeys.push(this.Parameter_NamePython(subMethodParam)); + } + } + } + + const coveredResult = keys.every((val) => allPossibleKeys.includes(val)); + const requiredCovered = requiredKeys.every((val) => keys.includes(val)); + + if (keys.length > 0) { + if (coveredResult && requiredCovered) { + return keys; + } else { + let text = ''; + if (!coveredResult) { + text += + 'The defined positional keys for ' + + this.Parameter_CliKey(param) + + ' contains invalid keys. All possible keys are: ' + + allPossibleKeys.join(', ') + + ' \n'; + } + if (!requiredCovered) { + text += + 'The defined positional keys for ' + + this.Parameter_CliKey(param) + + " doesn't contain all required keys. All required keys are: " + + requiredKeys.join(', ') + + ' \n'; + } + this.baseHandler.session.message({ Channel: Channel.Fatal, Text: text }); + return null; + } + } + + return allPossibleKeys; + } + + public Parameter_IsPolyOfSimple(param: Parameter): boolean { + if (!isNullOrUndefined(param['isPolyOfSimple'])) { + return param['isPolyOfSimple']; + } + if ( + param?.schema?.type === SchemaType.Object && + !isNullOrUndefined(param.schema['children']) && + !isNullOrUndefined(param.schema['discriminator']) + ) { + let isSimplePoly = true; + for (const child of param.schema['children'].all) { + if ( + this.schemaHandler.Schema_IsList(child) && + this.schemaHandler.Schema_IsListOfSimple(child) + ) { + continue; + } + isSimplePoly = false; + break; + } + if (isSimplePoly) { + param['isPolyOfSimple'] = true; + } else { + param['isPolyOfSimple'] = false; + } + return isSimplePoly; + } + return false; + } + + public Parameter_IsSimpleArray(param: Parameter): boolean { + if (this.Parameter_Type(param) === SchemaType.Array) { + const elementType = param.schema['elementType'].type; + if (!this.baseHandler.isComplexSchema(elementType, param.schema)) { + return true; + } + } + return false; + } +} diff --git a/src/generate/codemodel/Schema.ts b/src/generate/codemodel/Schema.ts new file mode 100644 index 000000000..11d322b81 --- /dev/null +++ b/src/generate/codemodel/Schema.ts @@ -0,0 +1,185 @@ +import { SchemaType, Schema, Parameter } from '@azure-tools/codemodel'; +import { values } from '@azure-tools/linq'; +import { isNullOrUndefined } from '../../utils/helper'; +import { CodeModelCliImpl } from './CodeModelAzImpl'; + +export interface SchemaModel { + Schema_MapsTo(Schema); + Schema_Type(Schema): string; + Schema_Description(Schema): string; + Schema_FlattenedFrom(Schema): Schema; + Schema_IsPositional(Schema): boolean; + Schema_IsListOfSimple(schema: Schema): boolean; + Schema_IsList(schema: Schema): boolean; +} + +export class SchemaModelImpl implements SchemaModel { + constructor(public baseHandler: CodeModelCliImpl) {} + public Schema_IsListOfSimple(schema: Schema): boolean { + // objects that is not base class of polymorphic and satisfy one of the four conditions + // 1. objects with simple properties + // 2. or objects with arrays as properties but has simple element type + // 3. or arrays with simple element types + // 4. or arrays with object element types but has simple properties + // 5. or dicts with simple element properties + // 6. or dicts with arrays as element properties but has simple element type + if (this.Schema_Type(schema) === SchemaType.Any) { + return false; + } + if (schema?.language?.['cli']?.json === true) { + return false; + } + if (this.Schema_Type(schema) === SchemaType.Array) { + if ( + schema['elementType'].type === SchemaType.Object || + schema['elementType'].type === SchemaType.Dictionary + ) { + for (const p of values(schema['elementType']?.properties)) { + if (p['readOnly']) { + continue; + } + if ( + p['schema'].type === SchemaType.Object || + p['schema'].type === SchemaType.Dictionary + ) { + return false; + } else if (p['schema'].type === SchemaType.Array) { + if ( + this.baseHandler.isComplexSchema( + p['schema']?.elementType?.type, + p['schema'], + ) + ) { + return false; + } + for (const mp of values(p['schema']?.elementType?.properties)) { + if (this.baseHandler.isComplexSchema(mp['schema'].type, mp['schema'])) { + return false; + } + } + for (const parent of values(p['schema']?.elementType?.parents?.all)) { + for (const pp of values(parent['properties'])) { + if ( + this.baseHandler.isComplexSchema( + pp['schema'].type, + pp['schema'], + ) + ) { + return false; + } + } + } + } else if (this.baseHandler.isComplexSchema(p['schema'].type, p['schema'])) { + return false; + } + } + return true; + } + } else if (this.Schema_Type(schema) === SchemaType.Object) { + if ( + !isNullOrUndefined(schema['children']) && + !isNullOrUndefined(schema['discriminator']) + ) { + return false; + } + for (const p of values(schema['properties'])) { + if (p['readOnly']) { + continue; + } + if ( + p['schema'].type === SchemaType.Object || + p['schema'].type === SchemaType.Dictionary + ) { + // objects.objects + return false; + } else if (p['schema'].type === SchemaType.Array) { + for (const mp of values(p['schema']?.elementType?.properties)) { + if (this.baseHandler.isComplexSchema(mp['schema'].type, mp['schema'])) { + return false; + } + } + for (const parent of values(p['schema']?.elementType?.parents?.all)) { + for (const pp of values(parent['properties'])) { + if (this.baseHandler.isComplexSchema(pp['schema'].type, pp['schema'])) { + return false; + } + } + } + } else if (this.baseHandler.isComplexSchema(p['schema'].type, p['schema'])) { + // objects.objects + return false; + } + } + return true; + } else if (this.Schema_Type(schema) === SchemaType.Dictionary) { + if ( + !isNullOrUndefined(schema['children']) && + !isNullOrUndefined(schema['discriminator']) + ) { + return false; + } + const p = schema['elementType']; + if (p.type === SchemaType.Object || p.type === SchemaType.Dictionary) { + // dicts.objects or dicts.dictionaries + return false; + } else if (p.type === SchemaType.Array) { + for (const mp of values(p.properties)) { + if (mp['readOnly']) { + continue; + } + if (this.baseHandler.isComplexSchema(mp['schema'].type, mp['schema'])) { + return false; + } + } + for (const parent of values(p.schema?.elementType?.parents?.all)) { + for (const pp of values(parent['properties'])) { + if (pp['readOnly']) { + continue; + } + if (this.baseHandler.isComplexSchema(pp['schema'].type, pp['schema'])) { + return false; + } + } + } + } else if (this.baseHandler.isComplexSchema(p.type, p)) { + // dicts.objects or dicts.dictionaries + return false; + } + return true; + } + return false; + } + + public Schema_IsList(schema: Schema): boolean { + if (schema.language['cli'].json === true) { + return true; + } + if (this.baseHandler.isComplexSchema(this.Schema_Type(schema), schema)) { + return true; + } + return false; + } + + public Schema_Description(schema: Schema): string { + return schema.language['az'].description?.replace(/\r?\n|\r/g, ' '); + } + + public Schema_FlattenedFrom(schema: Schema): Schema { + return schema?.language['cli']?.pythonFlattenedFrom; + } + + public Schema_IsPositional(schema: Schema): boolean { + return schema?.language?.['cli']?.positional; + } + + public Schema_MapsTo(schema: Schema): string { + return schema.language['az'].mapsto; + } + + public Schema_Type(schema: Schema): string { + if (isNullOrUndefined(schema)) { + return undefined; + } + return schema.type; + } +} diff --git a/src/generate/generators/Base.ts b/src/generate/generators/Base.ts index 32b1985f8..db8566953 100644 --- a/src/generate/generators/Base.ts +++ b/src/generate/generators/Base.ts @@ -4,10 +4,11 @@ *-------------------------------------------------------------------------------------------- */ import * as fs from 'fs'; import * as path from 'path'; -import { CodeModelAz } from '../CodeModelAz'; +import { CodeModelAz } from '../codemodel/CodeModelAz'; import { TemplateBase } from '../renders/TemplateBase'; import { inplaceGen } from '../../utils/inplace'; import { AzConfiguration, CodeGenConstants, TemplateRender } from '../../utils/models'; +import { CodeModelCliImpl } from '../codemodel/CodeModelAzImpl'; export abstract class GeneratorBase { model: CodeModelAz; @@ -15,11 +16,14 @@ export abstract class GeneratorBase { azDirectory: string; isDebugMode: boolean; templates: TemplateRender[]; + azOutputFolder: string; constructor(model: CodeModelAz) { this.model = model; this.azDirectory = ''; this.isDebugMode = AzConfiguration.getValue(CodeGenConstants.debug); + const { configHandler } = model.GetHandler(); + this.azOutputFolder = configHandler.azOutputFolder; } public abstract generateAll(): Promise; @@ -31,7 +35,7 @@ export abstract class GeneratorBase { ): Promise { if ( override !== false || - !fs.existsSync(path.join(this.model.azOutputFolder, template.relativePath)) + !fs.existsSync(path.join(this.azOutputFolder, template.relativePath)) ) { const genContent = await template.fullGeneration(); if (template.skip) { @@ -39,7 +43,7 @@ export abstract class GeneratorBase { } if (inplace) { this.files[template.relativePath] = inplaceGen( - this.model.azOutputFolder, + this.azOutputFolder, template.relativePath, genContent, ); @@ -54,9 +58,9 @@ export abstract class GeneratorBase { inplace = false, ): Promise { let base = ''; - if (fs.existsSync(path.join(this.model.azOutputFolder, template.relativePath))) { + if (fs.existsSync(path.join(this.azOutputFolder, template.relativePath))) { base = fs - .readFileSync(path.join(this.model.azOutputFolder, template.relativePath)) + .readFileSync(path.join(this.azOutputFolder, template.relativePath)) .toString(); } const genContent = await template.incrementalGeneration(base); @@ -65,7 +69,7 @@ export abstract class GeneratorBase { } if (inplace) { this.files[template.relativePath] = inplaceGen( - this.model.azOutputFolder, + this.azOutputFolder, template.relativePath, genContent, ); diff --git a/src/generate/generators/CoreFull.ts b/src/generate/generators/CoreFull.ts index 035c076f6..538b0ae9e 100644 --- a/src/generate/generators/CoreFull.ts +++ b/src/generate/generators/CoreFull.ts @@ -2,7 +2,7 @@ import * as path from 'path'; import { SystemType, PathConstants, AzConfiguration, CodeGenConstants } from '../../utils/models'; import { thoughtAsTrue } from '../../utils/helper'; import { GeneratorBase } from './Base'; -import { CodeModelAz } from '../CodeModelAz'; +import { CodeModelAz } from '../codemodel/CodeModelAz'; import { GenerateNamespaceInit } from '../renders/CliNamespaceInit'; import { CliReport } from '../renders/CliReport'; import { CliTopAction } from '../renders/CliTopAction'; @@ -26,11 +26,11 @@ import { GenerateMetaFile } from '../renders/CliMeta'; import { CliCmdletTest } from '../renders/tests/CliTestCmdlet'; import { SimpleTemplate } from '../renders/TemplateBase'; import { CliActions } from '../renders/generated/CliActions'; +import { config } from 'process'; export class AzCoreFullGenerator extends GeneratorBase { constructor(model: CodeModelAz) { super(model); - this.azDirectory = model.AzureCliFolder; } private getParam() { @@ -39,37 +39,37 @@ export class AzCoreFullGenerator extends GeneratorBase { public async generateAll() { const { model, isDebugMode, files } = this.getParam(); + const { extensionHandler, configHandler, exampleHandler } = model.GetHandler(); if (model.SelectFirstExtension()) { do { files[ - path.join(model.azOutputFolder, 'generated/_params.py') + path.join(configHandler.azOutputFolder, 'generated/_params.py') ] = GenerateAzureCliParams(model, isDebugMode); files[ - path.join(model.azOutputFolder, 'generated/custom.py') + path.join(configHandler.azOutputFolder, 'generated/custom.py') ] = GenerateAzureCliCustom(model); files[ - path.join(model.azOutputFolder, 'generated/_client_factory.py') + path.join(configHandler.azOutputFolder, 'generated/_client_factory.py') ] = GenerateAzureCliClientFactory(model); files[ - path.join(model.azOutputFolder, 'generated/_validators.py') + path.join(configHandler.azOutputFolder, 'generated/_validators.py') ] = GenerateAzureCliValidators(model); files[ - path.join(model.azOutputFolder, 'generated/__init__.py') + path.join(configHandler.azOutputFolder, 'generated/__init__.py') ] = GenerateNamespaceInit(model); - files[path.join(model.azOutputFolder, 'generated/_help.py')] = GenerateAzureCliHelp( - model, - isDebugMode, - ); files[ - path.join(model.azOutputFolder, 'tests/latest/__init__.py') + path.join(configHandler.azOutputFolder, 'generated/_help.py') + ] = GenerateAzureCliHelp(model, isDebugMode); + files[ + path.join(configHandler.azOutputFolder, 'tests/latest/__init__.py') ] = GenerateNamespaceInit(model); - if (model.SDK_NeedSDK) { + if (configHandler.SDK_NeedSDK) { files[ - path.join(model.azOutputFolder, 'vendored_sdks/__init__.py') + path.join(configHandler.azOutputFolder, 'vendored_sdks/__init__.py') ] = GenerateNamespaceInit(model); } files[ - path.join(model.azOutputFolder, 'manual/__init__.py') + path.join(configHandler.azOutputFolder, 'manual/__init__.py') ] = GenerateNamespaceInit(model); await this.generateFullSingleAndAddtoOutput(new CliActions(model)); await this.generateFullSingleAndAddtoOutput(new CliCommands(model)); @@ -82,7 +82,7 @@ export class AzCoreFullGenerator extends GeneratorBase { const requirementGenerator = new CliMainRequirement(model); for (const sys of [SystemType.Darwin, SystemType.Linux, SystemType.windows]) { requirementGenerator.relativePath = path.join( - model.AzureCliFolder, + configHandler.AzureCliFolder, '/src/azure-cli/requirements.py3.' + sys + '.txt', ); files[ @@ -93,14 +93,14 @@ export class AzCoreFullGenerator extends GeneratorBase { await this.generateFullSingleAndAddtoOutput(new CliTestInit(model)); await this.generateFullSingleAndAddtoOutput(new CliTestStep(model), true, true); - for (const testGroup of model.Extension_TestScenario - ? Object.getOwnPropertyNames(model.Extension_TestScenario) + for (const testGroup of exampleHandler.Example_TestScenario + ? Object.getOwnPropertyNames(exampleHandler.Example_TestScenario) : []) { await this.generateFullSingleAndAddtoOutput( new CliTestScenario( model, PathConstants.fullTestSceanrioFile(testGroup), - model.Extension_TestScenario[testGroup], + exampleHandler.Example_TestScenario[testGroup], testGroup, ), true, @@ -115,12 +115,12 @@ export class AzCoreFullGenerator extends GeneratorBase { true, ); } - model + exampleHandler .GetResourcePool() .generateArmTemplate( files, path.join( - model.azOutputFolder, + configHandler.azOutputFolder, PathConstants.testFolder, PathConstants.latestFolder, ), @@ -140,7 +140,7 @@ export class AzCoreFullGenerator extends GeneratorBase { new SimpleTemplate( this.model, path.join( - model.AzextFolder, + configHandler.AzextFolder, PathConstants.testFolder, PathConstants.cmdletFolder, PathConstants.conftestFile, diff --git a/src/generate/generators/CoreIncre.ts b/src/generate/generators/CoreIncre.ts index 793fb2db4..56ebda5c9 100644 --- a/src/generate/generators/CoreIncre.ts +++ b/src/generate/generators/CoreIncre.ts @@ -7,7 +7,7 @@ import * as path from 'path'; import { SystemType, PathConstants, AzConfiguration, CodeGenConstants } from '../../utils/models'; import { thoughtAsTrue } from '../../utils/helper'; import { GeneratorBase } from './Base'; -import { CodeModelAz } from '../CodeModelAz'; +import { CodeModelAz } from '../codemodel/CodeModelAz'; import { GenerateNamespaceInit } from '../renders/CliNamespaceInit'; import { CliReport } from '../renders/CliReport'; import { CliTopAction } from '../renders/CliTopAction'; @@ -46,6 +46,7 @@ export class AzCoreIncrementalGenerator extends GeneratorBase { } public async generateAll(): Promise { + const { extensionHandler, configHandler, exampleHandler } = this.model.GetHandler(); // generated and test folder this.files[ path.join(PathConstants.generatedFolder, PathConstants.paramsFile) @@ -72,7 +73,7 @@ export class AzCoreIncrementalGenerator extends GeneratorBase { ] = GenerateNamespaceInit(this.model); // vendor sdk folder - if (this.model.SDK_NeedSDK) { + if (configHandler.SDK_NeedSDK) { this.files[ path.join(PathConstants.vendoredskdsFolder, PathConstants.initFile) ] = GenerateNamespaceInit(this.model); @@ -96,11 +97,13 @@ export class AzCoreIncrementalGenerator extends GeneratorBase { const cliTopActionGenerator = new CliTopAction(this.model); let cliTopActionBase = ''; if ( - fs.existsSync(path.join(this.model.azOutputFolder, cliTopActionGenerator.relativePath)) + fs.existsSync( + path.join(configHandler.azOutputFolder, cliTopActionGenerator.relativePath), + ) ) { cliTopActionBase = fs .readFileSync( - path.join(this.model.azOutputFolder, cliTopActionGenerator.relativePath), + path.join(configHandler.azOutputFolder, cliTopActionGenerator.relativePath), ) .toString(); } @@ -114,7 +117,7 @@ export class AzCoreIncrementalGenerator extends GeneratorBase { const cliRequirement = new CliMainRequirement(this.model); for (const sys of [SystemType.Darwin, SystemType.Linux, SystemType.windows]) { cliRequirement.relativePath = path.join( - this.model.AzureCliFolder, + configHandler.AzureCliFolder, '/src/azure-cli/requirements.py3.' + sys + '.txt', ); this.files[cliRequirement.relativePath] = await cliRequirement.incrementalGeneration( @@ -124,14 +127,14 @@ export class AzCoreIncrementalGenerator extends GeneratorBase { await this.generateIncrementalSingleAndAddtoOutput(new CliTestInit(this.model)); await this.generateIncrementalSingleAndAddtoOutput(new CliTestStep(this.model), true); - for (const testGroup of this.model.Extension_TestScenario - ? Object.getOwnPropertyNames(this.model.Extension_TestScenario) + for (const testGroup of exampleHandler.Example_TestScenario + ? Object.getOwnPropertyNames(exampleHandler.Example_TestScenario) : []) { await this.generateIncrementalSingleAndAddtoOutput( new CliTestScenario( this.model, PathConstants.incTestScenarioFile(testGroup), - this.model.Extension_TestScenario[testGroup], + exampleHandler.Example_TestScenario[testGroup], testGroup, ), true, @@ -144,12 +147,12 @@ export class AzCoreIncrementalGenerator extends GeneratorBase { true, ); } - this.model + exampleHandler .GetResourcePool() .generateArmTemplate( this.files, path.join( - this.model.azOutputFolder, + configHandler.azOutputFolder, PathConstants.testFolder, PathConstants.latestFolder, ), @@ -166,7 +169,7 @@ export class AzCoreIncrementalGenerator extends GeneratorBase { new SimpleTemplate( this.model, path.join( - this.model.AzextFolder, + configHandler.AzextFolder, PathConstants.testFolder, PathConstants.cmdletFolder, PathConstants.conftestFile, diff --git a/src/generate/generators/ExtensionFull.ts b/src/generate/generators/ExtensionFull.ts index 156a7b790..8eb6480c6 100644 --- a/src/generate/generators/ExtensionFull.ts +++ b/src/generate/generators/ExtensionFull.ts @@ -6,7 +6,7 @@ import * as path from 'path'; import { PathConstants, AzConfiguration, CodeGenConstants } from '../../utils/models'; import { thoughtAsTrue } from '../../utils/helper'; import { GeneratorBase } from './Base'; -import { CodeModelAz } from '../CodeModelAz'; +import { CodeModelAz } from '../codemodel/CodeModelAz'; import { GenerateNamespaceInit } from '../renders/CliNamespaceInit'; import { CliTopAction } from '../renders/CliTopAction'; import { CliTopCustom } from '../renders/CliTopCustom'; @@ -35,10 +35,12 @@ import { SimpleTemplate } from '../renders/TemplateBase'; export class AzExtensionFullGenerator extends GeneratorBase { constructor(model: CodeModelAz) { super(model); - this.azDirectory = model.AzextFolder; + const { configHandler } = model.GetHandler(); + this.azDirectory = configHandler.AzextFolder; } public async generateAll(): Promise { + const { extensionHandler, configHandler, exampleHandler } = this.model.GetHandler(); this.files[path.join(this.azDirectory, 'generated/_params.py')] = GenerateAzureCliParams( this.model, this.isDebugMode, @@ -68,7 +70,7 @@ export class AzExtensionFullGenerator extends GeneratorBase { this.model, ); - if (this.model.SDK_NeedSDK) { + if (configHandler.SDK_NeedSDK) { this.files[ path.join(this.azDirectory, 'vendored_sdks/__init__.py') ] = GenerateNamespaceInit(this.model); @@ -88,14 +90,14 @@ export class AzExtensionFullGenerator extends GeneratorBase { await this.generateFullSingleAndAddtoOutput(new CliTestInit(this.model)); await this.generateFullSingleAndAddtoOutput(new CliTestStep(this.model), true, true); - for (const testGroup of this.model.Extension_TestScenario - ? Object.getOwnPropertyNames(this.model.Extension_TestScenario) + for (const testGroup of exampleHandler.Example_TestScenario + ? Object.getOwnPropertyNames(exampleHandler.Example_TestScenario) : []) { await this.generateFullSingleAndAddtoOutput( new CliTestScenario( this.model, PathConstants.fullTestSceanrioFile(testGroup), - this.model.Extension_TestScenario[testGroup], + exampleHandler.Example_TestScenario[testGroup], testGroup, ), true, @@ -110,7 +112,7 @@ export class AzExtensionFullGenerator extends GeneratorBase { true, ); } - this.model + exampleHandler .GetResourcePool() .generateArmTemplate( this.files, @@ -129,7 +131,7 @@ export class AzExtensionFullGenerator extends GeneratorBase { new SimpleTemplate( this.model, path.join( - this.model.AzextFolder, + configHandler.AzextFolder, PathConstants.testFolder, PathConstants.cmdletFolder, PathConstants.conftestFile, diff --git a/src/generate/generators/ExtensionIncre.ts b/src/generate/generators/ExtensionIncre.ts index fe9375c72..b9949d14d 100644 --- a/src/generate/generators/ExtensionIncre.ts +++ b/src/generate/generators/ExtensionIncre.ts @@ -7,7 +7,7 @@ import * as path from 'path'; import { PathConstants, AzConfiguration, CodeGenConstants } from '../../utils/models'; import { thoughtAsTrue } from '../../utils/helper'; import { GeneratorBase } from './Base'; -import { CodeModelAz } from '../CodeModelAz'; +import { CodeModelAz } from '../codemodel/CodeModelAz'; import { GenerateNamespaceInit } from '../renders/CliNamespaceInit'; import { CliTopAction } from '../renders/CliTopAction'; import { CliTopCustom } from '../renders/CliTopCustom'; @@ -30,14 +30,17 @@ import { CliTestStep, NeedPreparers } from '../renders/tests/CliTestStep'; import { GenerateMetaFile } from '../renders/CliMeta'; import { CliCmdletTest } from '../renders/tests/CliTestCmdlet'; import { SimpleTemplate } from '../renders/TemplateBase'; +import { clearConfigCache } from 'prettier'; export class AzExtensionIncrementalGenerator extends GeneratorBase { constructor(model: CodeModelAz) { super(model); - this.azDirectory = model.AzextFolder; + const { configHandler } = model.GetHandler(); + this.azDirectory = configHandler.AzextFolder; } public async generateAll(): Promise { + const { extensionHandler, configHandler, exampleHandler } = this.model.GetHandler(); this.files[ path.join(this.azDirectory, PathConstants.generatedFolder, PathConstants.paramsFile) ] = GenerateAzureCliParams(this.model, this.isDebugMode); @@ -65,7 +68,7 @@ export class AzExtensionIncrementalGenerator extends GeneratorBase { path.join(this.azDirectory, PathConstants.manualFolder, PathConstants.initFile) ] = GenerateNamespaceInit(this.model); - if (this.model.SDK_NeedSDK) { + if (configHandler.SDK_NeedSDK) { this.files[ path.join( this.azDirectory, @@ -92,11 +95,13 @@ export class AzExtensionIncrementalGenerator extends GeneratorBase { const cliTopActionGenerator = new CliTopAction(this.model); let cliTopActionBase = ''; if ( - fs.existsSync(path.join(this.model.azOutputFolder, cliTopActionGenerator.relativePath)) + fs.existsSync( + path.join(configHandler.azOutputFolder, cliTopActionGenerator.relativePath), + ) ) { cliTopActionBase = fs .readFileSync( - path.join(this.model.azOutputFolder, cliTopActionGenerator.relativePath), + path.join(configHandler.azOutputFolder, cliTopActionGenerator.relativePath), ) .toString(); } @@ -111,14 +116,14 @@ export class AzExtensionIncrementalGenerator extends GeneratorBase { await this.generateIncrementalSingleAndAddtoOutput(new CliTestInit(this.model)); await this.generateIncrementalSingleAndAddtoOutput(new CliTestStep(this.model), true); - for (const testGroup of this.model.Extension_TestScenario - ? Object.getOwnPropertyNames(this.model.Extension_TestScenario) + for (const testGroup of exampleHandler.Example_TestScenario + ? Object.getOwnPropertyNames(exampleHandler.Example_TestScenario) : []) { await this.generateIncrementalSingleAndAddtoOutput( new CliTestScenario( this.model, PathConstants.incTestScenarioFile(testGroup), - this.model.Extension_TestScenario[testGroup], + exampleHandler.Example_TestScenario[testGroup], testGroup, ), true, @@ -131,7 +136,7 @@ export class AzExtensionIncrementalGenerator extends GeneratorBase { true, ); } - this.model + exampleHandler .GetResourcePool() .generateArmTemplate( this.files, @@ -149,7 +154,7 @@ export class AzExtensionIncrementalGenerator extends GeneratorBase { new SimpleTemplate( this.model, path.join( - this.model.AzextFolder, + configHandler.AzextFolder, PathConstants.testFolder, PathConstants.cmdletFolder, PathConstants.conftestFile, diff --git a/src/generate/generators/Factory.ts b/src/generate/generators/Factory.ts index 3f2fd784f..a1f20c333 100644 --- a/src/generate/generators/Factory.ts +++ b/src/generate/generators/Factory.ts @@ -9,18 +9,19 @@ import { AzCoreIncrementalGenerator } from './CoreIncre'; import { AzExtensionFullGenerator } from './ExtensionFull'; import { AzExtensionIncrementalGenerator } from './ExtensionIncre'; import { GeneratorBase } from './Base'; -import { CodeModelCliImpl } from '../CodeModelAzImpl'; +import { CodeModelCliImpl } from '../codemodel/CodeModelAzImpl'; export class AzGeneratorFactory { static createAzGenerator(model: CodeModelCliImpl): GeneratorBase { - if (model.CliGenerationMode === GenerationMode.Full) { - if (model.IsCliCore) { + const { configHandler } = model.GetHandler(); + if (configHandler.CliGenerationMode === GenerationMode.Full) { + if (configHandler.IsCliCore) { return new AzCoreFullGenerator(model); } else { return new AzExtensionFullGenerator(model); } } else { - if (model.IsCliCore) { + if (configHandler.IsCliCore) { return new AzCoreIncrementalGenerator(model); } else { return new AzExtensionIncrementalGenerator(model); diff --git a/src/generate/renders/CliMeta.ts b/src/generate/renders/CliMeta.ts index 00edd6ea7..6281f73c0 100644 --- a/src/generate/renders/CliMeta.ts +++ b/src/generate/renders/CliMeta.ts @@ -3,11 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *-------------------------------------------------------------------------------------------- */ -import { CodeModelAz } from '../CodeModelAz'; +import { CodeModelAz } from '../codemodel/CodeModelAz'; import { putToZip } from '../../utils/inplace'; export function GenerateMetaFile(model: CodeModelAz) { - const output: string[] = JSON.stringify(model.GetMetaData(), null, 2).split('\n'); + const { configHandler, exampleHandler } = model.GetHandler(); + const output: string[] = JSON.stringify(exampleHandler.GetMetaData(), null, 2).split('\n'); - putToZip(model.azOutputFolder, 'meta.txt', output); + putToZip(configHandler.azOutputFolder, 'meta.txt', output); } diff --git a/src/generate/renders/CliNamespaceInit.ts b/src/generate/renders/CliNamespaceInit.ts index 4d88cb1d5..38992f218 100644 --- a/src/generate/renders/CliNamespaceInit.ts +++ b/src/generate/renders/CliNamespaceInit.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *-------------------------------------------------------------------------------------------- */ -import { CodeModelAz } from '../CodeModelAz'; +import { CodeModelAz } from '../codemodel/CodeModelAz'; export function GenerateNamespaceInit(model: CodeModelAz): string[] { const output: string[] = []; diff --git a/src/generate/renders/CliReport.ts b/src/generate/renders/CliReport.ts index e0973f379..db2f7059b 100644 --- a/src/generate/renders/CliReport.ts +++ b/src/generate/renders/CliReport.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *-------------------------------------------------------------------------------------------- */ -import { CodeModelAz } from '../CodeModelAz'; +import { CodeModelAz } from '../codemodel/CodeModelAz'; import * as path from 'path'; import { SchemaType } from '@azure-tools/codemodel'; import { @@ -15,6 +15,7 @@ import { } from '../../utils/models'; import { TemplateBase } from './TemplateBase'; import { isNullOrUndefined, ToMultiLine } from '../../utils/helper'; +import { CommandGroupModelImpl } from '../codemodel/CommandGroup'; export class CliReport extends TemplateBase { constructor(model: CodeModelAz) { @@ -87,6 +88,7 @@ export class CliReport extends TemplateBase { } GenerateAzureCliReport(model: CodeModelAz): string[] { + const { extensionHandler, commandGroupHandler } = model.GetHandler(); let output: string[] = []; output.push('# Azure CLI Module Creation Report'); @@ -94,12 +96,12 @@ export class CliReport extends TemplateBase { output.push('## EXTENSION'); output.push('|CLI Extension|Command Groups|'); output.push('|---------|------------|'); - output.push('|az ' + model.Extension_Name + '|[groups](#CommandGroups)'); + output.push('|az ' + extensionHandler.Extension_Name + '|[groups](#CommandGroups)'); output.push(''); output.push('## GROUPS'); output.push( '### Command groups in `az ' + - model.Extension_Name + + extensionHandler.Extension_Name + '` extension ', ); output.push('|CLI Command Group|Group Swagger name|Commands|'); @@ -110,12 +112,12 @@ export class CliReport extends TemplateBase { do { output.push( '|az ' + - model.CommandGroup_Name + + commandGroupHandler.CommandGroup_Name + '|' + - model.CommandGroup_CliKey + + commandGroupHandler.CommandGroup_CliKey + '|' + '[commands](#CommandsIn' + - model.CommandGroup_CliKey + + commandGroupHandler.CommandGroup_CliKey + ')|', ); } while (model.SelectNextCommandGroup()); @@ -129,10 +131,12 @@ export class CliReport extends TemplateBase { do { if (model.SelectFirstCommand()) { mo = this.getCommandBody(model); - if (!isNullOrUndefined(cmds[model.CommandGroup_Name])) { - cmds[model.CommandGroup_Name] = cmds[model.CommandGroup_Name].concat(mo); + if (!isNullOrUndefined(cmds[commandGroupHandler.CommandGroup_Name])) { + cmds[commandGroupHandler.CommandGroup_Name] = cmds[ + commandGroupHandler.CommandGroup_Name + ].concat(mo); } else { - cmds[model.CommandGroup_Name] = mo; + cmds[commandGroupHandler.CommandGroup_Name] = mo; } } } while (model.SelectNextCommandGroup()); @@ -156,10 +160,12 @@ export class CliReport extends TemplateBase { do { if (model.SelectFirstCommand()) { mo = this.getCommandDetails(model); - if (!isNullOrUndefined(cmds[model.CommandGroup_Name])) { - cmds[model.CommandGroup_Name] = cmds[model.CommandGroup_Name].concat(mo); + if (!isNullOrUndefined(cmds[commandGroupHandler.CommandGroup_Name])) { + cmds[commandGroupHandler.CommandGroup_Name] = cmds[ + commandGroupHandler.CommandGroup_Name + ].concat(mo); } else { - cmds[model.CommandGroup_Name] = mo; + cmds[commandGroupHandler.CommandGroup_Name] = mo; } } } while (model.SelectNextCommandGroup()); @@ -174,12 +180,13 @@ export class CliReport extends TemplateBase { } getCommandBody(model: CodeModelAz) { + const { commandGroupHandler, methodHandler, exampleHandler } = model.GetHandler(); const mo: string[] = []; mo.push( '### Commands in `az ' + - model.CommandGroup_Name + + commandGroupHandler.CommandGroup_Name + '` group', ); mo.push('|CLI Command|Operation Swagger name|Parameters|Examples|'); @@ -188,43 +195,43 @@ export class CliReport extends TemplateBase { do { if (model.SelectFirstMethod()) { do { - if (model.GetExamples(false).length > 0) { + if (exampleHandler.GetExamples(false).length > 0) { mo.push( '|[az ' + - model.CommandGroup_Name + + commandGroupHandler.CommandGroup_Name + ' ' + - model.Method_NameAz + + methodHandler.Method_NameAz + '](#' + - model.CommandGroup_CliKey + - model.Method_CliKey + + commandGroupHandler.CommandGroup_CliKey + + methodHandler.Method_CliKey + ')|' + - model.Method_CliKey + + methodHandler.Method_CliKey + '|' + '[Parameters](#Parameters' + - model.CommandGroup_CliKey + - model.Method_CliKey + + commandGroupHandler.CommandGroup_CliKey + + methodHandler.Method_CliKey + ')' + '|' + '[Example](#Examples' + - model.CommandGroup_CliKey + - model.Method_CliKey + + commandGroupHandler.CommandGroup_CliKey + + methodHandler.Method_CliKey + ')|', ); } else { mo.push( '|[az ' + - model.CommandGroup_Name + + commandGroupHandler.CommandGroup_Name + ' ' + - model.Method_NameAz + + methodHandler.Method_NameAz + '](#' + - model.CommandGroup_CliKey + - model.Method_CliKey + + commandGroupHandler.CommandGroup_CliKey + + methodHandler.Method_CliKey + ')|' + - model.Method_CliKey + + methodHandler.Method_CliKey + '|' + '[Parameters](#Parameters' + - model.CommandGroup_CliKey + - model.Method_CliKey + + commandGroupHandler.CommandGroup_CliKey + + methodHandler.Method_CliKey + ')' + '|Not Found|', ); @@ -238,8 +245,15 @@ export class CliReport extends TemplateBase { } getCommandDetails(model: CodeModelAz) { + const { + commandGroupHandler, + methodHandler, + methodParameterHandler, + parameterHandler, + exampleHandler, + } = model.GetHandler(); let mo: string[] = []; - mo.push('### group `az ' + model.CommandGroup_Name + '`'); + mo.push('### group `az ' + commandGroupHandler.CommandGroup_Name + '`'); if (model.SelectFirstCommand()) { do { const allRequiredParam: Map = new Map(); @@ -250,26 +264,26 @@ export class CliReport extends TemplateBase { do { mo.push( '#### Command `az ' + - model.CommandGroup_Name + + commandGroupHandler.CommandGroup_Name + ' ' + - model.Method_NameAz + + methodHandler.Method_NameAz + '`', ); mo.push(''); - for (const example of model.GetExamples(false)) { + for (const example of exampleHandler.GetExamples(false)) { mo.push( '##### Example', ); mo.push('```'); let parameters: string[] = []; - parameters = model.GetExampleItems(example, false, undefined); + parameters = exampleHandler.GetExampleItems(example, false, undefined); const line = parameters.join(' '); ToMultiLine(line, mo, CodeGenConstants.PYLINT_MAX_CODE_LENGTH, true); mo.push('```'); @@ -277,8 +291,8 @@ export class CliReport extends TemplateBase { mo.push( '##### Parameters ', ); mo.push('|Option|Type|Description|Path (SDK)|Swagger name|'); @@ -286,29 +300,34 @@ export class CliReport extends TemplateBase { if (!model.SelectFirstMethodParameter()) { continue; } - const originalOperation = model.Method_GetOriginalOperation; + const originalOperation = methodHandler.Method_GetOriginalOperation; do { if ( - model.MethodParameter_IsFlattened || - model.MethodParameter_Type === SchemaType.Constant + methodParameterHandler.MethodParameter_IsFlattened || + methodParameterHandler.MethodParameter_Type === SchemaType.Constant ) { continue; } - if (model.Parameter_IsPolyOfSimple(model.MethodParameter)) { + if ( + parameterHandler.Parameter_IsPolyOfSimple( + methodParameterHandler.MethodParameter, + ) + ) { continue; } if ( !isNullOrUndefined(originalOperation) && - model.MethodParameter['targetProperty']?.isDiscriminator + methodParameterHandler.MethodParameter['targetProperty'] + ?.isDiscriminator ) { continue; } - let optionName = model.MethodParameter_MapsTo; + let optionName = methodParameterHandler.MethodParameter_MapsTo; if (optionName.endsWith('_')) { optionName = optionName.substr(0, optionName.length - 1); } optionName = optionName.replace(/_/g, '-'); - if (model.MethodParameter_IsRequired) { + if (methodParameterHandler.MethodParameter_IsRequired) { if (allRequiredParam.has(optionName)) { continue; } @@ -317,13 +336,13 @@ export class CliReport extends TemplateBase { '|**--' + optionName + '**|' + - model.MethodParameter_Type + + methodParameterHandler.MethodParameter_Type + '|' + - model.MethodParameter_Description + + methodParameterHandler.MethodParameter_Description + '|' + - model.MethodParameter_Name + + methodParameterHandler.MethodParameter_Name + '|' + - model.MethodParameter_CliKey + + methodParameterHandler.MethodParameter_CliKey + '|', ); } else { @@ -335,13 +354,13 @@ export class CliReport extends TemplateBase { '|**--' + optionName + '**|' + - model.MethodParameter_Type + + methodParameterHandler.MethodParameter_Type + '|' + - model.MethodParameter_Description + + methodParameterHandler.MethodParameter_Description + '|' + - model.MethodParameter_Name + + methodParameterHandler.MethodParameter_Name + '|' + - model.MethodParameter_CliKey + + methodParameterHandler.MethodParameter_CliKey + '|', ); } diff --git a/src/generate/renders/CliTopAction.ts b/src/generate/renders/CliTopAction.ts index b1c91a474..8982908a0 100644 --- a/src/generate/renders/CliTopAction.ts +++ b/src/generate/renders/CliTopAction.ts @@ -12,19 +12,21 @@ import { isNullOrUndefined, } from '../../utils/helper'; import { GenerationMode, PathConstants } from '../../utils/models'; -import { CodeModelAz } from '../CodeModelAz'; +import { CodeModelAz } from '../codemodel/CodeModelAz'; import { HeaderGenerator } from './Header'; import { TemplateBase } from './TemplateBase'; +import { config } from 'process'; export class CliTopAction extends TemplateBase { constructor(model: CodeModelAz) { super(model); - this.relativePath = path.join(model.AzextFolder, PathConstants.actionFile); + const { configHandler } = model.GetHandler(); + this.relativePath = path.join(configHandler.AzextFolder, PathConstants.actionFile); const relativePathOldVersion = this.relativePath.replace( PathConstants.actionFile, PathConstants.actionFileOldVersion, ); - if (fs.existsSync(path.join(model.azOutputFolder, relativePathOldVersion))) { + if (fs.existsSync(path.join(configHandler.azOutputFolder, relativePathOldVersion))) { this.relativePath = relativePathOldVersion; } } diff --git a/src/generate/renders/CliTopCustom.ts b/src/generate/renders/CliTopCustom.ts index 05f9d60ab..54536c30d 100644 --- a/src/generate/renders/CliTopCustom.ts +++ b/src/generate/renders/CliTopCustom.ts @@ -11,14 +11,15 @@ import { isNullOrUndefined, } from '../../utils/helper'; import { GenerationMode, PathConstants } from '../../utils/models'; -import { CodeModelAz } from '../CodeModelAz'; +import { CodeModelAz } from '../codemodel/CodeModelAz'; import { HeaderGenerator } from './Header'; import { TemplateBase } from './TemplateBase'; export class CliTopCustom extends TemplateBase { constructor(model: CodeModelAz) { super(model); - this.relativePath = path.join(model.AzextFolder, PathConstants.customFile); + const { configHandler } = model.GetHandler(); + this.relativePath = path.join(configHandler.AzextFolder, PathConstants.customFile); } public async fullGeneration(): Promise { diff --git a/src/generate/renders/CliTopHelp.ts b/src/generate/renders/CliTopHelp.ts index e749e8302..c15742aa6 100644 --- a/src/generate/renders/CliTopHelp.ts +++ b/src/generate/renders/CliTopHelp.ts @@ -4,6 +4,7 @@ *-------------------------------------------------------------------------------------------- */ import { EOL } from 'os'; import * as path from 'path'; +import { config } from 'process'; import { getIndentString, keepHeaderLines, @@ -11,14 +12,15 @@ import { isNullOrUndefined, } from '../../utils/helper'; import { GenerationMode, PathConstants } from '../../utils/models'; -import { CodeModelAz } from '../CodeModelAz'; +import { CodeModelAz } from '../codemodel/CodeModelAz'; import { HeaderGenerator } from './Header'; import { TemplateBase } from './TemplateBase'; export class CliTopHelp extends TemplateBase { constructor(model: CodeModelAz) { super(model); - this.relativePath = path.join(model.AzextFolder, PathConstants.helpFile); + const { configHandler } = model.GetHandler(); + this.relativePath = path.join(configHandler.AzextFolder, PathConstants.helpFile); } public async fullGeneration(): Promise { diff --git a/src/generate/renders/CliTopInit.ts b/src/generate/renders/CliTopInit.ts index 10f5e803f..5d67e5bc2 100644 --- a/src/generate/renders/CliTopInit.ts +++ b/src/generate/renders/CliTopInit.ts @@ -12,14 +12,15 @@ import { isNullOrUndefined, } from '../../utils/helper'; import { GenerationMode, PathConstants } from '../../utils/models'; -import { CodeModelAz } from '../CodeModelAz'; +import { CodeModelAz } from '../codemodel/CodeModelAz'; import { HeaderGenerator } from './Header'; import { TemplateBase } from './TemplateBase'; export class CliTopInit extends TemplateBase { constructor(model: CodeModelAz) { super(model); - this.relativePath = path.join(model.AzextFolder, PathConstants.initFile); + const { configHandler } = model.GetHandler(); + this.relativePath = path.join(configHandler.AzextFolder, PathConstants.initFile); } public async fullGeneration(): Promise { @@ -127,14 +128,15 @@ export class CliTopInit extends TemplateBase { } private GenerateAzureCliInit(model: CodeModelAz): string[] { + const { configHandler, extensionHandler } = model.GetHandler(); const header: HeaderGenerator = new HeaderGenerator(); - header.addFromImport(model.CliCoreLib, ['AzCommandsLoader']); - if (model.ResourceType) { + header.addFromImport(configHandler.CliCoreLib, ['AzCommandsLoader']); + if (configHandler.ResourceType) { header.addFromImport('azure.cli.core.profiles', ['ResourceType']); } const output: string[] = header.getLines(); - let importPath = model.AzextFolder; - if (!model.IsCliCore) { + let importPath = configHandler.AzextFolder; + if (!configHandler.IsCliCore) { output.push( 'from ' + importPath + @@ -157,33 +159,43 @@ export class CliTopInit extends TemplateBase { } output.push(''); - output.push('class ' + model.Extension_NameClass + 'CommandsLoader(AzCommandsLoader):'); + output.push( + 'class ' + extensionHandler.Extension_NameClass + 'CommandsLoader(AzCommandsLoader):', + ); output.push(''); output.push(' def __init__(self, cli_ctx=None):'); - output.push(' from ' + model.CliCoreLib + '.commands import CliCommandType'); + output.push(' from ' + configHandler.CliCoreLib + '.commands import CliCommandType'); output.push( ' from ' + importPath + '.generated._client_factory import cf_' + - model.Extension_NameUnderscored + + extensionHandler.Extension_NameUnderscored + '_cl', ); - output.push(' ' + model.Extension_NameUnderscored + '_custom = CliCommandType('); - if (model.IsCliCore) { + output.push( + ' ' + extensionHandler.Extension_NameUnderscored + '_custom = CliCommandType(', + ); + if (configHandler.IsCliCore) { output.push( " operations_tmpl='azure.cli.command_modules." + - model.Extension_NameUnderscored + + extensionHandler.Extension_NameUnderscored + ".custom#{}',", ); } else { - output.push(" operations_tmpl='" + model.AzextFolder + ".custom#{}',"); + output.push( + " operations_tmpl='" + configHandler.AzextFolder + ".custom#{}',", + ); } - output.push(' client_factory=cf_' + model.Extension_NameUnderscored + '_cl)'); - output.push(` parent = super(${model.Extension_NameClass}CommandsLoader, self)`); + output.push( + ' client_factory=cf_' + extensionHandler.Extension_NameUnderscored + '_cl)', + ); + output.push( + ` parent = super(${extensionHandler.Extension_NameClass}CommandsLoader, self)`, + ); ToMultiLine( ` parent.__init__(cli_ctx=cli_ctx, custom_command_type=${ - model.Extension_NameUnderscored - }_custom${composeParamString(undefined, undefined, model.ResourceType)[0]})`, + extensionHandler.Extension_NameUnderscored + }_custom${composeParamString(undefined, undefined, configHandler.ResourceType)[0]})`, output, ); output.push(''); @@ -221,7 +233,9 @@ export class CliTopInit extends TemplateBase { output.push(' raise e'); output.push(''); output.push(''); - output.push('COMMAND_LOADER_CLS = ' + model.Extension_NameClass + 'CommandsLoader'); + output.push( + 'COMMAND_LOADER_CLS = ' + extensionHandler.Extension_NameClass + 'CommandsLoader', + ); output.push(''); return output; diff --git a/src/generate/renders/TemplateBase.ts b/src/generate/renders/TemplateBase.ts index 1f5d035b7..569078d75 100644 --- a/src/generate/renders/TemplateBase.ts +++ b/src/generate/renders/TemplateBase.ts @@ -2,7 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *-------------------------------------------------------------------------------------------- */ -import { CodeModelAz } from '../CodeModelAz'; +import { CodeModelAz } from '../codemodel/CodeModelAz'; import * as nunjucks from 'nunjucks'; import { AzConfiguration, CodeGenConstants } from '../../utils/models'; diff --git a/src/generate/renders/extraExt/CliExtHistory.ts b/src/generate/renders/extraExt/CliExtHistory.ts index dab9c1795..7ab49139a 100644 --- a/src/generate/renders/extraExt/CliExtHistory.ts +++ b/src/generate/renders/extraExt/CliExtHistory.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *-------------------------------------------------------------------------------------------- */ -import { CodeModelAz } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import * as path from 'path'; import { TemplateBase } from '../TemplateBase'; import { PathConstants } from '../../../utils/models'; diff --git a/src/generate/renders/extraExt/CliExtMetadata.ts b/src/generate/renders/extraExt/CliExtMetadata.ts index bd5b9579f..1d1d240e4 100644 --- a/src/generate/renders/extraExt/CliExtMetadata.ts +++ b/src/generate/renders/extraExt/CliExtMetadata.ts @@ -6,13 +6,14 @@ import { EOL } from 'os'; import * as path from 'path'; import { isNullOrUndefined } from '../../../utils/helper'; import { AzextMetadata, CodeGenConstants, PathConstants } from '../../../utils/models'; -import { CodeModelAz } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { TemplateBase } from '../TemplateBase'; export class CliTopMetadata extends TemplateBase { constructor(model: CodeModelAz) { + const { configHandler } = model.GetHandler(); super(model); - this.relativePath = path.join(model.AzextFolder, PathConstants.metadataFile); + this.relativePath = path.join(configHandler.AzextFolder, PathConstants.metadataFile); this.tmplPath = path.join( PathConstants.templateRootFolder, 'azext', @@ -41,9 +42,10 @@ export class CliTopMetadata extends TemplateBase { } public async GetRenderData(model: CodeModelAz): Promise { + const { extensionHandler } = model.GetHandler(); const data = { model: { - Extension_Mode: model.Extension_Mode, + Extension_Mode: extensionHandler.Extension_Mode, minCliCoreVersion: CodeGenConstants.minCliCoreVersion, }, }; diff --git a/src/generate/renders/extraExt/CliExtReadme.ts b/src/generate/renders/extraExt/CliExtReadme.ts index 9cd976fbd..ed8fd0692 100644 --- a/src/generate/renders/extraExt/CliExtReadme.ts +++ b/src/generate/renders/extraExt/CliExtReadme.ts @@ -5,8 +5,9 @@ import { HttpMethod } from '@azure-tools/codemodel'; import { CmdToMultiLines, isNullOrUndefined } from '../../../utils/helper'; import { PathConstants } from '../../../utils/models'; -import { CodeModelAz, CommandExample } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { TemplateBase } from '../TemplateBase'; +import { CommandExample } from '../../codemodel/Example'; export class CliExtReadme extends TemplateBase { constructor(model: CodeModelAz) { @@ -15,28 +16,29 @@ export class CliExtReadme extends TemplateBase { } public async fullGeneration(): Promise { + const { extensionHandler, commandGroupHandler, exampleHandler } = this.model.GetHandler(); let output: string[] = []; - output.push('# Azure CLI ' + this.model.Extension_Name + ' Extension #'); - output.push('This is the extension for ' + this.model.Extension_Name); + output.push('# Azure CLI ' + extensionHandler.Extension_Name + ' Extension #'); + output.push('This is the extension for ' + extensionHandler.Extension_Name); output.push(''); output.push('### How to use ###'); output.push('Install this extension using the below CLI command'); output.push('```'); - output.push('az extension add --name ' + this.model.Extension_Name); + output.push('az extension add --name ' + extensionHandler.Extension_Name); output.push('```'); output.push(''); output.push('### Included Features ###'); if (this.model.SelectFirstCommandGroup()) { do { - output.push('#### ' + this.model.CommandGroup_Name + ' ####'); + output.push('#### ' + commandGroupHandler.CommandGroup_Name + ' ####'); let exampleList: CommandExample[] = []; const exampleCommandList: string[] = []; if (this.model.SelectFirstCommand()) { do { - exampleList = exampleList.concat(this.model.GetExamples(false)); + exampleList = exampleList.concat(exampleHandler.GetExamples(false)); } while (this.model.SelectNextCommand()); } @@ -62,7 +64,7 @@ export class CliExtReadme extends TemplateBase { const temp = CmdToMultiLines(example.CommandString); exampleCommandList.push(...temp); } - const waitCommandString = this.model.GetExampleWait(example).join(' '); + const waitCommandString = exampleHandler.GetExampleWait(example).join(' '); if (!isNullOrUndefined(waitCommandString) && waitCommandString !== '') { exampleCommandList.push(''); const temp = CmdToMultiLines(waitCommandString); diff --git a/src/generate/renders/extraExt/CliExtSetupCfg.ts b/src/generate/renders/extraExt/CliExtSetupCfg.ts index 3ccddd43e..f65cc933e 100644 --- a/src/generate/renders/extraExt/CliExtSetupCfg.ts +++ b/src/generate/renders/extraExt/CliExtSetupCfg.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *-------------------------------------------------------------------------------------------- */ -import { CodeModelAz } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import * as path from 'path'; import { TemplateBase } from '../TemplateBase'; import { PathConstants } from '../../../utils/models'; diff --git a/src/generate/renders/extraExt/CliExtSetupPy.ts b/src/generate/renders/extraExt/CliExtSetupPy.ts index c61c05d40..65b3c261e 100644 --- a/src/generate/renders/extraExt/CliExtSetupPy.ts +++ b/src/generate/renders/extraExt/CliExtSetupPy.ts @@ -5,7 +5,7 @@ import { EOL } from 'os'; import { getLatestPyPiVersion, isNullOrUndefined } from '../../../utils/helper'; import { CodeGenConstants, GenerationMode, PathConstants } from '../../../utils/models'; -import { CodeModelAz } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { HeaderGenerator } from '../Header'; import { TemplateBase } from '../TemplateBase'; import compareVersions = require('compare-versions'); @@ -84,32 +84,33 @@ export class CliExtSetupPy extends TemplateBase { } public async GetRenderData(model: CodeModelAz): Promise { + const { extensionHandler, configHandler } = this.model.GetHandler(); const dependencies = []; - if (!model.SDK_NeedSDK) { - const packageName = model.GetPythonPackageName(); + if (!configHandler.SDK_NeedSDK) { + const packageName = configHandler.GetPythonPackageName(); const latestVersion = await getLatestPyPiVersion(packageName); const line = packageName + '~=' + latestVersion; dependencies.push(line); } - let azRelativeOutputFolder = path.resolve(model.azOutputFolder); - if (!isNullOrUndefined(model.AzureCliFolder)) { + let azRelativeOutputFolder = path.resolve(configHandler.azOutputFolder); + if (!isNullOrUndefined(configHandler.AzureCliFolder)) { azRelativeOutputFolder = azRelativeOutputFolder.replace( - path.join(path.resolve(model.AzureCliFolder), '/'), + path.join(path.resolve(configHandler.AzureCliFolder), '/'), '', ); - } else if (!isNullOrUndefined(model.AzureCliExtFolder)) { + } else if (!isNullOrUndefined(configHandler.AzureCliExtFolder)) { azRelativeOutputFolder = azRelativeOutputFolder.replace( - path.join(path.resolve(model.AzureCliExtFolder), '/'), + path.join(path.resolve(configHandler.AzureCliExtFolder), '/'), '', ); } const data = { model: { - AzextFolder: model.AzextFolder, - Extension_Name: model.Extension_Name, + AzextFolder: configHandler.AzextFolder, + Extension_Name: extensionHandler.Extension_Name, azRelativeOutputFolder: azRelativeOutputFolder.replace(/\\/g, '/'), - Extension_NameClass: model.Extension_NameClass, - Extension_NameUnderscored: model.Extension_NameUnderscored, + Extension_NameClass: extensionHandler.Extension_NameClass, + Extension_NameUnderscored: extensionHandler.Extension_NameUnderscored, dependencies: dependencies, }, }; diff --git a/src/generate/renders/extraMain/CliMainDocSourceJsonMap.ts b/src/generate/renders/extraMain/CliMainDocSourceJsonMap.ts index f5b718a96..cda1cfee6 100644 --- a/src/generate/renders/extraMain/CliMainDocSourceJsonMap.ts +++ b/src/generate/renders/extraMain/CliMainDocSourceJsonMap.ts @@ -6,15 +6,20 @@ import * as fs from 'fs'; import { EOL } from 'os'; import * as path from 'path'; +import { clearConfigCache } from 'prettier'; import { isNullOrUndefined } from '../../../utils/helper'; import { PathConstants } from '../../../utils/models'; -import { CodeModelAz } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { TemplateBase } from '../TemplateBase'; export class CliMainDocSourceJsonMap extends TemplateBase { constructor(model: CodeModelAz) { + const { configHandler } = model.GetHandler(); super(model); - this.relativePath = path.join(model.AzureCliFolder, PathConstants.docSourceJsonFile); + this.relativePath = path.join( + configHandler.AzureCliFolder, + PathConstants.docSourceJsonFile, + ); } public async fullGeneration(): Promise { @@ -26,14 +31,15 @@ export class CliMainDocSourceJsonMap extends TemplateBase { } private GenerateDocSourceJsonMap(model: CodeModelAz, docSourceJsonMapPath): string[] { + const { extensionHandler } = this.model.GetHandler(); const outputFile = fs.readFileSync(docSourceJsonMapPath).toString().split(EOL); const docSourceJson = JSON.parse(fs.readFileSync(docSourceJsonMapPath).toString()); - if (isNullOrUndefined(docSourceJson[model.Extension_NameUnderscored])) { + if (isNullOrUndefined(docSourceJson[extensionHandler.Extension_NameUnderscored])) { const line = '"' + - model.Extension_Name + + extensionHandler.Extension_Name + '": "src/azure-cli/azure/cli/command_modules/' + - model.Extension_Name + + extensionHandler.Extension_Name + '/_help.py"'; let cnt = outputFile.length; let foundLastLine = false; diff --git a/src/generate/renders/extraMain/CliMainRequirement.ts b/src/generate/renders/extraMain/CliMainRequirement.ts index 8c6773618..0d6b18a1c 100644 --- a/src/generate/renders/extraMain/CliMainRequirement.ts +++ b/src/generate/renders/extraMain/CliMainRequirement.ts @@ -6,7 +6,7 @@ import * as fs from 'fs'; import { EOL } from 'os'; import { getLatestPyPiVersion } from '../../../utils/helper'; -import { CodeModelAz } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { TemplateBase } from '../TemplateBase'; export class CliMainRequirement extends TemplateBase { @@ -23,13 +23,14 @@ export class CliMainRequirement extends TemplateBase { } private async GenerateRequirementTxt(model: CodeModelAz, requirementPath) { + const { configHandler } = this.model.GetHandler(); const outputFile = fs.readFileSync(requirementPath).toString().split(EOL); - const latestVersion = await getLatestPyPiVersion(model.GetPythonPackageName()); + const latestVersion = await getLatestPyPiVersion(configHandler.GetPythonPackageName()); let found = false; - const line = model.GetPythonPackageName() + '==' + latestVersion; + const line = configHandler.GetPythonPackageName() + '==' + latestVersion; for (const dependency of outputFile) { - if (dependency.indexOf(model.GetPythonPackageName() + '==') > -1) { + if (dependency.indexOf(configHandler.GetPythonPackageName() + '==') > -1) { found = true; break; } diff --git a/src/generate/renders/extraMain/CliMainSetupPy.ts b/src/generate/renders/extraMain/CliMainSetupPy.ts index 842e95304..42949492e 100644 --- a/src/generate/renders/extraMain/CliMainSetupPy.ts +++ b/src/generate/renders/extraMain/CliMainSetupPy.ts @@ -8,13 +8,14 @@ import { EOL } from 'os'; import * as path from 'path'; import { getLatestPyPiVersion } from '../../../utils/helper'; import { PathConstants } from '../../../utils/models'; -import { CodeModelAz } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { TemplateBase } from '../TemplateBase'; export class CliMainSetupPy extends TemplateBase { constructor(model: CodeModelAz) { super(model); - this.relativePath = path.join(model.AzureCliFolder, PathConstants.mainSetupPyFile); + const { configHandler } = this.model.GetHandler(); + this.relativePath = path.join(configHandler.AzureCliFolder, PathConstants.mainSetupPyFile); } public async fullGeneration(): Promise { @@ -26,8 +27,9 @@ export class CliMainSetupPy extends TemplateBase { } private async GenerateAzureCliMainSetUp(model: CodeModelAz, requirementPath) { + const { configHandler } = this.model.GetHandler(); const outputFile = fs.readFileSync(requirementPath).toString().split(EOL); - const packageName = model.GetPythonPackageName(); + const packageName = configHandler.GetPythonPackageName(); const latestVersion = await getLatestPyPiVersion(packageName); let found = false; let cnt = 0; diff --git a/src/generate/renders/generated/CliActions.ts b/src/generate/renders/generated/CliActions.ts index 2c82013a1..a2970c0f7 100644 --- a/src/generate/renders/generated/CliActions.ts +++ b/src/generate/renders/generated/CliActions.ts @@ -5,7 +5,7 @@ import { Parameter, SchemaType } from '@azure-tools/codemodel'; import { ToPythonString, ToMultiLine, isNullOrUndefined } from '../../../utils/helper'; -import { CodeModelAz } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { HeaderGenerator } from '../Header'; import { TemplateBase } from '../TemplateBase'; import * as path from 'path'; @@ -16,8 +16,9 @@ let allActions: Map; export class CliActions extends TemplateBase { constructor(model: CodeModelAz) { super(model); + const { configHandler } = this.model.GetHandler(); this.relativePath = path.join( - model.AzextFolder, + configHandler.AzextFolder, PathConstants.generatedFolder, PathConstants.actionFile, ); diff --git a/src/generate/renders/generated/CliClientFactory.ts b/src/generate/renders/generated/CliClientFactory.ts index 1e9cc5609..edd1bb772 100644 --- a/src/generate/renders/generated/CliClientFactory.ts +++ b/src/generate/renders/generated/CliClientFactory.ts @@ -3,51 +3,56 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *-------------------------------------------------------------------------------------------- */ -import { CodeModelAz } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { HeaderGenerator } from '../Header'; import { isNullOrUndefined } from '../../../utils/helper'; export function GenerateAzureCliClientFactory(model: CodeModelAz): string[] { const header: HeaderGenerator = new HeaderGenerator(); + const { extensionHandler, configHandler } = model.GetHandler(); const output: string[] = header.getLines(); model.SelectFirstCommandGroup(true); output.push(''); output.push(''); - output.push('def cf_' + model.Extension_NameUnderscored + '_cl(cli_ctx, *_):'); + output.push('def cf_' + extensionHandler.Extension_NameUnderscored + '_cl(cli_ctx, *_):'); output.push( - ' from ' + model.CliCoreLib + '.commands.client_factory import get_mgmt_service_client', + ' from ' + + configHandler.CliCoreLib + + '.commands.client_factory import get_mgmt_service_client', + ); + output.push( + ' from ' + configHandler.GetPythonNamespace() + ' import ' + model.PythonMgmtClient, ); - output.push(' from ' + model.GetPythonNamespace() + ' import ' + model.PythonMgmtClient); - if (!isNullOrUndefined(model.Extension_ClientAuthenticationPolicy)) { + if (!isNullOrUndefined(extensionHandler.Extension_ClientAuthenticationPolicy)) { output.push( ' from azure.core.pipeline.policies import ' + - model.Extension_ClientAuthenticationPolicy, + extensionHandler.Extension_ClientAuthenticationPolicy, ); } // Start handle arguments output.push(' return get_mgmt_service_client(cli_ctx,'); output.push(' ' + model.PythonMgmtClient); - if (!isNullOrUndefined(model.Extension_ClientSubscriptionBound)) { + if (!isNullOrUndefined(extensionHandler.Extension_ClientSubscriptionBound)) { output.push(output.pop() + ','); output.push( ' subscription_bound=' + - (model.Extension_ClientSubscriptionBound ? 'True' : 'False'), + (extensionHandler.Extension_ClientSubscriptionBound ? 'True' : 'False'), ); } - if (!isNullOrUndefined(model.Extension_ClientBaseUrlBound)) { + if (!isNullOrUndefined(extensionHandler.Extension_ClientBaseUrlBound)) { output.push(output.pop() + ','); output.push( ' base_url_bound=' + - (model.Extension_ClientBaseUrlBound ? 'True' : 'False'), + (extensionHandler.Extension_ClientBaseUrlBound ? 'True' : 'False'), ); } - if (!isNullOrUndefined(model.Extension_ClientAuthenticationPolicy)) { + if (!isNullOrUndefined(extensionHandler.Extension_ClientAuthenticationPolicy)) { output.push(output.pop() + ','); output.push( ' authentication_policy=' + - model.Extension_ClientAuthenticationPolicy + + extensionHandler.Extension_ClientAuthenticationPolicy + '()', ); } @@ -63,7 +68,7 @@ export function GenerateAzureCliClientFactory(model: CodeModelAz): string[] { output.push('def cf_' + model.GetModuleOperationName() + '(cli_ctx, *_):'); output.push( ' return cf_' + - model.Extension_NameUnderscored + + extensionHandler.Extension_NameUnderscored + '_cl(cli_ctx).' + model.GetModuleOperationNamePython(), ); diff --git a/src/generate/renders/generated/CliCommands.ts b/src/generate/renders/generated/CliCommands.ts index 8f0dd355f..588d814fa 100644 --- a/src/generate/renders/generated/CliCommands.ts +++ b/src/generate/renders/generated/CliCommands.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *-------------------------------------------------------------------------------------------- */ -import { CodeModelAz } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { isNullOrUndefined } from '../../../utils/helper'; import { TemplateBase } from '../TemplateBase'; import { @@ -17,6 +17,7 @@ import { import * as path from 'path'; export class CliCommands extends TemplateBase { private importProfile = false; + private imports: Map = new Map(); private importClientFactories = []; private lineTooLong = false; private needWaitCommand = false; @@ -27,8 +28,9 @@ export class CliCommands extends TemplateBase { constructor(model: CodeModelAz) { super(model); + const { configHandler } = this.model.GetHandler(); this.relativePath = path.join( - model.AzextFolder, + configHandler.AzextFolder, PathConstants.generatedFolder, PathConstants.commandsFile, ); @@ -43,6 +45,19 @@ export class CliCommands extends TemplateBase { return `'${str}'`; } + addImport(importKey: string, importValues: string[]) { + let list = []; + if (this.imports.has(importKey)) { + list = this.imports.get(importKey); + } + importValues.forEach((val) => { + if (list.indexOf(val) === -1) { + list.push(val); + } + }); + this.imports.set(importKey, importValues); + } + extensionConverter(item: any): any { if (!isNullOrUndefined(item['parent']) && !isNullOrUndefined(item['name'])) { item['name'] = item['parent'] + ' ' + item['name']; @@ -57,6 +72,20 @@ export class CliCommands extends TemplateBase { item['propertiesString'][prop] = this.pythonString(item[prop]); } }); + if (!isNullOrUndefined(item['features'])) { + Object.keys(item['features']).forEach((prop: string) => { + item['propertiesString'][prop] = item['features'][prop]; + }); + } + if (!isNullOrUndefined(item['imports'])) { + Object.keys(item['imports']).forEach((prop: string) => { + if (typeof item['imports'][prop] === 'string') { + this.addImport(prop, [item['imports'][prop]]); + } else if (Array.isArray(item['imports'][prop])) { + this.addImport(prop, item['imports'][prop]); + } + }); + } this.extraNonStringProperties.forEach((prop) => { if (!isNullOrUndefined(item[prop])) { item['propertiesString'][prop] = item[prop]; @@ -93,6 +122,20 @@ export class CliCommands extends TemplateBase { item['propertiesString'][prop] = this.pythonString(item[prop]); } }); + if (!isNullOrUndefined(item['features'])) { + Object.keys(item['features']).forEach((prop: string) => { + item['propertiesString'][prop] = item['features'][prop]; + }); + } + if (!isNullOrUndefined(item['imports'])) { + Object.keys(item['imports']).forEach((prop: string) => { + if (typeof item['imports'][prop] === 'string') { + this.addImport(prop, [item['imports'][prop]]); + } else if (Array.isArray(item['imports'][prop])) { + this.addImport(prop, item['imports'][prop]); + } + }); + } this.extraNonStringProperties.forEach((prop) => { if (!isNullOrUndefined(item[prop])) { item['propertiesString'][prop] = item[prop]; @@ -131,8 +174,9 @@ export class CliCommands extends TemplateBase { } public async GetRenderData(): Promise> { + const { configHandler } = this.model.GetHandler(); let data = { imports: [], pylints: [] }; - data['imports'].push([this.model.CliCoreLib + '.commands', ['CliCommandType']]); + this.addImport(configHandler.CliCoreLib + '.commands', ['CliCommandType']); const inputProperties: Map = new Map< CodeModelTypes, @@ -162,6 +206,8 @@ export class CliCommands extends TemplateBase { 'resourceType', 'mode', 'hasCommand', + 'features', + 'imports', ], { name: SortOrder.ASEC }, [], @@ -184,6 +230,8 @@ export class CliCommands extends TemplateBase { 'needGeneric', 'genericSetterArgName', 'clientFactoryName', + 'features', + 'imports', ], {}, [], @@ -198,17 +246,17 @@ export class CliCommands extends TemplateBase { ]; data = { ...data, ...this.model.getModelData('extension', inputProperties, dependencies) }; if (this.importProfile) { - data['imports'].push([this.model.CliCoreLib + '.profiles', ['ResourceType']]); + this.addImport(configHandler.CliCoreLib + '.profiles', ['ResourceType']); } if ( !isNullOrUndefined(this.importClientFactories) && Array.isArray(this.importClientFactories) && this.importClientFactories.length > 0 ) { - data['imports'].push([ - this.model.AzextFolder + '.generated._client_factory', + this.addImport( + configHandler.AzextFolder + '.generated._client_factory', this.importClientFactories, - ]); + ); } data['pylints'].push( '# pylint: disable=too-many-statements', @@ -218,7 +266,8 @@ export class CliCommands extends TemplateBase { if (this.lineTooLong) { data['pylints'].push('# pylint: disable=line-too-long'); } - data['azextFolder'] = this.model.AzextFolder; + data['azextFolder'] = configHandler.AzextFolder; + data.imports = Array.from(this.imports); const result = { data: { imports: [], pylints: [] } }; result.data = data; return result; diff --git a/src/generate/renders/generated/CliCustom.ts b/src/generate/renders/generated/CliCustom.ts index acb7dcc65..377164cf4 100644 --- a/src/generate/renders/generated/CliCustom.ts +++ b/src/generate/renders/generated/CliCustom.ts @@ -4,6 +4,7 @@ *-------------------------------------------------------------------------------------------- */ import { Operation, Parameter, SchemaType } from '@azure-tools/codemodel'; +import { config } from 'process'; import { Capitalize, ToCamelCase, @@ -12,11 +13,12 @@ import { isNullOrUndefined, } from '../../../utils/helper'; import { CodeGenConstants } from '../../../utils/models'; -import { CodeModelAz } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { HeaderGenerator } from '../Header'; let allParams = []; export function GenerateAzureCliCustom(model: CodeModelAz): string[] { + const { configHandler } = model.GetHandler(); const header: HeaderGenerator = new HeaderGenerator(); header.disableTooManyLines = true; @@ -36,7 +38,7 @@ export function GenerateAzureCliCustom(model: CodeModelAz): string[] { } if (required.nowait) { - header.addFromImport(model.CliCoreLib + '.util', ['sdk_no_wait']); + header.addFromImport(configHandler.CliCoreLib + '.util', ['sdk_no_wait']); } if (required.disableUnusedArgument) { @@ -65,12 +67,13 @@ class CustomParam { } function getCustomParam(model: CodeModelAz, required: any) { - const originalOperation = model.Method_GetOriginalOperation; + const { methodHandler } = model.GetHandler(); + const originalOperation = methodHandler.Method_GetOriginalOperation; let genericParameter = null; if (!isNullOrUndefined(originalOperation)) { - genericParameter = model.Method_GenericSetterParameter(originalOperation); + genericParameter = methodHandler.Method_GenericSetterParameter(originalOperation); } - const needGeneric = model.Method_NeedGeneric; + const needGeneric = methodHandler.Method_NeedGeneric; if (needGeneric) { required.disableUnusedArgument = true; } @@ -97,8 +100,15 @@ function GenerateBody(model: CodeModelAz, required: any): string[] { } function ConstructMethodBodyParameter(model: CodeModelAz, needGeneric = false, required: any) { + const { + methodHandler, + methodParameterHandler, + configHandler, + schemaHandler, + parameterHandler, + } = model.GetHandler(); let outputBody: string[] = []; - const opNames = model.Method_NameAz.split(' '); + const opNames = methodHandler.Method_NameAz.split(' '); let valueToMatch = null; if (opNames.length > 1) { valueToMatch = Capitalize(ToCamelCase(opNames[0])); @@ -115,35 +125,45 @@ function ConstructMethodBodyParameter(model: CodeModelAz, needGeneric = false, r skip = false; } if ( - (model.MethodParameter_IsCliFlattened && - (!isNullOrUndefined(model.MethodParameter.language['cli'].cliFlattenTrace) || - model.SDK_NoFlatten || + (methodParameterHandler.MethodParameter_IsCliFlattened && + (!isNullOrUndefined( + methodParameterHandler.MethodParameter.language['cli'].cliFlattenTrace, + ) || + configHandler.SDK_NoFlatten || !isNullOrUndefined( - model.MethodParameter.extensions?.['cli-poly-as-resource-base-schema'], + methodParameterHandler.MethodParameter.extensions?.[ + 'cli-poly-as-resource-base-schema' + ], ))) || - model.Method.extensions?.['cli-split-operation-original-operation'] - ?.genericSetterParam === model.MethodParameter || - (model.MethodParameter_IsFlattened && - model.MethodParameter.extensions?.['cli-flattened']) + methodHandler.Method.extensions?.['cli-split-operation-original-operation'] + ?.genericSetterParam === methodParameterHandler.MethodParameter || + (methodParameterHandler.MethodParameter_IsFlattened && + methodParameterHandler.MethodParameter.extensions?.['cli-flattened']) ) { while ( - !isNullOrUndefined(model.MethodParameter.language?.['cli']?.cliFlattenTrace) && - model.MethodParameter.language?.['cli']?.cliFlattenTrace?.length < - originalParameterStack.length + !isNullOrUndefined( + methodParameterHandler.MethodParameter.language?.['cli']?.cliFlattenTrace, + ) && + methodParameterHandler.MethodParameter.language?.['cli']?.cliFlattenTrace + ?.length < originalParameterStack.length ) { originalParameterStack.pop(); originalParameterNameStack.pop(); } // This is because splited operation will miss one cliM4Path in its' CLIFlattenTrace if ( - !isNullOrUndefined(model.MethodParameter.language?.['cli']?.cliFlattenTrace) && - model.MethodParameter.language?.['cli']?.cliFlattenTrace?.length === - originalParameterStack.length && + !isNullOrUndefined( + methodParameterHandler.MethodParameter.language?.['cli']?.cliFlattenTrace, + ) && + methodParameterHandler.MethodParameter.language?.['cli']?.cliFlattenTrace + ?.length === originalParameterStack.length && isNullOrUndefined( - model.Method.extensions?.['cli-poly-as-resource-original-operation'], + methodHandler.Method.extensions?.[ + 'cli-poly-as-resource-original-operation' + ], ) && isNullOrUndefined( - model.Method.extensions?.['cli-split-operation-original-operation'], + methodHandler.Method.extensions?.['cli-split-operation-original-operation'], ) ) { originalParameterStack.pop(); @@ -151,14 +171,14 @@ function ConstructMethodBodyParameter(model: CodeModelAz, needGeneric = false, r } if ( originalParameterStack.length === 0 && - allParams.indexOf(model.MethodParameter.schema) === -1 + allParams.indexOf(methodParameterHandler.MethodParameter.schema) === -1 ) { - allParams.push(model.MethodParameter.schema); - originalParameterStack.push(model.MethodParameter); - originalParameterNameStack.push(model.MethodParameter_Name); + allParams.push(methodParameterHandler.MethodParameter.schema); + originalParameterStack.push(methodParameterHandler.MethodParameter); + originalParameterNameStack.push(methodParameterHandler.MethodParameter_Name); } else if (originalParameterStack.length > 0) { - originalParameterStack.push(model.MethodParameter); - originalParameterNameStack.push(model.MethodParameter_Name); + originalParameterStack.push(methodParameterHandler.MethodParameter); + originalParameterNameStack.push(methodParameterHandler.MethodParameter_Name); } else { continue; } @@ -176,19 +196,20 @@ function ConstructMethodBodyParameter(model: CodeModelAz, needGeneric = false, r ); } } else if (originalParameterStack.length > 0) { - const flattenedFrom = model.Schema_FlattenedFrom( - model.MethodParameter['targetProperty'], + const flattenedFrom = schemaHandler.Schema_FlattenedFrom( + methodParameterHandler.MethodParameter['targetProperty'], ); if ( - model.MethodParameter['originalParameter'] === originalParameterStack.last || + methodParameterHandler.MethodParameter['originalParameter'] === + originalParameterStack.last || (!isNullOrUndefined(originalParameterStack.last['nameBaseParam']) && - model.MethodParameter['originalParameter'] === + methodParameterHandler.MethodParameter['originalParameter'] === originalParameterStack.last['nameBaseParam']) || !isNullOrUndefined(flattenedFrom) ) { let access = []; - const paramName = model.Parameter_NamePython( - model.MethodParameter['targetProperty'], + const paramName = parameterHandler.Parameter_NamePython( + methodParameterHandler.MethodParameter['targetProperty'], ); if ( !isNullOrUndefined(flattenedFrom) && @@ -197,12 +218,15 @@ function ConstructMethodBodyParameter(model: CodeModelAz, needGeneric = false, r // If last originalParameter in the stack doesn't have originalParameterStack.last cliM4Path. it means this argument is not flattened from originalParameterStack.last. We should pop the last item out. while ( !isNullOrUndefined( - model.MethodParameter.language?.['cli']?.cliFlattenTrace, + methodParameterHandler.MethodParameter.language?.['cli'] + ?.cliFlattenTrace, ) && !isNullOrUndefined( originalParameterStack.last.language?.['cli']?.cliM4Path, ) && - model.MethodParameter.language?.['cli']?.cliFlattenTrace.indexOf( + methodParameterHandler.MethodParameter.language?.[ + 'cli' + ]?.cliFlattenTrace.indexOf( originalParameterStack.last.language?.['cli']?.cliM4Path, ) === -1 ) { @@ -239,7 +263,10 @@ function ConstructMethodBodyParameter(model: CodeModelAz, needGeneric = false, r } } - if (model.MethodParameter['targetProperty']?.isDiscriminator === true) { + if ( + methodParameterHandler.MethodParameter['targetProperty'] + ?.isDiscriminator === true + ) { if (!isNullOrUndefined(valueToMatch)) { access = ConstructValuation( model, @@ -255,15 +282,17 @@ function ConstructMethodBodyParameter(model: CodeModelAz, needGeneric = false, r } } else { let defaultValue = ToPythonString( - model.MethodParameter_DefaultValue, - model.MethodParameter_Type, + methodParameterHandler.MethodParameter_DefaultValue, + methodParameterHandler.MethodParameter_Type, ); - if (model.MethodParameter_DefaultValue === '{}') { + if (methodParameterHandler.MethodParameter_DefaultValue === '{}') { defaultValue = '{}'; } - if (!model.MethodParameter_IsHidden) { + if (!methodParameterHandler.MethodParameter_IsHidden) { let needIfClause = true; - if (model.MethodParameter_Type === SchemaType.Constant) { + if ( + methodParameterHandler.MethodParameter_Type === SchemaType.Constant + ) { needIfClause = false; } access = ConstructValuation( @@ -273,15 +302,17 @@ function ConstructMethodBodyParameter(model: CodeModelAz, needGeneric = false, r prefixIndent, originalParameterNameStack, paramName, - model.MethodParameter_MapsTo, + methodParameterHandler.MethodParameter_MapsTo, defaultValue, needIfClause, ); - } else if (!isNullOrUndefined(model.MethodParameter_DefaultValue)) { + } else if ( + !isNullOrUndefined(methodParameterHandler.MethodParameter_DefaultValue) + ) { if ( model.isComplexSchema( - model.MethodParameter_Type, - model.MethodParameter, + methodParameterHandler.MethodParameter_Type, + methodParameterHandler.MethodParameter, ) && defaultValue !== '{}' ) { @@ -300,19 +331,27 @@ function ConstructMethodBodyParameter(model: CodeModelAz, needGeneric = false, r } } outputBody = outputBody.concat(access); - if (model.Parameter_IsPolyOfSimple(model.MethodParameter)) { - const baseParam = model.MethodParameter; + if ( + parameterHandler.Parameter_IsPolyOfSimple( + methodParameterHandler.MethodParameter, + ) + ) { + const baseParam = methodParameterHandler.MethodParameter; let hasNext = false; if (model.SelectNextMethodParameter(true)) { hasNext = true; while ( hasNext && - model.MethodParameter['polyBaseParam'] === baseParam + methodParameterHandler.MethodParameter['polyBaseParam'] === + baseParam ) { hasNext = model.SelectNextMethodParameter(true); } } - if (hasNext && model.MethodParameter['polyBaseParam'] !== baseParam) { + if ( + hasNext && + methodParameterHandler.MethodParameter['polyBaseParam'] !== baseParam + ) { skip = true; } } @@ -323,7 +362,8 @@ function ConstructMethodBodyParameter(model: CodeModelAz, needGeneric = false, r // then we need to run construction logic for this parameter one more time. if ( originalParameterStack.length > 0 && - model.MethodParameter['originalParameter'] === originalParameterStack.last + methodParameterHandler.MethodParameter['originalParameter'] === + originalParameterStack.last ) { skip = true; } @@ -391,8 +431,15 @@ function ConstructValuation( } function GetSingleCommandDef(model: CodeModelAz, required: any) { + const { + commandGroupHandler, + commandHandler, + methodHandler, + methodParameterHandler, + parameterHandler, + } = model.GetHandler(); const output: string[] = []; - const updatedMethodName: string = model.Command_FunctionName; + const updatedMethodName: string = commandHandler.Command_FunctionName; let call = 'def ' + updatedMethodName + '('; const indent = ' '.repeat(call.length); @@ -414,41 +461,50 @@ function GetSingleCommandDef(model: CodeModelAz, required: any) { output.push(call); firstLine = true; } - if (model.Method_IsLongRun && model.CommandGroup_HasShowCommand) { + if (methodHandler.Method_IsLongRun && commandGroupHandler.CommandGroup_HasShowCommand) { required.nowait = true; hasLongRun = true; } if (model.SelectFirstMethodParameter()) { do { - if (model.MethodParameter_IsFlattened) { + if (methodParameterHandler.MethodParameter_IsFlattened) { continue; } - if (model.MethodParameter_Type === SchemaType.Constant) { + if (methodParameterHandler.MethodParameter_Type === SchemaType.Constant) { continue; } if ( needGeneric && !isNullOrUndefined(genericParameter) && - model.MethodParameter_MapsTo === model.Parameter_MapsTo(genericParameter) + methodParameterHandler.MethodParameter_MapsTo === + parameterHandler.Parameter_MapsTo(genericParameter) ) { continue; } - if (model.MethodParameter_IsList && !model.MethodParameter_IsListOfSimple) { - if (model.Parameter_IsPolyOfSimple(model.MethodParameter)) { + if ( + methodParameterHandler.MethodParameter_IsList && + !methodParameterHandler.MethodParameter_IsListOfSimple + ) { + if ( + parameterHandler.Parameter_IsPolyOfSimple( + methodParameterHandler.MethodParameter, + ) + ) { continue; } } if ( !isNullOrUndefined(originalOperation) && - model.MethodParameter['targetProperty']?.isDiscriminator + methodParameterHandler.MethodParameter['targetProperty']?.isDiscriminator ) { continue; } - const requiredParam: boolean = model.MethodParameter_RequiredByMethod; + const requiredParam: boolean = + methodParameterHandler.MethodParameter_RequiredByMethod; - const name = model.MethodParameter_MapsTo; // PythonParameterName(element.Name); + const name = methodParameterHandler.MethodParameter_MapsTo; // PythonParameterName(element.Name); if (requiredParam && !allParam.has(name)) { allParam.set(name, true); output[output.length - 1] += ','; @@ -467,37 +523,45 @@ function GetSingleCommandDef(model: CodeModelAz, required: any) { ); if (model.SelectFirstMethodParameter()) { do { - if (model.MethodParameter_IsFlattened) { + if (methodParameterHandler.MethodParameter_IsFlattened) { continue; } - if (model.MethodParameter_Type === SchemaType.Constant) { + if (methodParameterHandler.MethodParameter_Type === SchemaType.Constant) { continue; } if ( needGeneric && !isNullOrUndefined(genericParameter) && - model.MethodParameter_MapsTo === model.Parameter_MapsTo(genericParameter) + methodParameterHandler.MethodParameter_MapsTo === + parameterHandler.Parameter_MapsTo(genericParameter) ) { continue; } - if (model.MethodParameter_IsList && !model.MethodParameter_IsListOfSimple) { - if (model.Parameter_IsPolyOfSimple(model.MethodParameter)) { + if ( + methodParameterHandler.MethodParameter_IsList && + !methodParameterHandler.MethodParameter_IsListOfSimple + ) { + if ( + parameterHandler.Parameter_IsPolyOfSimple( + methodParameterHandler.MethodParameter, + ) + ) { continue; } } if ( !isNullOrUndefined(originalOperation) && - model.MethodParameter['targetProperty']?.isDiscriminator + methodParameterHandler.MethodParameter['targetProperty']?.isDiscriminator ) { continue; } - const requiredParam = model.MethodParameter_RequiredByMethod; + const requiredParam = methodParameterHandler.MethodParameter_RequiredByMethod; - const name = model.MethodParameter_MapsTo; + const name = methodParameterHandler.MethodParameter_MapsTo; if (!requiredParam && !allParam.has(name)) { allParam.set(name, true); output[output.length - 1] += ','; @@ -517,6 +581,7 @@ function GetSingleCommandDef(model: CodeModelAz, required: any) { } function GetSingleCommandBody(model: CodeModelAz, required: any) { + const { methodHandler, methodParameterHandler, parameterHandler } = model.GetHandler(); let originalParameters = null; let output: string[] = []; @@ -550,23 +615,29 @@ function GetSingleCommandBody(model: CodeModelAz, required: any) { if ( needGeneric && !isNullOrUndefined(genericParameter) && - model.MethodParameter_MapsTo === model.Parameter_MapsTo(genericParameter) + methodParameterHandler.MethodParameter_MapsTo === + parameterHandler.Parameter_MapsTo(genericParameter) ) { continue; } if ( - model.MethodParameter_IsList && - !model.MethodParameter_IsListOfSimple && - !model.MethodParameter_IsSimpleArray + methodParameterHandler.MethodParameter_IsList && + !methodParameterHandler.MethodParameter_IsListOfSimple && + !methodParameterHandler.MethodParameter_IsSimpleArray ) { - if (model.Parameter_IsPolyOfSimple(model.MethodParameter)) { - const baseParam = model.MethodParameter; - const baseName = model.MethodParameter_MapsTo; + if ( + parameterHandler.Parameter_IsPolyOfSimple( + methodParameterHandler.MethodParameter, + ) + ) { + const baseParam = methodParameterHandler.MethodParameter; + const baseName = methodParameterHandler.MethodParameter_MapsTo; if (allPolyBaseParam.has(baseName)) { continue; } allPolyBaseParam.set(baseName, true); - const baseRequired = model.MethodParameter_RequiredByMethod; + const baseRequired = + methodParameterHandler.MethodParameter_RequiredByMethod; outputBody.push(' ' + 'all_' + baseName + ' = []'); const childNames = []; let hasNext = false; @@ -575,9 +646,10 @@ function GetSingleCommandBody(model: CodeModelAz, required: any) { } while ( hasNext && - model.MethodParameter['polyBaseParam'] === baseParam + methodParameterHandler.MethodParameter['polyBaseParam'] === + baseParam ) { - const childName = model.MethodParameter_MapsTo; + const childName = methodParameterHandler.MethodParameter_MapsTo; childNames.push(childName); outputBody.push(' if ' + childName + ' is not None:'); outputBody.push( @@ -626,18 +698,20 @@ function GetSingleCommandBody(model: CodeModelAz, required: any) { continue; } } else if ( - model.MethodParameter_DefaultValue !== undefined && - model.MethodParameter_Type !== SchemaType.Constant + methodParameterHandler.MethodParameter_DefaultValue !== undefined && + methodParameterHandler.MethodParameter_Type !== SchemaType.Constant ) { // model is simple type with default value - outputBody.push(' if ' + model.MethodParameter_MapsTo + ' is None:'); + outputBody.push( + ' if ' + methodParameterHandler.MethodParameter_MapsTo + ' is None:', + ); outputBody.push( ' ' + - model.MethodParameter_MapsTo + + methodParameterHandler.MethodParameter_MapsTo + ' = ' + ToPythonString( - model.MethodParameter_DefaultValue, - model.MethodParameter_Type, + methodParameterHandler.MethodParameter_DefaultValue, + methodParameterHandler.MethodParameter_Type, ), ); } @@ -650,7 +724,7 @@ function GetSingleCommandBody(model: CodeModelAz, required: any) { } while (model.SelectNextMethod()); model.SelectFirstMethod(); - const needIfStatement = !model.Method_IsLast; + const needIfStatement = !methodHandler.Method_IsLast; do { const { originalOperation, needGeneric } = getCustomParam(model, required); @@ -659,24 +733,32 @@ function GetSingleCommandBody(model: CodeModelAz, required: any) { let ifStatement = prefix; prefix += ' '; - if (!model.Method_IsLast) { - ifStatement += model.Method_IsFirst ? 'if' : 'elif'; + if (!methodHandler.Method_IsLast) { + ifStatement += methodHandler.Method_IsFirst ? 'if' : 'elif'; if (model.SelectFirstMethodParameter()) { do { - if (!model.MethodParameter_IsRequired) { + if (!methodParameterHandler.MethodParameter_IsRequired) { continue; } - if (model.MethodParameter_Type === SchemaType.Constant) { + if ( + methodParameterHandler.MethodParameter_Type === SchemaType.Constant + ) { continue; } - if (model.MethodParameter_IsFlattened) { + if (methodParameterHandler.MethodParameter_IsFlattened) { continue; } ifStatement += ifStatement.endsWith('if') ? '' : ' and'; - if (model.MethodParameter_MapsTo === 'resource_group_name') { - ifStatement += ' ' + model.MethodParameter_MapsTo; + if ( + methodParameterHandler.MethodParameter_MapsTo === + 'resource_group_name' + ) { + ifStatement += ' ' + methodParameterHandler.MethodParameter_MapsTo; } else { - ifStatement += ' ' + model.MethodParameter_MapsTo + ' is not None'; + ifStatement += + ' ' + + methodParameterHandler.MethodParameter_MapsTo + + ' is not None'; } } while (model.SelectNextMethodParameter()); ifStatement += ':'; @@ -763,18 +845,24 @@ function GetPolyMethodCall( originalParameters: Parameter[], required: any, ): string[] { + const { + commandGroupHandler, + methodHandler, + parameterHandler, + configHandler, + } = model.GetHandler(); let methodCall: string = prefix + 'return '; let indent = ''; let methodName = originalOperation.language.python.name; - if (model.Method_IsLongRun && model.CommandGroup_HasShowCommand) { - if (!model.SDK_IsTrack1) { + if (methodHandler.Method_IsLongRun && commandGroupHandler.CommandGroup_HasShowCommand) { + if (!configHandler.SDK_IsTrack1) { methodName = 'begin_' + methodName; } methodCall += 'sdk_no_wait('; indent = ' '.repeat(methodCall.length); methodCall += 'no_wait,' + '\n' + indent + 'client.' + methodName; } else { - if (!model.SDK_IsTrack1 && model.Method_IsLongRun) { + if (!configHandler.SDK_IsTrack1 && methodHandler.Method_IsLongRun) { methodName = 'begin_' + methodName; } methodCall += 'client.' + methodName + '('; @@ -786,19 +874,22 @@ function GetPolyMethodCall( const param = originalParameters[cnt]; cnt++; if ( - (param.flattened && !model.Parameter_IsCliFlattened(param)) || - (model.Parameter_IsCliFlattened(param) && !model.SDK_NoFlatten) + (param.flattened && !parameterHandler.Parameter_IsCliFlattened(param)) || + (parameterHandler.Parameter_IsCliFlattened(param) && !configHandler.SDK_NoFlatten) ) { continue; } if (param.schema.type === SchemaType.Constant) { continue; } - if (model.Parameter_InGlobal(param)) { + if (parameterHandler.Parameter_InGlobal(param)) { continue; } - const optionName = model.Parameter_SubMapsTo(model.Method_NameCli, param); - const parameterName = model.Parameter_NamePython(param); + const optionName = parameterHandler.Parameter_SubMapsTo( + methodHandler.Method_NameCli, + param, + ); + const parameterName = parameterHandler.Parameter_NamePython(param); if (isNullOrUndefined(parameterName)) { continue; } @@ -835,19 +926,20 @@ function GetSimpleCallItem( originParam: Parameter = null, optionName: string = null, ): string { + const { parameterHandler, schemaHandler } = model.GetHandler(); let parameterPair = ''; if (m4Flattened && !isNullOrUndefined(originParam)) { - const paramNamePython = model.Parameter_NamePython(originParam); - const keyName = model.Parameter_NamePython(param); - const paramDefaultValue = model.Parameter_DefaultValue(originParam); - if (model.Parameter_IsHidden(originParam)) { + const paramNamePython = parameterHandler.Parameter_NamePython(originParam); + const keyName = parameterHandler.Parameter_NamePython(param); + const paramDefaultValue = parameterHandler.Parameter_DefaultValue(originParam); + if (parameterHandler.Parameter_IsHidden(originParam)) { if (paramDefaultValue) { - if (model.Schema_Type(param.schema) === SchemaType.Object) { + if (schemaHandler.Schema_Type(param.schema) === SchemaType.Object) { const defaultValue = JSON.parse(paramDefaultValue); parameterPair = keyName + '=json.loads(' + - JSON.stringify(defaultValue[model.Parameter_NamePython(param)]) + + JSON.stringify(defaultValue[parameterHandler.Parameter_NamePython(param)]) + ')'; required.json = true; } else { @@ -856,8 +948,8 @@ function GetSimpleCallItem( keyName + '=' + ToPythonString( - defaultValue[model.Parameter_NamePython(param)], - model.Parameter_Type(param), + defaultValue[parameterHandler.Parameter_NamePython(param)], + parameterHandler.Parameter_Type(param), ); } } else { @@ -865,25 +957,30 @@ function GetSimpleCallItem( } } else { parameterPair = - keyName + '=' + model.Parameter_MapsTo(originParam) + "['" + keyName + "']"; + keyName + + '=' + + parameterHandler.Parameter_MapsTo(originParam) + + "['" + + keyName + + "']"; } } else { - const paramNamePython = model.Parameter_NamePython(param); - const paramDefaultValue = model.Parameter_DefaultValue(param); - if (model.Parameter_IsHidden(param)) { + const paramNamePython = parameterHandler.Parameter_NamePython(param); + const paramDefaultValue = parameterHandler.Parameter_DefaultValue(param); + if (parameterHandler.Parameter_IsHidden(param)) { if (paramDefaultValue) { - if (model.Schema_Type(param.schema) === SchemaType.Object) { + if (schemaHandler.Schema_Type(param.schema) === SchemaType.Object) { parameterPair = paramNamePython + '=json.loads(' + - ToPythonString(paramDefaultValue, model.Parameter_Type(param)) + + ToPythonString(paramDefaultValue, parameterHandler.Parameter_Type(param)) + ')'; required.json = true; } else { parameterPair = paramNamePython + '=' + - ToPythonString(paramDefaultValue, model.Parameter_Type(param)); + ToPythonString(paramDefaultValue, parameterHandler.Parameter_Type(param)); } } else { parameterPair = paramNamePython + '=None'; @@ -892,7 +989,7 @@ function GetSimpleCallItem( if (!isNullOrUndefined(optionName)) { parameterPair = paramNamePython + '=' + optionName; } else { - parameterPair = paramNamePython + '=' + model.Parameter_MapsTo(param); + parameterPair = paramNamePython + '=' + parameterHandler.Parameter_MapsTo(param); } } } @@ -900,18 +997,25 @@ function GetSimpleCallItem( } function GetMethodCall(model: CodeModelAz, required: any, prefix: any): string[] { + const { + commandGroupHandler, + methodHandler, + methodParameterHandler, + parameterHandler, + configHandler, + } = model.GetHandler(); let methodCall: string = prefix + 'return '; - let methodName = model.Method_Name; + let methodName = methodHandler.Method_Name; let indent = ''; - if (model.Method_IsLongRun && model.CommandGroup_HasShowCommand) { - if (!model.SDK_IsTrack1) { + if (methodHandler.Method_IsLongRun && commandGroupHandler.CommandGroup_HasShowCommand) { + if (!configHandler.SDK_IsTrack1) { methodName = 'begin_' + methodName; } methodCall += 'sdk_no_wait('; indent = ' '.repeat(methodCall.length); methodCall += 'no_wait,' + '\n' + indent + 'client.' + methodName; } else { - if (!model.SDK_IsTrack1 && model.Method_IsLongRun) { + if (!configHandler.SDK_IsTrack1 && methodHandler.Method_IsLongRun) { methodName = 'begin_' + methodName; } methodCall += 'client.' + methodName + '('; @@ -925,30 +1029,42 @@ function GetMethodCall(model: CodeModelAz, required: any, prefix: any): string[] skip = false; } - const param = model.MethodParameter; + const param = methodParameterHandler.MethodParameter; if ( - (model.MethodParameter_IsFlattened && !model.MethodParameter_IsCliFlattened) || - (model.MethodParameter_IsCliFlattened && !model.SDK_NoFlatten) + (methodParameterHandler.MethodParameter_IsFlattened && + !methodParameterHandler.MethodParameter_IsCliFlattened) || + (methodParameterHandler.MethodParameter_IsCliFlattened && + !configHandler.SDK_NoFlatten) ) { continue; } - if (model.MethodParameter_Type === SchemaType.Constant) { + if (methodParameterHandler.MethodParameter_Type === SchemaType.Constant) { continue; } - if (isNullOrUndefined(model.MethodParameter_NamePython)) { - if (model.Parameter_IsPolyOfSimple(model.MethodParameter)) { - const baseParam = model.MethodParameter; + if (isNullOrUndefined(methodParameterHandler.MethodParameter_NamePython)) { + if ( + parameterHandler.Parameter_IsPolyOfSimple( + methodParameterHandler.MethodParameter, + ) + ) { + const baseParam = methodParameterHandler.MethodParameter; let hasNext = false; if (model.SelectNextMethodParameter(true)) { hasNext = true; - while (hasNext && model.MethodParameter['polyBaseParam'] === baseParam) { + while ( + hasNext && + methodParameterHandler.MethodParameter['polyBaseParam'] === baseParam + ) { hasNext = model.SelectNextMethodParameter(true); } } - if (hasNext && model.MethodParameter['polyBaseParam'] !== baseParam) { + if ( + hasNext && + methodParameterHandler.MethodParameter['polyBaseParam'] !== baseParam + ) { skip = true; } } @@ -956,9 +1072,14 @@ function GetMethodCall(model: CodeModelAz, required: any, prefix: any): string[] } let parameterPair = ''; - const m4FlattenedFrom = model.MethodParameter.language['cli']?.m4FlattenedFrom; + const m4FlattenedFrom = + methodParameterHandler.MethodParameter.language['cli']?.m4FlattenedFrom; if (isNullOrUndefined(m4FlattenedFrom) || m4FlattenedFrom.length <= 0) { - parameterPair = GetSimpleCallItem(model, model.MethodParameter, required); + parameterPair = GetSimpleCallItem( + model, + methodParameterHandler.MethodParameter, + required, + ); } else { const items = []; for (const mparam of m4FlattenedFrom) { @@ -974,17 +1095,23 @@ function GetMethodCall(model: CodeModelAz, required: any, prefix: any): string[] methodCall += ',' + '\n' + indent + parameterPair; } - if (model.Parameter_IsPolyOfSimple(model.MethodParameter)) { - const baseParam = model.MethodParameter; + if (parameterHandler.Parameter_IsPolyOfSimple(methodParameterHandler.MethodParameter)) { + const baseParam = methodParameterHandler.MethodParameter; let hasNext = false; if (model.SelectNextMethodParameter(true)) { hasNext = true; - while (hasNext && model.MethodParameter['polyBaseParam'] === baseParam) { + while ( + hasNext && + methodParameterHandler.MethodParameter['polyBaseParam'] === baseParam + ) { hasNext = model.SelectNextMethodParameter(true); } } - if (hasNext && model.MethodParameter['polyBaseParam'] !== baseParam) { + if ( + hasNext && + methodParameterHandler.MethodParameter['polyBaseParam'] !== baseParam + ) { skip = true; } } diff --git a/src/generate/renders/generated/CliHelp.ts b/src/generate/renders/generated/CliHelp.ts index 3796ed20a..994d9af8b 100644 --- a/src/generate/renders/generated/CliHelp.ts +++ b/src/generate/renders/generated/CliHelp.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *-------------------------------------------------------------------------------------------- */ -import { CodeModelAz } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { SchemaType, Parameter } from '@azure-tools/codemodel'; import { HeaderGenerator } from '../Header'; import { ToMultiLine, isNullOrUndefined, ToSentence } from '../../../utils/helper'; @@ -17,6 +17,12 @@ function initVars() { } export function GenerateAzureCliHelp(model: CodeModelAz, debug: boolean): string[] { + const { + extensionHandler, + commandGroupHandler, + commandHandler, + exampleHandler, + } = model.GetHandler(); initVars(); const header: HeaderGenerator = new HeaderGenerator(); header.disableTooManyLines = true; @@ -25,10 +31,10 @@ export function GenerateAzureCliHelp(model: CodeModelAz, debug: boolean): string output.push(''); output.push(''); - model.GatherInternalResource(); - output.push("helps['" + model.Extension_Name + "'] = '''"); + exampleHandler.GatherInternalResource(); + output.push("helps['" + extensionHandler.Extension_Name + "'] = '''"); output.push(' type: group'); - output.push(' short-summary: ' + model.Extension_Description); + output.push(' short-summary: ' + extensionHandler.Extension_Description); output.push("'''"); if (model.SelectFirstCommandGroup()) { do { @@ -45,20 +51,23 @@ export function GenerateAzureCliHelp(model: CodeModelAz, debug: boolean): string const allLongRunCommand = []; if (model.SelectFirstCommand()) { do { - const subCommandGroupName = model.Command_SubGroupName; + const subCommandGroupName = commandHandler.Command_SubGroupName; if (subCommandGroupName !== '' && !allSubGroup.has(subCommandGroupName)) { allSubGroup.set(subCommandGroupName, true); output = output.concat( generateCommandGroupHelp(model, subCommandGroupName, debug), ); } - if (model.Command_IsLongRun && model.CommandGroup_HasShowCommand) { + if ( + commandHandler.Command_IsLongRun && + commandGroupHandler.CommandGroup_HasShowCommand + ) { hasWait = true; let waitParam = ''; - if (allSupportWaited.indexOf(model.Command_MethodName) < 0) { + if (allSupportWaited.indexOf(commandHandler.Command_MethodName) < 0) { waitParam = 'create'; } else { - waitParam = model.Command_MethodName; + waitParam = commandHandler.Command_MethodName; } if (allLongRunCommand.indexOf(waitParam + 'd') < 0) { allLongRunCommand.push(waitParam + 'd'); @@ -69,7 +78,10 @@ export function GenerateAzureCliHelp(model: CodeModelAz, debug: boolean): string } while (model.SelectNextCommand()); if (hasWait) { output = output.concat( - generateWaitCommandHelp(model.CommandGroup_Name, allLongRunCommand), + generateWaitCommandHelp( + commandGroupHandler.CommandGroup_Name, + allLongRunCommand, + ), ); } } @@ -117,18 +129,19 @@ function generateWaitCommandHelp(commandGroup, allLongRunCommand) { } function generateCommandGroupHelp(model: CodeModelAz, subCommandGroupName = '', debug: boolean) { + const { commandGroupHandler } = model.GetHandler(); const output = []; output.push(''); if (subCommandGroupName !== '') { output.push("helps['" + subCommandGroupName + '\'] = """'); } else { - if (model.CommandGroup_Help.trim() === '') { + if (commandGroupHandler.CommandGroup_Help.trim() === '') { return []; } - output.push("helps['" + model.CommandGroup_Name + '\'] = """'); + output.push("helps['" + commandGroupHandler.CommandGroup_Name + '\'] = """'); } output.push(' type: group'); - let shortSummary = ' short-summary: ' + model.CommandGroup_Help.trim(); + let shortSummary = ' short-summary: ' + commandGroupHandler.CommandGroup_Help.trim(); if (subCommandGroupName !== '') { shortSummary = shortSummary + ' sub group ' + subCommandGroupName.split(' ').pop(); } @@ -136,7 +149,7 @@ function generateCommandGroupHelp(model: CodeModelAz, subCommandGroupName = '', if (!shortSummary.trimRight().endsWith('.')) { shortSummary += '.'; } - shortSummary += ' Command group swagger name=' + model.CommandGroup_CliKey; + shortSummary += ' Command group swagger name=' + commandGroupHandler.CommandGroup_CliKey; } ToMultiLine(shortSummary, output, CodeGenConstants.PYLINT_MAX_CODE_LENGTH, true); @@ -145,35 +158,45 @@ function generateCommandGroupHelp(model: CodeModelAz, subCommandGroupName = '', } function addParameterHelp(output: string[], model: CodeModelAz, debug: boolean) { + const { methodHandler, methodParameterHandler, parameterHandler } = model.GetHandler(); let parameterOutput = [' parameters:']; if (model.SelectFirstMethod()) { do { - const originalOperation = model.Method_GetOriginalOperation; + const originalOperation = methodHandler.Method_GetOriginalOperation; let baseParam = null; if (model.SelectFirstMethodParameter()) { do { - if (model.MethodParameter_IsFlattened) { + if (methodParameterHandler.MethodParameter_IsFlattened) { continue; } if ( - model.MethodParameter_Type === SchemaType.Constant || - model.MethodParameter['readOnly'] + methodParameterHandler.MethodParameter_Type === SchemaType.Constant || + methodParameterHandler.MethodParameter['readOnly'] ) { continue; } - const parameterName = model.MethodParameter_MapsTo; + const parameterName = methodParameterHandler.MethodParameter_MapsTo; if ( !isNullOrUndefined(originalOperation) && - model.MethodParameter['targetProperty']?.isDiscriminator + methodParameterHandler.MethodParameter['targetProperty']?.isDiscriminator ) { continue; } let parameterAlias: string[] = []; - if (!isNullOrUndefined(model.MethodParameter?.language?.['az']?.alias)) { - if (!isNullOrUndefined(model.MethodParameter?.language?.['az']?.alias)) { - const alias = model.MethodParameter?.language?.['az']?.alias; + if ( + !isNullOrUndefined( + methodParameterHandler.MethodParameter?.language?.['az']?.alias, + ) + ) { + if ( + !isNullOrUndefined( + methodParameterHandler.MethodParameter?.language?.['az']?.alias, + ) + ) { + const alias = + methodParameterHandler.MethodParameter?.language?.['az']?.alias; if (typeof alias === 'string') { parameterAlias.push(alias); @@ -189,19 +212,23 @@ function addParameterHelp(output: string[], model: CodeModelAz, debug: boolean) }); if ( - model.MethodParameter_IsList && - model.MethodParameter_IsListOfSimple && - !model.MethodParameter_IsSimpleArray + methodParameterHandler.MethodParameter_IsList && + methodParameterHandler.MethodParameter_IsListOfSimple && + !methodParameterHandler.MethodParameter_IsSimpleArray ) { - if (model.Parameter_IsPolyOfSimple(model.MethodParameter)) { - baseParam = model.MethodParameter; + if ( + parameterHandler.Parameter_IsPolyOfSimple( + methodParameterHandler.MethodParameter, + ) + ) { + baseParam = methodParameterHandler.MethodParameter; continue; } - if (model.MethodParameter_IsPositional) { + if (methodParameterHandler.MethodParameter_IsPositional) { parameterOutput = parameterOutput.concat( getPositionalActionHelp(model, parameterAlias, baseParam, debug), ); - } else if (model.MethodParameter_IsShorthandSyntax) { + } else if (methodParameterHandler.MethodParameter_IsShorthandSyntax) { parameterOutput = parameterOutput.concat( getShorthandSyntaxAction(model, parameterAlias, baseParam, debug), ); @@ -229,6 +256,7 @@ function getShorthandSyntaxAction( baseParam: Parameter, debug: boolean, ) { + const { methodParameterHandler, parameterHandler, schemaHandler } = model.GetHandler(); let parameterOutput: string[] = []; const actionOutput: string[] = []; ToMultiLine( @@ -241,15 +269,18 @@ function getShorthandSyntaxAction( if (debug) { let shortSummary = '"'; if ( - model.MethodParameter_Description && - model.MethodParameter_Description.trim().length > 0 + methodParameterHandler.MethodParameter_Description && + methodParameterHandler.MethodParameter_Description.trim().length > 0 ) { - shortSummary += model.MethodParameter_Description.trim().replace(/"/g, '\\\\"'); + shortSummary += methodParameterHandler.MethodParameter_Description.trim().replace( + /"/g, + '\\\\"', + ); } if (!shortSummary.endsWith('.')) { shortSummary += '.'; } - shortSummary += ' Swagger name=' + model.MethodParameter_CliKey + '"'; + shortSummary += ' Swagger name=' + methodParameterHandler.MethodParameter_CliKey + '"'; ToMultiLine( ` short-summary: ${shortSummary}`.replace(/\r?\n|\r/g, ''), actionOutput, @@ -258,10 +289,13 @@ function getShorthandSyntaxAction( ); } else { if ( - model.MethodParameter_Description && - model.MethodParameter_Description.trim().length > 0 + methodParameterHandler.MethodParameter_Description && + methodParameterHandler.MethodParameter_Description.trim().length > 0 ) { - const shortSummary = model.MethodParameter_Description.trim().replace(/"/g, '\\\\"'); + const shortSummary = methodParameterHandler.MethodParameter_Description.trim().replace( + /"/g, + '\\\\"', + ); ToMultiLine( ` short-summary: "${shortSummary}"`.replace(/\r?\n|\r/g, ''), actionOutput, @@ -272,10 +306,11 @@ function getShorthandSyntaxAction( } let options: Parameter[] = []; - if (!isNullOrUndefined(model.MethodParameter_ActionName)) { - if (baseParam && model.MethodParameter['polyBaseParam'] === baseParam) { + if (!isNullOrUndefined(methodParameterHandler.MethodParameter_ActionName)) { + if (baseParam && methodParameterHandler.MethodParameter['polyBaseParam'] === baseParam) { const keyToMatch = baseParam.schema?.['discriminator']?.property?.language.python?.name; - const valueToMatch = model.MethodParameter.schema?.['discriminatorValue']; + const valueToMatch = + methodParameterHandler.MethodParameter.schema?.['discriminatorValue']; options = GetKeyValueActionOptions(model, null, keyToMatch, valueToMatch); } else { options = GetKeyValueActionOptions(model, null); @@ -283,8 +318,9 @@ function getShorthandSyntaxAction( } if (options.length > 0) { actionOutput.push(' long-summary: |'); - const optionUsage = ' ' + options.map((p) => `${model.Parameter_NameAz(p)}=XX`).join(','); - if (model.MethodParameter_Type === SchemaType.Array) { + const optionUsage = + ' ' + options.map((p) => `${parameterHandler.Parameter_NameAz(p)}=XX`).join(','); + if (methodParameterHandler.MethodParameter_Type === SchemaType.Array) { ToMultiLine( ' Usage: ' + parameterAlias[0] + optionUsage.repeat(2), actionOutput, @@ -301,17 +337,20 @@ function getShorthandSyntaxAction( } actionOutput.push(''); for (const p of options) { - const pDesc = model.Parameter_Description(p); + const pDesc = parameterHandler.Parameter_Description(p); if (!pDesc || pDesc.trim().length <= 0) continue; - let line = ` ${model.Parameter_NameAz(p)}: `; + let line = ` ${parameterHandler.Parameter_NameAz(p)}: `; if (p.required) line += 'Required. '; - line += model + line += parameterHandler .Parameter_Description(p) .trim() .replace(/\r?\n|\r/g, ''); ToMultiLine(line, actionOutput, CodeGenConstants.PYLINT_MAX_CODE_LENGTH, true); } - if (model.Schema_Type(model.MethodParameter.schema) === SchemaType.Array) { + if ( + schemaHandler.Schema_Type(methodParameterHandler.MethodParameter.schema) === + SchemaType.Array + ) { actionOutput.push(''); ToMultiLine( ` Multiple actions can be specified by using more than one ${parameterAlias[0]} argument.`, @@ -331,6 +370,7 @@ function getPositionalActionHelp( baseParam: Parameter, debug: boolean, ) { + const { methodParameterHandler, parameterHandler, schemaHandler } = model.GetHandler(); let parameterOutput: string[] = []; const actionOutput: string[] = []; ToMultiLine( @@ -343,15 +383,18 @@ function getPositionalActionHelp( if (debug) { let shortSummary = '"'; if ( - model.MethodParameter_Description && - model.MethodParameter_Description.trim().length > 0 + methodParameterHandler.MethodParameter_Description && + methodParameterHandler.MethodParameter_Description.trim().length > 0 ) { - shortSummary += model.MethodParameter_Description.trim().replace(/"/g, '\\\\"'); + shortSummary += methodParameterHandler.MethodParameter_Description.trim().replace( + /"/g, + '\\\\"', + ); } if (!shortSummary.endsWith('.')) { shortSummary += '.'; } - shortSummary += ' Swagger name=' + model.MethodParameter_CliKey + '"'; + shortSummary += ' Swagger name=' + methodParameterHandler.MethodParameter_CliKey + '"'; ToMultiLine( ` short-summary: ${shortSummary}`.replace(/\r?\n|\r/g, ''), actionOutput, @@ -360,10 +403,13 @@ function getPositionalActionHelp( ); } else { if ( - model.MethodParameter_Description && - model.MethodParameter_Description.trim().length > 0 + methodParameterHandler.MethodParameter_Description && + methodParameterHandler.MethodParameter_Description.trim().length > 0 ) { - const shortSummary = model.MethodParameter_Description.trim().replace(/"/g, '\\\\"'); + const shortSummary = methodParameterHandler.MethodParameter_Description.trim().replace( + /"/g, + '\\\\"', + ); ToMultiLine( ` short-summary: "${shortSummary}"`.replace(/\r?\n|\r/g, ''), actionOutput, @@ -373,12 +419,13 @@ function getPositionalActionHelp( } } - const positionalKeys = model.MethodParameter_PositionalKeys; + const positionalKeys = methodParameterHandler.MethodParameter_PositionalKeys; let options: Parameter[] = []; - if (!isNullOrUndefined(model.MethodParameter_ActionName)) { - if (baseParam && model.MethodParameter['polyBaseParam'] === baseParam) { + if (!isNullOrUndefined(methodParameterHandler.MethodParameter_ActionName)) { + if (baseParam && methodParameterHandler.MethodParameter['polyBaseParam'] === baseParam) { const keyToMatch = baseParam.schema?.['discriminator']?.property?.language.python?.name; - const valueToMatch = model.MethodParameter.schema?.['discriminatorValue']; + const valueToMatch = + methodParameterHandler.MethodParameter.schema?.['discriminatorValue']; options = GetKeyValueActionOptions(model, positionalKeys, keyToMatch, valueToMatch); } else { options = GetKeyValueActionOptions(model, positionalKeys); @@ -391,7 +438,7 @@ function getPositionalActionHelp( ' The order of this parameter is specific customized. Usage: ', parameterAlias[0], ] - .concat(options.map((p) => `${model.Parameter_NameAz(p)}-value`)) + .concat(options.map((p) => `${parameterHandler.Parameter_NameAz(p)}-value`)) .join(' '), actionOutput, CodeGenConstants.PYLINT_MAX_CODE_LENGTH, @@ -399,17 +446,20 @@ function getPositionalActionHelp( ); actionOutput.push(''); for (const p of options) { - const pDesc = model.Parameter_Description(p); + const pDesc = parameterHandler.Parameter_Description(p); if (!pDesc || pDesc.trim().length <= 0) continue; - let line = ` ${model.Parameter_NameAz(p)}: `; + let line = ` ${parameterHandler.Parameter_NameAz(p)}: `; line += 'Required. '; - line += model + line += parameterHandler .Parameter_Description(p) .trim() .replace(/\r?\n|\r/g, ''); ToMultiLine(line, actionOutput, CodeGenConstants.PYLINT_MAX_CODE_LENGTH, true); } - if (model.Schema_Type(model.MethodParameter.schema) === SchemaType.Array) { + if ( + schemaHandler.Schema_Type(methodParameterHandler.MethodParameter.schema) === + SchemaType.Array + ) { actionOutput.push(''); ToMultiLine( ` Multiple actions can be specified by using more than one ${parameterAlias[0]} argument.`, @@ -429,6 +479,7 @@ function getKeyValueActionHelp( baseParam: Parameter, debug: boolean, ) { + const { methodParameterHandler, parameterHandler, schemaHandler } = model.GetHandler(); let parameterOutput: string[] = []; const actionOutput: string[] = []; ToMultiLine( @@ -441,15 +492,18 @@ function getKeyValueActionHelp( if (debug) { let shortSummary = '"'; if ( - model.MethodParameter_Description && - model.MethodParameter_Description.trim().length > 0 + methodParameterHandler.MethodParameter_Description && + methodParameterHandler.MethodParameter_Description.trim().length > 0 ) { - shortSummary += model.MethodParameter_Description.trim().replace(/"/g, '\\\\"'); + shortSummary += methodParameterHandler.MethodParameter_Description.trim().replace( + /"/g, + '\\\\"', + ); } if (!shortSummary.endsWith('.')) { shortSummary += '.'; } - shortSummary += ' Swagger name=' + model.MethodParameter_CliKey + '"'; + shortSummary += ' Swagger name=' + methodParameterHandler.MethodParameter_CliKey + '"'; ToMultiLine( ` short-summary: ${shortSummary}`.replace(/\r?\n|\r/g, ''), actionOutput, @@ -458,10 +512,13 @@ function getKeyValueActionHelp( ); } else { if ( - model.MethodParameter_Description && - model.MethodParameter_Description.trim().length > 0 + methodParameterHandler.MethodParameter_Description && + methodParameterHandler.MethodParameter_Description.trim().length > 0 ) { - const shortSummary = model.MethodParameter_Description.trim().replace(/"/g, '\\\\"'); + const shortSummary = methodParameterHandler.MethodParameter_Description.trim().replace( + /"/g, + '\\\\"', + ); ToMultiLine( ` short-summary: "${shortSummary}"`.replace(/\r?\n|\r/g, ''), actionOutput, @@ -472,10 +529,11 @@ function getKeyValueActionHelp( } let options: Parameter[] = []; - if (!isNullOrUndefined(model.MethodParameter_ActionName)) { - if (baseParam && model.MethodParameter['polyBaseParam'] === baseParam) { + if (!isNullOrUndefined(methodParameterHandler.MethodParameter_ActionName)) { + if (baseParam && methodParameterHandler.MethodParameter['polyBaseParam'] === baseParam) { const keyToMatch = baseParam.schema?.['discriminator']?.property?.language.python?.name; - const valueToMatch = model.MethodParameter.schema?.['discriminatorValue']; + const valueToMatch = + methodParameterHandler.MethodParameter.schema?.['discriminatorValue']; options = GetKeyValueActionOptions(model, null, keyToMatch, valueToMatch); } else { options = GetKeyValueActionOptions(model, null); @@ -485,7 +543,7 @@ function getKeyValueActionHelp( actionOutput.push(' long-summary: |'); ToMultiLine( [' Usage:', parameterAlias[0]] - .concat(options.map((p) => `${model.Parameter_NameAz(p)}=XX`)) + .concat(options.map((p) => `${parameterHandler.Parameter_NameAz(p)}=XX`)) .join(' '), actionOutput, CodeGenConstants.PYLINT_MAX_CODE_LENGTH, @@ -493,17 +551,20 @@ function getKeyValueActionHelp( ); actionOutput.push(''); for (const p of options) { - const pDesc = model.Parameter_Description(p); + const pDesc = parameterHandler.Parameter_Description(p); if (!pDesc || pDesc.trim().length <= 0) continue; - let line = ` ${model.Parameter_NameAz(p)}: `; + let line = ` ${parameterHandler.Parameter_NameAz(p)}: `; if (p.required) line += 'Required. '; - line += model + line += parameterHandler .Parameter_Description(p) .trim() .replace(/\r?\n|\r/g, ''); ToMultiLine(line, actionOutput, CodeGenConstants.PYLINT_MAX_CODE_LENGTH, true); } - if (model.Schema_Type(model.MethodParameter.schema) === SchemaType.Array) { + if ( + schemaHandler.Schema_Type(methodParameterHandler.MethodParameter.schema) === + SchemaType.Array + ) { actionOutput.push(''); ToMultiLine( ` Multiple actions can be specified by using more than one ${parameterAlias[0]} argument.`, @@ -523,13 +584,14 @@ function GetKeyValueActionOptions( keyToMatch: string = null, valueToMatch: string = null, ): Parameter[] { + const { methodParameterHandler, parameterHandler } = model.GetHandler(); const options: Parameter[] = []; if (!SchemaType.Object || !SchemaType.Array) { return options; } - if (model.MethodParameter_IsPositional) { + if (methodParameterHandler.MethodParameter_IsPositional) { for (const item of positionalKeys) { options.push(null); } @@ -547,23 +609,23 @@ function GetKeyValueActionOptions( if ( !isNullOrUndefined(keyToMatch) && !isNullOrUndefined(valueToMatch) && - model.Parameter_NamePython(model.SubMethodParameter) === keyToMatch + parameterHandler.Parameter_NamePython(model.SubMethodParameter) === keyToMatch ) { continue; } if (model.SubMethodParameter) { - if (model.MethodParameter_IsPositional) { + if (methodParameterHandler.MethodParameter_IsPositional) { if ( !isNullOrUndefined(positionalKeys) && Array.isArray(positionalKeys) && positionalKeys.length > 0 && positionalKeys.indexOf( - model.Parameter_NamePython(model.SubMethodParameter), + parameterHandler.Parameter_NamePython(model.SubMethodParameter), ) > -1 ) { options[ positionalKeys.indexOf( - model.Parameter_NamePython(model.SubMethodParameter), + parameterHandler.Parameter_NamePython(model.SubMethodParameter), ) ] = model.SubMethodParameter; } @@ -580,6 +642,12 @@ function GetKeyValueActionOptions( } function generateCommandHelp(model: CodeModelAz, debug = false) { + const { + commandGroupHandler, + commandHandler, + methodHandler, + exampleHandler, + } = model.GetHandler(); // create, delete, list, show, update // let method: string = methods[mi]; // let ctx = model.SelectCommand(method); @@ -588,7 +656,7 @@ function generateCommandHelp(model: CodeModelAz, debug = false) { // continue; let output: string[] = []; output.push(''); - const commandHead = model.Command_Name; + const commandHead = commandHandler.Command_Name; output.push("helps['" + commandHead + '\'] = """'); output.push(' type: command'); @@ -599,14 +667,14 @@ function generateCommandHelp(model: CodeModelAz, debug = false) { let isFirst = true; if (model.SelectFirstMethod()) { do { - shortSummary += (isFirst ? '' : ' And ') + model.Method_Help.trim(); + shortSummary += (isFirst ? '' : ' And ') + methodHandler.Method_Help.trim(); isFirst = false; if (debug) { shortSummary += ' Command group swagger name=' + - model.CommandGroup_CliKey + + commandGroupHandler.CommandGroup_CliKey + ', Command swagger name=' + - model.Method_CliKey; + methodHandler.Method_CliKey; } } while (model.SelectNextMethod()); } @@ -622,7 +690,7 @@ function generateCommandHelp(model: CodeModelAz, debug = false) { if (model.SelectFirstMethod()) { do { - for (const example of model.GetExamples(false)) { + for (const example of exampleHandler.GetExamples(false)) { if (!examplesStarted) { output.push(' examples:'); examplesStarted = true; @@ -630,11 +698,11 @@ function generateCommandHelp(model: CodeModelAz, debug = false) { // output.push ("# " + example_id); let parameters: string[] = []; - parameters = model.GetExampleItems(example, false, undefined); + parameters = exampleHandler.GetExampleItems(example, false, undefined); output.push(' - name: ' + example.Title); output.push(' text: |-'); const line = ' ' + parameters.join(' '); - if (model.Command_MethodName === 'show') { + if (commandHandler.Command_MethodName === 'show') { showExampleStr = line; } ToMultiLine(line, output, CodeGenConstants.PYLINT_MAX_CODE_LENGTH, true); diff --git a/src/generate/renders/generated/CliParams.ts b/src/generate/renders/generated/CliParams.ts index 03391924b..76670ecc3 100644 --- a/src/generate/renders/generated/CliParams.ts +++ b/src/generate/renders/generated/CliParams.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *-------------------------------------------------------------------------------------------- */ -import { CodeModelAz } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { EscapeString, ToCamelCase, @@ -43,6 +43,7 @@ function initVars() { } export function GenerateAzureCliParams(model: CodeModelAz, debug: boolean): string[] { + const { commandGroupHandler, commandHandler, configHandler } = model.GetHandler(); initVars(); let outputArgs: string[] = []; @@ -58,12 +59,15 @@ export function GenerateAzureCliParams(model: CodeModelAz, debug: boolean): stri let showOutput = []; if (model.SelectFirstCommand()) { do { - if (model.Command_IsLongRun && model.CommandGroup_HasShowCommand) { + if ( + commandHandler.Command_IsLongRun && + commandGroupHandler.CommandGroup_HasShowCommand + ) { needWait = true; } - const needGeneric = model.Command_NeedGeneric; + const needGeneric = commandHandler.Command_NeedGeneric; const commandOutput = getCommandBody(model, needGeneric, debug); - if (model.Command_MethodName === 'show') { + if (commandHandler.Command_MethodName === 'show') { showOutput = commandOutput; } if (commandOutput.length > 0) { @@ -93,7 +97,7 @@ export function GenerateAzureCliParams(model: CodeModelAz, debug: boolean): stri if (hasResourceGroup) parameterImports.push('resource_group_name_type'); if (hasLocation) parameterImports.push('get_location_type'); if (parameterImports.length > 0) { - header.addFromImport(model.CliCoreLib + '.commands.parameters', parameterImports); + header.addFromImport(configHandler.CliCoreLib + '.commands.parameters', parameterImports); } const validatorImports: string[] = []; @@ -104,15 +108,15 @@ export function GenerateAzureCliParams(model: CodeModelAz, debug: boolean): stri validatorImports.push('validate_file_or_dict'); } if (validatorImports.length > 0) { - header.addFromImport(model.CliCoreLib + '.commands.validators', validatorImports); + header.addFromImport(configHandler.CliCoreLib + '.commands.validators', validatorImports); } if (hasActions) { - if (model.IsCliCore) { + if (configHandler.IsCliCore) { const topAction = new CliTopAction(model); header.addFromImport('..' + topAction.relativePath.replace(/\.py$/, ''), actions); } else { - header.addFromImport(model.AzextFolder + '.action', actions); + header.addFromImport(configHandler.AzextFolder + '.action', actions); } } @@ -136,6 +140,12 @@ export function GenerateAzureCliParams(model: CodeModelAz, debug: boolean): stri } function getCommandBody(model: CodeModelAz, needGeneric = false, debug = false) { + const { + commandHandler, + methodHandler, + methodParameterHandler, + parameterHandler, + } = model.GetHandler(); // let method: string = methods[mi]; // let ctx = model.SelectCommand(method); @@ -143,45 +153,47 @@ function getCommandBody(model: CodeModelAz, needGeneric = false, debug = false) // continue; const outputArgs: string[] = []; outputArgs.push(''); - outputArgs.push(" with self.argument_context('" + model.Command_Name + "') as c:"); + outputArgs.push(" with self.argument_context('" + commandHandler.Command_Name + "') as c:"); let hasParam = false; const allParam: Map = new Map(); const allPythonParam: Map = new Map(); if (model.SelectFirstMethod()) { do { - const originalOperation = model.Method_GetOriginalOperation; + const originalOperation = methodHandler.Method_GetOriginalOperation; if (!isNullOrUndefined(originalOperation)) { for (const param of originalOperation.parameters) { - if (model.Parameter_InGlobal(param)) { + if (parameterHandler.Parameter_InGlobal(param)) { continue; } - if (model.Parameter_IsFlattened(param) === true) { + if (parameterHandler.Parameter_IsFlattened(param) === true) { continue; } if (param?.schema?.type === SchemaType.Constant || param.readOnly) { continue; } - if (!isNullOrUndefined(param?.language?.python?.name)) { - allPythonParam.set(param.language.python.name, true); + const pythonParamName = parameterHandler.Parameter_NamePython(param); + if (!isNullOrUndefined(pythonParamName)) { + allPythonParam.set(pythonParamName, true); } } if (!isNullOrUndefined(originalOperation.requests[0].parameters)) { for (const param of originalOperation.requests[0].parameters) { - if (model.Parameter_InGlobal(param)) { + if (parameterHandler.Parameter_InGlobal(param)) { continue; } if ( - model.Parameter_IsFlattened(param) === true && - !model.Parameter_IsCliFlattened(param) + parameterHandler.Parameter_IsFlattened(param) === true && + !parameterHandler.Parameter_IsCliFlattened(param) ) { continue; } if (param?.schema?.type === SchemaType.Constant || param.readOnly) { continue; } - if (!isNullOrUndefined(param?.language?.python?.name)) { - allPythonParam.set(param.language.python.name, true); + const pythonParamName = parameterHandler.Parameter_NamePython(param); + if (!isNullOrUndefined(pythonParamName)) { + allPythonParam.set(pythonParamName, true); } } } @@ -190,26 +202,26 @@ function getCommandBody(model: CodeModelAz, needGeneric = false, debug = false) let hasResourceGroupInOperation = false; if (model.SelectFirstMethodParameter()) { do { - if (model.MethodParameter_IsFlattened) { + if (methodParameterHandler.MethodParameter_IsFlattened) { continue; } if ( - model.MethodParameter_Type === SchemaType.Constant || - model.MethodParameter['readOnly'] + methodParameterHandler.MethodParameter_Type === SchemaType.Constant || + methodParameterHandler.MethodParameter['readOnly'] ) { continue; } hasParam = true; if ( isNullOrUndefined(originalOperation) && - !isNullOrUndefined(model.MethodParameter_NamePython) + !isNullOrUndefined(methodParameterHandler.MethodParameter_NamePython) ) { - allPythonParam.set(model.MethodParameter_NamePython, true); + allPythonParam.set(methodParameterHandler.MethodParameter_NamePython, true); } - const parameterName = model.MethodParameter_MapsTo; + const parameterName = methodParameterHandler.MethodParameter_MapsTo; if ( !isNullOrUndefined(originalOperation) && - model.MethodParameter['targetProperty']?.isDiscriminator + methodParameterHandler.MethodParameter['targetProperty']?.isDiscriminator ) { continue; } @@ -218,9 +230,13 @@ function getCommandBody(model: CodeModelAz, needGeneric = false, debug = false) } let argument = " c.argument('" + parameterName + "'"; - if (!isNullOrUndefined(model.MethodParameter.language['az'].alias)) { + if ( + !isNullOrUndefined( + methodParameterHandler.MethodParameter.language['az'].alias, + ) + ) { argument = " c.argument('" + parameterName + "'"; - const aliases = model.MethodParameter.language['az'].alias; + const aliases = methodParameterHandler.MethodParameter.language['az'].alias; if (aliases.length > 0) { const aliasStr = []; const oriAlias = []; @@ -237,7 +253,7 @@ function getCommandBody(model: CodeModelAz, needGeneric = false, debug = false) oriAlias.push(tmpAlias); } } - model.MethodParameter.language['az'].alias = oriAlias; + methodParameterHandler.MethodParameter.language['az'].alias = oriAlias; argument += ', options_list=[' + aliasStr.join(', ') + ']'; } } @@ -247,17 +263,17 @@ function getCommandBody(model: CodeModelAz, needGeneric = false, debug = false) } allParam.set(parameterName, true); - if (model.MethodParameter_Type === SchemaType.Boolean) { + if (methodParameterHandler.MethodParameter_Type === SchemaType.Boolean) { hasBoolean = true; argument += ', arg_type=get_three_state_flag()'; } else if ( - model.MethodParameter_Type === SchemaType.Choice || - model.MethodParameter_Type === SchemaType.SealedChoice + methodParameterHandler.MethodParameter_Type === SchemaType.Choice || + methodParameterHandler.MethodParameter_Type === SchemaType.SealedChoice ) { hasEnum = true; argument += ', arg_type=get_enum_type(['; - model.MethodParameter_EnumValues.forEach((element) => { + methodParameterHandler.MethodParameter_EnumValues.forEach((element) => { if (!argument.endsWith('[')) argument += ', '; argument += "'" + element + "'"; }); @@ -283,34 +299,45 @@ function getCommandBody(model: CodeModelAz, needGeneric = false, debug = false) } hasLocation = true; needSkip = true; - } else if (model.MethodParameter_IsSimpleArray) { - if (model.MethodParameter.language['cli'].required === false) { + } else if (methodParameterHandler.MethodParameter_IsSimpleArray) { + if ( + methodParameterHandler.MethodParameter.language['cli'].required === + false + ) { argument += ", nargs='*'"; } else { argument += ", nargs='+'"; } } else if ( - model.MethodParameter_IsList && - !model.MethodParameter_IsListOfSimple + methodParameterHandler.MethodParameter_IsList && + !methodParameterHandler.MethodParameter_IsListOfSimple ) { - if (model.Parameter_IsPolyOfSimple(model.MethodParameter)) { - baseParam = model.MethodParameter; + if ( + parameterHandler.Parameter_IsPolyOfSimple( + methodParameterHandler.MethodParameter, + ) + ) { + baseParam = methodParameterHandler.MethodParameter; continue; } hasJson = true; argument += ', type=validate_file_or_dict'; } else if ( - model.MethodParameter_IsList && - model.MethodParameter_IsListOfSimple + methodParameterHandler.MethodParameter_IsList && + methodParameterHandler.MethodParameter_IsListOfSimple ) { - const actionName: string = model.MethodParameter_ActionName; + const actionName: string = + methodParameterHandler.MethodParameter_ActionName; argument += ', action=' + actionName; hasActions = true; if (actions.indexOf(actionName) < 0) { actions.push(actionName); } - if (model.MethodParameter.language['cli'].required === false) { + if ( + methodParameterHandler.MethodParameter.language['cli'].required === + false + ) { argument += ", nargs='*'"; } else { argument += ", nargs='+'"; @@ -318,19 +345,28 @@ function getCommandBody(model: CodeModelAz, needGeneric = false, debug = false) } if (!needSkip) { - if (model.MethodParameter_Type === SchemaType.Integer) { + if (methodParameterHandler.MethodParameter_Type === SchemaType.Integer) { argument += ', type=int'; - } else if (model.MethodParameter_Type === SchemaType.Number) { + } else if ( + methodParameterHandler.MethodParameter_Type === SchemaType.Number + ) { argument += ', type=float'; - } else if (model.MethodParameter_Type === SchemaType.String) { + } else if ( + methodParameterHandler.MethodParameter_Type === SchemaType.String + ) { argument += ', type=str'; } argument += ", help='" + - EscapeString(model.MethodParameter_Description).trimRight(); - if (model.MethodParameter_IsList && !model.MethodParameter_IsSimpleArray) { - const netDescription = model.MethodParameter_Description.trim(); + EscapeString( + methodParameterHandler.MethodParameter_Description, + ).trimRight(); + if ( + methodParameterHandler.MethodParameter_IsList && + !methodParameterHandler.MethodParameter_IsSimpleArray + ) { + const netDescription = methodParameterHandler.MethodParameter_Description.trim(); if ( netDescription.length > 0 && netDescription[netDescription.length - 1].match( @@ -339,18 +375,25 @@ function getCommandBody(model: CodeModelAz, needGeneric = false, debug = false) ) { argument += '.'; } - if (model.MethodParameter_IsListOfSimple) { + if (methodParameterHandler.MethodParameter_IsListOfSimple) { let options = []; - if (!isNullOrUndefined(model.MethodParameter_ActionName)) { + if ( + !isNullOrUndefined( + methodParameterHandler.MethodParameter_ActionName, + ) + ) { if ( baseParam && - model.MethodParameter['polyBaseParam'] === baseParam + methodParameterHandler.MethodParameter['polyBaseParam'] === + baseParam ) { const keyToMatch = baseParam.schema?.discriminator?.property?.language .python?.name; const valueToMatch = - model.MethodParameter.schema?.['discriminatorValue']; + methodParameterHandler.MethodParameter.schema?.[ + 'discriminatorValue' + ]; options = GetActionOptions(model, keyToMatch, valueToMatch); } else { options = GetActionOptions(model); @@ -369,47 +412,60 @@ function getCommandBody(model: CodeModelAz, needGeneric = false, debug = false) if (!argument.endsWith('.')) { argument += '.'; } - argument += ' Swagger name=' + model.MethodParameter_CliKey; + argument += + ' Swagger name=' + methodParameterHandler.MethodParameter_CliKey; } argument += "'"; if ( !isNullOrUndefined(baseParam) && - model.MethodParameter['polyBaseParam'] === baseParam + methodParameterHandler.MethodParameter['polyBaseParam'] === baseParam ) { argument += ", arg_group='" + - Capitalize(ToCamelCase(model.Parameter_MapsTo(baseParam))) + + Capitalize( + ToCamelCase(parameterHandler.Parameter_MapsTo(baseParam)), + ) + + "'"; + } else if ( + !isNullOrUndefined(methodParameterHandler.MethodParameter_ArgGroup) + ) { + argument += + ", arg_group='" + + methodParameterHandler.MethodParameter_ArgGroup + "'"; - } else if (!isNullOrUndefined(model.MethodParameter_ArgGroup)) { - argument += ", arg_group='" + model.MethodParameter_ArgGroup + "'"; } } - const lastItem = model.Method_NameAz.split(' ').last; + const lastItem = methodHandler.Method_NameAz.split(' ').last; if ( !lastItem.startsWith('list') && - !model.Method_NameAz.split(' ').last.startsWith('create') + !methodHandler.Method_NameAz.split(' ').last.startsWith('create') ) { - if (!isNullOrUndefined(model.MethodParameter_IdPart)) { - argument += ", id_part='" + model.MethodParameter_IdPart + "'"; + if (!isNullOrUndefined(methodParameterHandler.MethodParameter_IdPart)) { + argument += + ", id_part='" + methodParameterHandler.MethodParameter_IdPart + "'"; } } - if (!isNullOrUndefined(model.MethodParameter_DefaultConfigKey)) { + if ( + !isNullOrUndefined(methodParameterHandler.MethodParameter_DefaultConfigKey) + ) { argument += - ", configured_default='" + model.MethodParameter_DefaultConfigKey + "'"; + ", configured_default='" + + methodParameterHandler.MethodParameter_DefaultConfigKey + + "'"; } const paramRet = composeParamString( - model.MethodParameter_MaxApi, - model.MethodParameter_MinApi, - model.MethodParameter_ResourceType, + methodParameterHandler.MethodParameter_MaxApi, + methodParameterHandler.MethodParameter_MinApi, + methodParameterHandler.MethodParameter_ResourceType, ); argument += paramRet[0]; if (paramRet[1]) useResourceType = true; let parameterExtraInfo = ''; parameterExtraInfo = getExtraModeInfo( - model.MethodParameter_Mode, - model.Command_Mode, + methodParameterHandler.MethodParameter_Mode, + commandHandler.Command_Mode, ); if (parameterExtraInfo !== '') { parameterExtraInfo = ', ' + parameterExtraInfo; @@ -444,6 +500,7 @@ function GetActionOptions( keyToMatch: string = null, valueToMatch: string = null, ): string[] { + const { parameterHandler } = model.GetHandler(); const options = []; if (!SchemaType.Object || !SchemaType.Array) { @@ -461,11 +518,11 @@ function GetActionOptions( if ( !isNullOrUndefined(keyToMatch) && !isNullOrUndefined(valueToMatch) && - model.Parameter_NamePython(model.SubMethodParameter) === keyToMatch + parameterHandler.Parameter_NamePython(model.SubMethodParameter) === keyToMatch ) { continue; } - const azName = model.Parameter_NameAz(model.SubMethodParameter); + const azName = parameterHandler.Parameter_NameAz(model.SubMethodParameter); if (azName) { options.push(azName); } diff --git a/src/generate/renders/generated/CliValidators.ts b/src/generate/renders/generated/CliValidators.ts index 8ba6dd0ac..d6790be75 100644 --- a/src/generate/renders/generated/CliValidators.ts +++ b/src/generate/renders/generated/CliValidators.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *-------------------------------------------------------------------------------------------- */ -import { CodeModelAz } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { HeaderGenerator } from '../Header'; export function GenerateAzureCliValidators(model: CodeModelAz): string[] { diff --git a/src/generate/renders/tests/CliTestCmdlet.ts b/src/generate/renders/tests/CliTestCmdlet.ts index 9499d15ea..c18febfea 100644 --- a/src/generate/renders/tests/CliTestCmdlet.ts +++ b/src/generate/renders/tests/CliTestCmdlet.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *-------------------------------------------------------------------------------------------- */ import * as path from 'path'; -import { CodeModelAz } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { CliTestStep } from './CliTestStep'; import { deepCopy, isGeneratedExampleId, isNullOrUndefined } from '../../../utils/helper'; import { TemplateBase } from '../TemplateBase'; @@ -21,11 +21,12 @@ class CmdletTestCase { export class CliCmdletTest extends TemplateBase { constructor(model: CodeModelAz, isNegativeTest: boolean) { super(model); + const { configHandler } = model.GetHandler(); const testFileName = isNegativeTest ? PathConstants.negativeTestFile : PathConstants.positiveTestFile; this.relativePath = path.join( - model.AzextFolder, + configHandler.AzextFolder, PathConstants.testFolder, PathConstants.cmdletFolder, testFileName, @@ -74,10 +75,10 @@ export class CliCmdletTest extends TemplateBase { ]; for (const extension of this.model.getModelData('extension', inputProperties, dependencies) - .Extensions) - for (const commandGroup of extension.CommandGroups) - for (const command of commandGroup.Commands) - for (const method of command.Methods) + .Extensions) { + for (const commandGroup of extension.CommandGroups) { + for (const command of commandGroup.Commands) { + for (const method of command.Methods) { if (method.hasAzExample) { (method.AzExamples as any[]).sort((a, b) => { return a.id > b.id ? 1 : -1; @@ -118,6 +119,10 @@ export class CliCmdletTest extends TemplateBase { } ret.testData.testCases.push(testCase); } + } + } + } + } return ret; } } diff --git a/src/generate/renders/tests/CliTestInit.ts b/src/generate/renders/tests/CliTestInit.ts index c346f4e93..20af2de78 100644 --- a/src/generate/renders/tests/CliTestInit.ts +++ b/src/generate/renders/tests/CliTestInit.ts @@ -3,15 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *-------------------------------------------------------------------------------------------- */ import * as path from 'path'; -import { CodeModelAz } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { TemplateBase } from '../TemplateBase'; import { PathConstants } from '../../../utils/models'; export class CliTestInit extends TemplateBase { constructor(model: CodeModelAz) { super(model); + const { configHandler } = model.GetHandler(); this.relativePath = path.join( - model.AzextFolder, + configHandler.AzextFolder, PathConstants.testFolder, PathConstants.initFile, ); diff --git a/src/generate/renders/tests/CliTestPrepare.ts b/src/generate/renders/tests/CliTestPrepare.ts index 82e6f1a71..37fd68965 100644 --- a/src/generate/renders/tests/CliTestPrepare.ts +++ b/src/generate/renders/tests/CliTestPrepare.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { CodeModelAz } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { TemplateBase } from '../TemplateBase'; import { PathConstants } from '../../../utils/models'; import { GenPreparerName, preparerInfos } from './ScenarioTool'; @@ -26,9 +26,10 @@ export class CliTestPrepare extends TemplateBase { resourceNames: string[]; constructor(model: CodeModelAz, resourceNames: string[]) { super(model); + const { configHandler } = model.GetHandler(); this.resourceNames = resourceNames; this.relativePath = path.join( - model.AzextFolder, + configHandler.AzextFolder, PathConstants.testFolder, PathConstants.latestFolder, PathConstants.preparersFile, @@ -61,6 +62,7 @@ export class CliTestPrepare extends TemplateBase { } private CreatePreparer(model: CodeModelAz, resourceName: string) { + const { exampleHandler } = model.GetHandler(); const preparerInfo = preparerInfos[resourceName]; const preparerData = new PreparerData(GenPreparerName(preparerInfo.className)); for (let i = 0; i < preparerInfo.dependResources.length; i++) { @@ -99,12 +101,12 @@ export class CliTestPrepare extends TemplateBase { i++ ) { if ( - model + exampleHandler .GetResourcePool() .isResource( preparerInfos[preparerInfo.className].dependResources[i], null, - ) === model.GetResourcePool().isResource(depend, null) + ) === exampleHandler.GetResourcePool().isResource(depend, null) ) { variables.push( `self.test_class_instance.kwargs.get(self.${ diff --git a/src/generate/renders/tests/CliTestScenario.ts b/src/generate/renders/tests/CliTestScenario.ts index 1df526ac3..db4dcacb6 100644 --- a/src/generate/renders/tests/CliTestScenario.ts +++ b/src/generate/renders/tests/CliTestScenario.ts @@ -3,12 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *-------------------------------------------------------------------------------------------- */ import * as path from 'path'; -import { CodeModelAz, CommandExample } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { CliTestStep } from './CliTestStep'; import { ToMultiLine, Capitalize } from '../../../utils/helper'; import { HeaderGenerator } from '../Header'; import { TemplateBase } from '../TemplateBase'; import { CodeGenConstants, PathConstants } from '../../../utils/models'; +import { CommandExample } from '../../codemodel/Example'; export class CliTestScenario extends TemplateBase { public configValue: any; @@ -18,8 +19,9 @@ export class CliTestScenario extends TemplateBase { constructor(model: CodeModelAz, testFilename: string, configValue: any, groupName: string) { super(model); + const { configHandler } = model.GetHandler(); this.relativePath = path.join( - model.AzextFolder, + configHandler.AzextFolder, PathConstants.testFolder, PathConstants.latestFolder, testFilename, @@ -58,7 +60,8 @@ export class CliTestScenario extends TemplateBase { } private GenerateAzureCliTestScenario(model: CodeModelAz, config: any, scenarioName: string) { - const commandParams = model.GatherInternalResource(); + const { configHandler, exampleHandler } = model.GetHandler(); + const commandParams = exampleHandler.GatherInternalResource(); config.unshift({ function: `setup_${scenarioName}` }); config.push({ function: `cleanup_${scenarioName}` }); @@ -70,7 +73,7 @@ export class CliTestScenario extends TemplateBase { const testClassName = Capitalize(this.groupName) + scenarioName + 'Test'; classInfo.push('class ' + testClassName + '(ScenarioTest):'); - const subscriptionId = model.GetSubscriptionKey(); + const subscriptionId = exampleHandler.GetSubscriptionKey(); if (subscriptionId) { initiates.push(' self.kwargs.update({'); initiates.push(` '${subscriptionId}': self.get_subscription_id()`); @@ -101,7 +104,7 @@ export class CliTestScenario extends TemplateBase { ); function buildSenario(template: CliTestScenario, outputFunc: string[], minimum: boolean) { - model.GetResourcePool().clearExampleParams(); + exampleHandler.GetResourcePool().clearExampleParams(); // go through the examples to generate steps for (let ci = 0; ci < config.length; ci++) { @@ -113,7 +116,7 @@ export class CliTestScenario extends TemplateBase { let found = false; const examples: CommandExample[] = []; let exampleIdx = -1; - for (const exampleCmd of model.FindExampleById( + for (const exampleCmd of exampleHandler.FindExampleById( exampleId, commandParams, examples, @@ -123,7 +126,7 @@ export class CliTestScenario extends TemplateBase { exampleIdx += 1; if (exampleCmd && exampleCmd.length > 0) { found = true; - const checks = model.GetExampleChecks(examples[exampleIdx]); + const checks = exampleHandler.GetExampleChecks(examples[exampleIdx]); functionName = CliTestStep.ToFunctionName( { name: examples[exampleIdx].Id }, exampleCmd[0], @@ -179,9 +182,9 @@ export class CliTestScenario extends TemplateBase { ); if ( functionName.startsWith('setup_') && - model.GetResourcePool().hasTestResourceScenario + exampleHandler.GetResourcePool().hasTestResourceScenario ) { - steps.push(...model.GetResourcePool().setupWithArmTemplate()); + steps.push(...exampleHandler.GetResourcePool().setupWithArmTemplate()); } else { steps.push(' pass'); } @@ -199,7 +202,7 @@ export class CliTestScenario extends TemplateBase { outputFunc.push(''); } buildSenario(this, funcScenario, false); - if (model.GenMinTest) { + if (configHandler.GenMinTest) { funcMinScenario.push('@try_manual'); funcMinScenario.push( ...ToMultiLine( @@ -245,7 +248,7 @@ export class CliTestScenario extends TemplateBase { buildTestcase(testCaseName, false), ), ); - if (model.GenMinTest) { + if (configHandler.GenMinTest) { this.scenarios.push(...buildTestcase(testCaseName, true)); } } diff --git a/src/generate/renders/tests/CliTestStep.ts b/src/generate/renders/tests/CliTestStep.ts index 46cf1e6be..5a5f60c9e 100644 --- a/src/generate/renders/tests/CliTestStep.ts +++ b/src/generate/renders/tests/CliTestStep.ts @@ -3,12 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *-------------------------------------------------------------------------------------------- */ import * as path from 'path'; -import { CodeModelAz, CommandExample } from '../../CodeModelAz'; +import { CodeModelAz } from '../../codemodel/CodeModelAz'; import { PreparerEntity, getResourceKey } from './ScenarioTool'; import { ToMultiLine, deepCopy, isNullOrUndefined } from '../../../utils/helper'; import { HeaderGenerator } from '../Header'; import { TemplateBase } from '../TemplateBase'; import { CodeGenConstants, PathConstants, AzConfiguration } from '../../../utils/models'; +import { CommandExample } from '../../codemodel/Example'; let usePreparers: Set, shortToLongName, funcNames, allSteps, stepBuff: Record; @@ -27,8 +28,9 @@ export function NeedPreparers(): Set { export class CliTestStep extends TemplateBase { constructor(model: CodeModelAz) { super(model); + const { configHandler } = model.GetHandler(); this.relativePath = path.join( - model.AzextFolder, + configHandler.AzextFolder, PathConstants.testFolder, PathConstants.latestFolder, PathConstants.testStepFile, @@ -44,6 +46,7 @@ export class CliTestStep extends TemplateBase { } private GenerateAzureCliTestStep(model: CodeModelAz): string[] { + const { extensionHandler, configHandler, exampleHandler } = model.GetHandler(); initVars(); const steps: string[] = []; steps.push(''); @@ -51,15 +54,15 @@ export class CliTestStep extends TemplateBase { steps.push('from .. import try_manual'); steps.push(''); - const commandParams = model.GatherInternalResource(); + const commandParams = exampleHandler.GatherInternalResource(); let config: any = []; - if (model.GetResourcePool().hasTestResourceScenario) { - for (const g in model.Extension_TestScenario) { - for (const s in model.Extension_TestScenario[g]) - config.push(...model.Extension_TestScenario[g][s]); + if (exampleHandler.GetResourcePool().hasTestResourceScenario) { + for (const g in exampleHandler.Example_TestScenario) { + for (const s in exampleHandler.Example_TestScenario[g]) + config.push(...exampleHandler.Example_TestScenario[g][s]); } } else { - config = deepCopy(model.Extension_DefaultTestScenario); + config = deepCopy(exampleHandler.Example_DefaultTestScenario); } const header: HeaderGenerator = new HeaderGenerator(); @@ -70,7 +73,7 @@ export class CliTestStep extends TemplateBase { [], [], ); - model.GetResourcePool().clearExampleParams(); + exampleHandler.GetResourcePool().clearExampleParams(); // go through the examples to generate steps for (let ci = 0; ci < config.length; ci++) { @@ -90,7 +93,7 @@ export class CliTestStep extends TemplateBase { const examples: CommandExample[] = []; let exampleIdx = -1; let waitCmds: string[][]; - for (const exampleCmd of model.FindExampleById( + for (const exampleCmd of exampleHandler.FindExampleById( exampleId, commandParams, examples, @@ -116,7 +119,7 @@ export class CliTestStep extends TemplateBase { } found = true; if (isNullOrUndefined(waitCmds)) { - waitCmds = model.FindExampleWaitById(exampleId); + waitCmds = exampleHandler.FindExampleWaitById(exampleId); } const cmdString = exampleCmd.join('\n'); @@ -190,7 +193,7 @@ export class CliTestStep extends TemplateBase { steps.push(''); }; createStep(); - if (model.GenMinTest) createStep(true); + if (configHandler.GenMinTest) createStep(true); } else if (functionName) { steps.push(''); steps.push(`# Env ${functionName}`); @@ -237,12 +240,13 @@ export class CliTestStep extends TemplateBase { decorators: string[], initiates: string[], ): string[] { + const { extensionHandler, configHandler, exampleHandler } = model.GetHandler(); const decorated = []; const internalObjects = []; const parameterNames = []; - for (const entity of model.GetPreparerEntities() as PreparerEntity[]) { + for (const entity of exampleHandler.GetPreparerEntities() as PreparerEntity[]) { if (!entity.info.name) { - const created = model.GetTestUniqueResource + const created = configHandler.GetTestUniqueResource ? entity.info.createdObjectNames.length > 0 : entity.info.createdObjectNames.indexOf(entity.objectName) >= 0; internalObjects.push([ @@ -256,7 +260,7 @@ export class CliTestStep extends TemplateBase { // create preparers for outside dependency let line = ` @${entity.info.name}(name_prefix='clitest${ - model.Extension_NameUnderscored + extensionHandler.Extension_NameUnderscored }_${entity.objectName}'[:7], key='${getResourceKey( entity.info.className, entity.objectName, @@ -286,7 +290,7 @@ export class CliTestStep extends TemplateBase { if (internalObjects.length > 0) { initiates.push(' self.kwargs.update({'); for (const [className, kargsKey, hasCreateExample, objectName] of internalObjects) { - if (hasCreateExample && model.RandomizeNames) { + if (hasCreateExample && configHandler.RandomizeNames) { const RANDOMIZE_MIN_LEN = 4; let prefixLen = Math.floor(objectName.length / 2); if (objectName.length - prefixLen < RANDOMIZE_MIN_LEN) diff --git a/src/generate/renders/tests/ScenarioTool.ts b/src/generate/renders/tests/ScenarioTool.ts index 880dabfda..be78d1a87 100644 --- a/src/generate/renders/tests/ScenarioTool.ts +++ b/src/generate/renders/tests/ScenarioTool.ts @@ -1,4 +1,4 @@ -import { CommandExample, ExampleParam, KeyValueType } from '../../CodeModelAz'; +import { CommandExample, ExampleParam, KeyValueType } from '../../codemodel/Example'; import { deepCopy, isDict, diff --git a/src/modifiers.ts b/src/modifiers.ts index 7ad5046fd..7bf098659 100644 --- a/src/modifiers.ts +++ b/src/modifiers.ts @@ -35,6 +35,8 @@ interface WhereCommandDirective { description: string; }; }; + features?: any; + imports?: any; } function getFilterError(whereObject: any, prohibitedFilters: Array): string { @@ -67,6 +69,8 @@ function isWhereCommandDirective(it: any): it is WhereCommandDirective { const directive = it; const where = directive.where; const set = directive.set; + const features = directive.features; + const imports = directive.imports; if (where && (where.command || where['parameter-name'] || where.group)) { const prohibitedFilters = ['model-name', 'property-name', 'enum-name', 'enum-value-name']; let error = getFilterError(where, prohibitedFilters); @@ -133,6 +137,8 @@ export class Modifiers { directive.set !== undefined ? directive.set['parameter-name'] : undefined; const paramDescriptionReplacer = directive.set !== undefined ? directive.set['parameter-description'] : undefined; + const features = directive.features; + const imports = directive.imports; if ( !isNullOrUndefined(parameter.language['az'].name) && !isNullOrUndefined(parameterRegex) && @@ -146,6 +152,12 @@ export class Modifiers { parameter.language['az'].mapsto = parameter.language['az'].name.replace(/-/g, '_'); parameter.language['az'].description = paramDescriptionReplacer || parameter.language['az'].description; + if (!isNullOrUndefined(features)) { + parameter.language['az']['features'] = features; + } + if (!isNullOrUndefined(imports)) { + parameter.language['az']['imports'] = imports; + } } } @@ -154,6 +166,8 @@ export class Modifiers { const groupReplacer = directive.set !== undefined ? directive.set.group : undefined; const groupDescriptionReplacer = directive.set !== undefined ? directive.set['group-description'] : undefined; + const features = directive.features; + const imports = directive.imports; if ( !isNullOrUndefined(operationGroup.language['az']['command']) && !isNullOrUndefined(groupRegex) && @@ -177,6 +191,12 @@ export class Modifiers { operationGroup.language['az'].description = groupDescriptionReplacer || operationGroup.language['az'].description; this.groupChanged = true; + if (!isNullOrUndefined(features)) { + operationGroup.language['az']['features'] = features; + } + if (!isNullOrUndefined(imports)) { + operationGroup.language['az']['imports'] = imports; + } } } @@ -193,6 +213,8 @@ export class Modifiers { const groupReplacer = directive.set !== undefined ? directive.set.group : undefined; const commandDescriptionReplacer = directive.set !== undefined ? directive.set['command-description'] : undefined; + const features = directive.features; + const imports = directive.imports; if (this.groupChanged) { operation.language['az'].command = operationGroup.language['az'].command + ' ' + operation.language['az'].name; @@ -204,6 +226,12 @@ export class Modifiers { ) { operation.language['az'].description = commandDescriptionReplacer || operation.language['az'].description; + if (!isNullOrUndefined(features)) { + operation.language['az']['features'] = features; + } + if (!isNullOrUndefined(imports)) { + operation.language['az']['imports'] = imports; + } if (isNullOrUndefined(commandReplacer)) { return; } @@ -270,6 +298,51 @@ export class Modifiers { Text: ' newAzName:' + newAzName, }); } + if ( + !isNullOrUndefined(operation.language['az'].subCommandGroup) && + !isNullOrUndefined(groupRegex) && + operation.language['az'].subCommandGroup.match(groupRegex) + ) { + operation.language['az'].subCommandGroup = groupReplacer + ? groupRegex + ? operation.language['az'].subCommandGroup.replace(groupRegex, groupReplacer) + : groupReplacer + : operation.language['az'].subCommandGroup; + if (groupReplacer.match(operationGroup.language['az'].command)) { + const tmpCmdRegex = new RegExp(groupRegex.source.replace('$', ''), 'g'); + const tmpNameRegex = new RegExp( + groupRegex.source + .replace(operationGroup.language['az'].command + ' ', '') + .replace('$', ''), + 'g', + ); + const tmpNameReplacer = groupReplacer.replace( + operationGroup.language['az'].command + ' ', + '', + ); + operation.language['az'].command = groupReplacer + ? tmpCmdRegex + ? operation.language['az'].command.replace(tmpCmdRegex, groupReplacer) + : groupReplacer + : operation.language['az'].command; + operation.language['az'].name = tmpNameReplacer + ? tmpNameRegex + ? operation.language['az'].name.replace(tmpNameRegex, tmpNameReplacer) + : tmpNameReplacer + : operation.language['az'].name; + if (!isNullOrUndefined(features)) { + operation.language['az']['features'] = features; + } + if (!isNullOrUndefined(imports)) { + operation.language['az']['imports'] = imports; + } + } else { + this.session.message({ + Channel: Channel.Warning, + Text: ' Can not change the sub command group parent group name', + }); + } + } if ( !isNullOrUndefined(operation.language['az'].subCommandGroup) && !isNullOrUndefined(groupRegex) && diff --git a/test/scenarios/kusto/configuration/readme.az.md b/test/scenarios/kusto/configuration/readme.az.md index b28c4ddb4..d151f6718 100644 --- a/test/scenarios/kusto/configuration/readme.az.md +++ b/test/scenarios/kusto/configuration/readme.az.md @@ -53,4 +53,28 @@ az: package-name: azure-mgmt-kusto az-output-folder: $(azure-cli-folder)/src/azure-cli/azure/cli/command_modules/kusto python-sdk-output-folder: "$(az-output-folder)/vendored_sdks/kusto" + +directive: + - where: + command: kusto cluster remove-language-extension + features: + exception_handler: handle_template_based_exception + imports: + azure.cli.core.exception: handle_template_based_exception + - where: + command: kusto cluster add-language-extension + features: + completer: get_resource_name_completion_list('Microsoft.Network/expressRouteCircuits') + imports: + azure.cli.core.utils: get_resource_name_completion_list + - where: + group: kusto database + features: + exception_handler: handle_template_based_exception + imports: + azure.cli.core.exception: handle_template_based_exception + - where: + command: kusto database list + features: + option_list: "['--private-cloud', 123, True]" ``` \ No newline at end of file diff --git a/test/scenarios/kusto/output/coredefault/src/azure-cli/azure/cli/command_modules/kusto/generated/commands.py b/test/scenarios/kusto/output/coredefault/src/azure-cli/azure/cli/command_modules/kusto/generated/commands.py index ef6bb646f..1ba6db72f 100644 --- a/test/scenarios/kusto/output/coredefault/src/azure-cli/azure/cli/command_modules/kusto/generated/commands.py +++ b/test/scenarios/kusto/output/coredefault/src/azure-cli/azure/cli/command_modules/kusto/generated/commands.py @@ -13,6 +13,8 @@ # pylint: disable=line-too-long from azure.cli.core.commands import CliCommandType +from azure.cli.core.utils import get_resource_name_completion_list +from azure.cli.core.exception import handle_template_based_exception from ..generated._client_factory import ( cf_cluster, cf_cluster_principal_assignment, @@ -68,13 +70,23 @@ def load_command_table(self, _): g.custom_command('create', 'kusto_cluster_create', supports_no_wait=True) g.custom_command('update', 'kusto_cluster_update', supports_no_wait=True) g.custom_command('delete', 'kusto_cluster_delete', supports_no_wait=True, confirmation=True) - g.custom_command('add-language-extension', 'kusto_cluster_add_language_extension', supports_no_wait=True) + g.custom_command( + 'add-language-extension', + 'kusto_cluster_add_language_extension', + completer=get_resource_name_completion_list('Microsoft.Network/expressRouteCircuits'), + supports_no_wait=True, + ) g.custom_command('detach-follower-database', 'kusto_cluster_detach_follower_database', supports_no_wait=True) g.custom_command('diagnose-virtual-network', 'kusto_cluster_diagnose_virtual_network', supports_no_wait=True) g.custom_command('list-follower-database', 'kusto_cluster_list_follower_database') g.custom_command('list-language-extension', 'kusto_cluster_list_language_extension') g.custom_command('list-sku', 'kusto_cluster_list_sku') - g.custom_command('remove-language-extension', 'kusto_cluster_remove_language_extension', supports_no_wait=True) + g.custom_command( + 'remove-language-extension', + 'kusto_cluster_remove_language_extension', + exception_handler=handle_template_based_exception, + supports_no_wait=True, + ) g.custom_command('start', 'kusto_cluster_start', supports_no_wait=True) g.custom_command('stop', 'kusto_cluster_stop', supports_no_wait=True) g.custom_wait_command('wait', 'kusto_cluster_show') @@ -96,8 +108,14 @@ def load_command_table(self, _): ) g.custom_wait_command('wait', 'kusto_cluster_principal_assignment_show') - with self.command_group('kusto database', kusto_database, client_factory=cf_database, is_experimental=True) as g: - g.custom_command('list', 'kusto_database_list') + with self.command_group( + 'kusto database', + kusto_database, + client_factory=cf_database, + exception_handler=handle_template_based_exception, + is_experimental=True, + ) as g: + g.custom_command('list', 'kusto_database_list', option_list=['--private-cloud', 123, True]) g.custom_show_command('show', 'kusto_database_show') g.custom_command('create', 'kusto_database_create', supports_no_wait=True) g.custom_command('update', 'kusto_database_update', supports_no_wait=True) diff --git a/test/scenarios/kusto/output/coretrack2/src/azure-cli/azure/cli/command_modules/kusto/generated/commands.py b/test/scenarios/kusto/output/coretrack2/src/azure-cli/azure/cli/command_modules/kusto/generated/commands.py index 64ff2b953..f606333c5 100644 --- a/test/scenarios/kusto/output/coretrack2/src/azure-cli/azure/cli/command_modules/kusto/generated/commands.py +++ b/test/scenarios/kusto/output/coretrack2/src/azure-cli/azure/cli/command_modules/kusto/generated/commands.py @@ -13,6 +13,8 @@ # pylint: disable=line-too-long from azure.cli.core.commands import CliCommandType +from azure.cli.core.utils import get_resource_name_completion_list +from azure.cli.core.exception import handle_template_based_exception from ..generated._client_factory import ( cf_cluster, cf_cluster_principal_assignment, @@ -68,13 +70,23 @@ def load_command_table(self, _): g.custom_command('create', 'kusto_cluster_create', supports_no_wait=True) g.custom_command('update', 'kusto_cluster_update', supports_no_wait=True) g.custom_command('delete', 'kusto_cluster_delete', supports_no_wait=True, confirmation=True) - g.custom_command('add-language-extension', 'kusto_cluster_add_language_extension', supports_no_wait=True) + g.custom_command( + 'add-language-extension', + 'kusto_cluster_add_language_extension', + completer=get_resource_name_completion_list('Microsoft.Network/expressRouteCircuits'), + supports_no_wait=True, + ) g.custom_command('detach-follower-database', 'kusto_cluster_detach_follower_database', supports_no_wait=True) g.custom_command('diagnose-virtual-network', 'kusto_cluster_diagnose_virtual_network', supports_no_wait=True) g.custom_command('list-follower-database', 'kusto_cluster_list_follower_database') g.custom_command('list-language-extension', 'kusto_cluster_list_language_extension') g.custom_command('list-sku', 'kusto_cluster_list_sku') - g.custom_command('remove-language-extension', 'kusto_cluster_remove_language_extension', supports_no_wait=True) + g.custom_command( + 'remove-language-extension', + 'kusto_cluster_remove_language_extension', + exception_handler=handle_template_based_exception, + supports_no_wait=True, + ) g.custom_command('start', 'kusto_cluster_start', supports_no_wait=True) g.custom_command('stop', 'kusto_cluster_stop', supports_no_wait=True) g.custom_wait_command('wait', 'kusto_cluster_show') @@ -99,8 +111,14 @@ def load_command_table(self, _): ) g.custom_wait_command('wait', 'kusto_cluster_principal_assignment_show') - with self.command_group('kusto database', kusto_database, client_factory=cf_database, is_experimental=True) as g: - g.custom_command('list', 'kusto_database_list') + with self.command_group( + 'kusto database', + kusto_database, + client_factory=cf_database, + exception_handler=handle_template_based_exception, + is_experimental=True, + ) as g: + g.custom_command('list', 'kusto_database_list', option_list=['--private-cloud', 123, True]) g.custom_show_command('show', 'kusto_database_show') g.custom_command('create', 'kusto_database_create', supports_no_wait=True) g.custom_command('update', 'kusto_database_update', supports_no_wait=True) diff --git a/test/scenarios/kusto/output/ext_default_folder/src/kusto/azext_kusto/generated/custom.py b/test/scenarios/kusto/output/ext_default_folder/src/kusto/azext_kusto/generated/custom.py index b307294f0..b864220cb 100644 --- a/test/scenarios/kusto/output/ext_default_folder/src/kusto/azext_kusto/generated/custom.py +++ b/test/scenarios/kusto/output/ext_default_folder/src/kusto/azext_kusto/generated/custom.py @@ -83,11 +83,11 @@ def kusto_cluster_create(client, def kusto_cluster_update(client, resource_group_name, cluster_name, + name, + tier, tags=None, location=None, - name=None, capacity=None, - tier=None, trusted_external_tenants=None, optimized_autoscale=None, enable_disk_encryption=None, diff --git a/test/scenarios/kusto/output/ext_default_folder/src/kusto/report.md b/test/scenarios/kusto/output/ext_default_folder/src/kusto/report.md index dc8e6569d..1896eeee2 100644 --- a/test/scenarios/kusto/output/ext_default_folder/src/kusto/report.md +++ b/test/scenarios/kusto/output/ext_default_folder/src/kusto/report.md @@ -245,11 +245,11 @@ key-vault-uri="https://dummy.keyvault.com" key-version="keyVersion" --resource-g |------|----|-----------|----------|------------| |**--resource-group-name**|string|The name of the resource group containing the Kusto cluster.|resource_group_name|resourceGroupName| |**--cluster-name**|string|The name of the Kusto cluster.|cluster_name|clusterName| +|**--name**|choice|SKU name.|name|name| +|**--tier**|choice|SKU tier.|tier|tier| |**--tags**|dictionary|Resource tags.|tags|tags| |**--location**|string|Resource location.|location|location| -|**--name**|choice|SKU name.|name|name| |**--capacity**|integer|The number of instances of the cluster.|capacity|capacity| -|**--tier**|choice|SKU tier.|tier|tier| |**--trusted-external-tenants**|array|The cluster's external tenants.|trusted_external_tenants|trustedExternalTenants| |**--optimized-autoscale**|object|Optimized auto scale definition.|optimized_autoscale|optimizedAutoscale| |**--enable-disk-encryption**|boolean|A boolean value that indicates if the cluster's disks are encrypted.|enable_disk_encryption|enableDiskEncryption| diff --git a/test/scenarios/kusto/output/extnosdknoflattentrack1/src/kusto/azext_kusto/generated/custom.py b/test/scenarios/kusto/output/extnosdknoflattentrack1/src/kusto/azext_kusto/generated/custom.py index 88fa7c755..42c578958 100644 --- a/test/scenarios/kusto/output/extnosdknoflattentrack1/src/kusto/azext_kusto/generated/custom.py +++ b/test/scenarios/kusto/output/extnosdknoflattentrack1/src/kusto/azext_kusto/generated/custom.py @@ -83,11 +83,11 @@ def kusto_cluster_create(client, def kusto_cluster_update(client, resource_group_name, cluster_name, + name, + tier, tags=None, location=None, - name=None, capacity=None, - tier=None, trusted_external_tenants=None, optimized_autoscale=None, enable_disk_encryption=None, diff --git a/test/scenarios/kusto/output/extnosdknoflattentrack1/src/kusto/report.md b/test/scenarios/kusto/output/extnosdknoflattentrack1/src/kusto/report.md index dc8e6569d..1896eeee2 100644 --- a/test/scenarios/kusto/output/extnosdknoflattentrack1/src/kusto/report.md +++ b/test/scenarios/kusto/output/extnosdknoflattentrack1/src/kusto/report.md @@ -245,11 +245,11 @@ key-vault-uri="https://dummy.keyvault.com" key-version="keyVersion" --resource-g |------|----|-----------|----------|------------| |**--resource-group-name**|string|The name of the resource group containing the Kusto cluster.|resource_group_name|resourceGroupName| |**--cluster-name**|string|The name of the Kusto cluster.|cluster_name|clusterName| +|**--name**|choice|SKU name.|name|name| +|**--tier**|choice|SKU tier.|tier|tier| |**--tags**|dictionary|Resource tags.|tags|tags| |**--location**|string|Resource location.|location|location| -|**--name**|choice|SKU name.|name|name| |**--capacity**|integer|The number of instances of the cluster.|capacity|capacity| -|**--tier**|choice|SKU tier.|tier|tier| |**--trusted-external-tenants**|array|The cluster's external tenants.|trusted_external_tenants|trustedExternalTenants| |**--optimized-autoscale**|object|Optimized auto scale definition.|optimized_autoscale|optimizedAutoscale| |**--enable-disk-encryption**|boolean|A boolean value that indicates if the cluster's disks are encrypted.|enable_disk_encryption|enableDiskEncryption| diff --git a/test/unittest/render-getActionRenderData.ts b/test/unittest/render-getActionRenderData.ts index fe68d98ad..ab2979362 100644 --- a/test/unittest/render-getActionRenderData.ts +++ b/test/unittest/render-getActionRenderData.ts @@ -14,7 +14,7 @@ import { AzConfiguration, CodeGenConstants, ExtensionMode } from '../../src/util import { CliActions } from '../../src/generate/renders/generated/CliActions'; import { AzLinter } from '../../src/azlinter'; import { Entry } from '../../src/entry'; -import { CodeModelCliImpl } from '../../src/generate/CodeModelAzImpl'; +import { CodeModelCliImpl } from '../../src/generate/codemodel/CodeModelAzImpl'; import { createTestSession } from '../utils/test-helper'; sourceMapSupport.install(); @@ -42,7 +42,8 @@ describe('getActionsRender', () => { await entry.init(); const codeModel = new CodeModelCliImpl(session); - codeModel.GenerateTestInit(); + const { exampleHandler } = codeModel.GetHandler(); + exampleHandler.GenerateTestInit(); model = codeModel; } diff --git a/test/unittest/render-getCommandsRenderData.ts b/test/unittest/render-getCommandsRenderData.ts index 4078acd4a..3ea98037d 100644 --- a/test/unittest/render-getCommandsRenderData.ts +++ b/test/unittest/render-getCommandsRenderData.ts @@ -14,7 +14,7 @@ import { AzConfiguration, CodeGenConstants, ExtensionMode } from '../../src/util import { CliCommands } from '../../src/generate/renders/generated/CliCommands'; import { AzLinter } from '../../src/azlinter'; import { Entry } from '../../src/entry'; -import { CodeModelCliImpl } from '../../src/generate/CodeModelAzImpl'; +import { CodeModelCliImpl } from '../../src/generate/codemodel/CodeModelAzImpl'; import { createTestSession } from '../utils/test-helper'; sourceMapSupport.install(); @@ -42,7 +42,8 @@ describe('getCommandsRender', () => { await entry.init(); const codeModel = new CodeModelCliImpl(session); - codeModel.GenerateTestInit(); + const { exampleHandler } = codeModel.GetHandler(); + exampleHandler.GenerateTestInit(); model = codeModel; } diff --git a/test/unittest/render-getRenderData.ts b/test/unittest/render-getRenderData.ts index 1b41dba65..87a1a7c37 100644 --- a/test/unittest/render-getRenderData.ts +++ b/test/unittest/render-getRenderData.ts @@ -11,7 +11,7 @@ import { CodeModel, SchemaType } from '@azure-tools/codemodel'; import * as sourceMapSupport from 'source-map-support'; import { CodeModelTypes, DataGraph, RenderInput, SortOrder } from '../../src/utils/models'; import { Entry } from '../../src/entry'; -import { CodeModelCliImpl } from '../../src/generate/CodeModelAzImpl'; +import { CodeModelCliImpl } from '../../src/generate/codemodel/CodeModelAzImpl'; import { isNullOrUndefined } from '../../src/utils/helper'; import { createTestSession } from '../utils/test-helper'; @@ -40,7 +40,8 @@ describe('RenderSetupPy', () => { await entry.init(); const codeModel = new CodeModelCliImpl(session); - codeModel.GenerateTestInit(); + const { exampleHandler } = codeModel.GetHandler(); + exampleHandler.GenerateTestInit(); model = codeModel; }