async addVariants()

in powershell/plugins/create-commands-v2.ts [561:697]


  async addVariants(parameters: Array<Parameter> | undefined, operation: Operation, variant: CommandVariant, vname: string, state: State, preOperations?: Array<Operation>, commandType?: CommandType) {
    // now synthesize parameter set variants multiplexed by the variants.
    const [constants, requiredParameters] = values(parameters).bifurcate(parameter => parameter.language.default.constantValue || parameter.language.default.fromHost ? true : false);
    const constantParameters = constants.map(each => `'${each.language.default.constantValue}'`);

    // the body parameter
    // xichen: How to handle if has multiple requests?
    const body = operation.requests?.[0].parameters?.find((p) => !p.origin || p.origin.indexOf('modelerfour:synthesized') < 0) || null;
    // skip-for-time-being, looks x-ms-requestBody-name is not supported any more
    //const bodyParameterName = (operation.requestBody && operation.requestBody.extensions) ? operation.requestBody.extensions['x-ms-requestBody-name'] || 'bodyParameter' : '';
    const bodyParameterName = body ? body.language.default.name : '';

    // all the properties in the body parameter
    const bodyProperties = (body && body.schema && isObjectSchema(body.schema)) ? values(getAllProperties(body.schema)).where(property => !property.language.default.readOnly).toArray() : [];

    // smash body property names together
    const bodyPropertyNames = bodyProperties.joinWith(each => each.language.default.name);

    // for each polymorphic body, we should do a separate variant that takes the polymorphic body type instead of the base type
    // skip-for-time-being, this is for polymorphism
    //const polymorphicBodies = (body && body.schema && body.schema.details.default.polymorphicChildren && length(body.schema.details.default.polymorphicChildren)) ? (<Array<Schema>>body.schema.details.default.polymorphicChildren).joinWith(child => child.details.default.name) : '';

    // wait! "update" should be "set" if it's a PUT
    if (variant.verb === 'Update' && operation.requests && operation.requests[0].protocol?.http?.method === HttpMethod.Put) {
      variant.verb = 'Set';
    }
    //for operations which has pre operations (only support GET+PUT for now), change it's action to update
    if (preOperations && preOperations.length > 0) {
      variant.action = variant.verb = 'Update';
    }
    // create variant 
    // skip-for-time-being, since operationId looks not included in m4.
    //state.message({ Channel: Channel.Debug, Text: `${variant.verb}-${variant.subject} //  ${operation.operationId} => ${JSON.stringify(variant)} taking ${requiredParameters.joinWith(each => each.name)}; ${constantParameters} ; ${bodyPropertyNames} ${polymorphicBodies ? `; Polymorphic bodies: ${polymorphicBodies} ` : ''}` });
    await this.addVariant(pascalCase([variant.action, vname]), body, bodyParameterName, [...constants, ...requiredParameters], operation, variant, state, preOperations, commandType);

    if (await state.getValue('disable-via-identity', false)) {
      return;
    }

    // eslint-disable-next-line prefer-const
    let [pathParams, otherParams] = values(requiredParameters).bifurcate(each => each?.protocol?.http?.in === ParameterLocation.Path);
    //exclude subscriptionId and resourceGroupName from path parameters
    pathParams = pathParams.filter(pathParam => !this.reservedPathParam.has(pathParam.language.default.name));
    //if parent pipline input is disabled, only generate identity for current resource itself
    if (!await state.getValue('enable-parent-pipeline-input', this.isAzure)) {
      if (length(pathParams) > 0 && variant.action.toLowerCase() != 'list') {
        await this.addVariant(pascalCase([variant.action, vname, 'via-identity']), body, bodyParameterName, [...constants, ...otherParams], operation, variant, state, preOperations, commandType);
      }
      return;
    }

    const disableGetEnableList = await this.state.getValue('enable-parent-pipeline-input-for-list', false);
    /*
      for resource /A1/A2/.../An-1/An, generate variants that take
        ViaIdentity: An as identity
        ViaIdentity{An-1}: An-1 as identity + An Name
        ...
        ViaIdentity{A1}: A1 as identity + [A2 + A3 + ... + An-1 + An] Names
    */
    for (let i = pathParams.length - 1; i >= 0; i--) {
      if ((!disableGetEnableList && variant.action.toLowerCase() === 'list') || (disableGetEnableList && i === pathParams.length - 1 && variant.action.toLowerCase() === 'get')) {
        continue;
      }
      let resourceName = getResourceNameFromPath(operation.requests?.[0].protocol.http?.path, pathParams[i].language.default.name, true);
      //cannot get resource name from path, give up generate ViaIdentity variant
      if (!resourceName) {
        break;
      }

      //variant for current resource is simply named ViaIdentity otherwise ViaIdentity${resourceName}
      if (i === pathParams.length - 1 && variant.action.toLowerCase() !== 'list') {
        resourceName = '';
      }
      await this.addVariant(pascalCase([variant.action, vname, `via-identity${resourceName}`]), body, bodyParameterName, [...constants, ...otherParams, ...pathParams.slice(i + 1)], operation, variant, state, preOperations, commandType);
    }

    if (this.supportJsonInput && hasValidBodyParameters(operation) &&
      commandType != CommandType.GetPut && commandType != CommandType.ManagedIdentityUpdate) {
      const createStringParameter = (name: string, description: string, serializedName: string): IParameter => {
        const schema = new SchemaModel(name, description, SchemaType.String);
        const language = {
          default: {
            name: name,
            description: description,
            serializedName: serializedName,
          },
        };
        schema.language = language;
        const httpParameter = {
          implementation: 'Method',
          language: language,
          schema: schema,
          required: true,
        };
        const parameter = new IParameter(name, schema, {
          description: description,
          required: true,
          details: {
            default: {
              description: description,
              name: name,
              isBodyParameter: false,
              httpParameter: httpParameter,
            },
          },
          schema: schema,
          allowEmptyValue: false,
          deprecated: false,
        });
        (<any>parameter).httpParameter = httpParameter;
        return parameter;
      };
      const jsonVariant = pascalCase([variant.action, vname]);
      const parameter = new IParameter(`${bodyParameterName}Body`, body!.schema, {
        details: {
          default: {
            description: body!.schema.language.default.description,
            name: pascalCase(`${bodyParameterName}Body`),
            isBodyParameter: true,
          }
        }
      });
      const opJsonString = await this.addVariant(`${jsonVariant}ViaJsonString`, null, '', [...constants, ...requiredParameters], operation, variant, state, preOperations, commandType);
      opJsonString.details.default.dropBodyParameter = true;
      opJsonString.parameters = opJsonString.parameters.filter(each => each.details.default.isBodyParameter !== true);
      opJsonString.parameters.push(createStringParameter('JsonString', `Json string supplied to the ${jsonVariant} operation`, 'jsonString'));
      opJsonString.parameters.push(parameter);
      opJsonString.details.default.dropBodyParameter = true;

      const opJsonFilePath = await this.addVariant(`${jsonVariant}ViaJsonFilePath`, null, '', [...constants, ...requiredParameters], operation, variant, state, preOperations, commandType);
      opJsonFilePath.details.default.dropBodyParameter = true;
      opJsonFilePath.parameters = opJsonFilePath.parameters.filter(each => each.details.default.isBodyParameter !== true);
      opJsonFilePath.parameters.push(createStringParameter('JsonFilePath', `Path of Json file supplied to the ${jsonVariant} operation`, 'jsonFilePath'));
      opJsonFilePath.parameters.push(parameter);
      opJsonFilePath.details.default.dropBodyParameter = true;
    }
  }