private NewAddPowershellParameters()

in powershell/cmdlets/class.ts [1770:2131]


  private NewAddPowershellParameters(operation: CommandOperation) {
    const vps = operation.details.csharp.virtualParameters || {
      body: [],
      operation: [],
    };

    for (const parameter of values(operation.parameters)) {
      // these are the parameters that this command expects
      parameter.schema;
      const td = this.state.project.schemaDefinitionResolver.resolveTypeDeclaration(<NewSchema>parameter.schema, true, this.state, this.state.project.fixedArray);

      if (parameter.details.csharp.constantValue) {
        // this parameter has a constant value -- SKIP IT
        continue;
      }

      if (parameter.details.csharp.fromHost) {
        // the parameter is expected to be gotten from the host.(ie, Az.Accounts)

        const hostParameter = this.add(new BackedProperty(parameter.details.csharp.name, td, {
          metadata: {
            parameterDefinition: parameter.details.csharp.httpParameter
          },
          description: parameter.details.csharp.description,
        }));
        this.thingsToSerialize.push(hostParameter);
        // in the BeginProcessing, we should tell it to go get the value for this property from the common module
        this.$<Method>('BeginProcessing').add(hostParameter.assignPrivate(new LiteralExpression(`${this.state.project.serviceNamespace.moduleClass.declaration}.Instance.GetParameter(this.MyInvocation, ${this.correlationId.value}, "${parameter.name}") as string`)));
        continue;
      }
      const $this = this;

      if (parameter.details.csharp.apiversion) {
        // Api-version parameters for azure are a custom implementation
        this.add(new Property(parameter.details.csharp.name, td, {
          getAccess: Access.Internal,
          setAccess: Access.Private,
          metadata: {
            parameterDefinition: parameter.details.csharp.httpParameter
          },
          description: parameter.details.csharp.description,
          *get() {
            const metadata = operation.extensions['x-ms-metadata'];
            const profiles = <Dictionary<string>>metadata.profiles || new Dictionary<string>();

            yield Switch(`${$this.state.project.serviceNamespace.moduleClass.declaration}.Instance.Profile`, function* () {
              for (const { key: profileName, value: apiVersion } of items(profiles)) {
                yield TerminalCase(`"${profileName}"`, Return(`"${apiVersion}"`));
              }
              yield TerminalDefaultCase(Return(`"${metadata.apiVersions[0]}"`));
            });
          }
        }));
        continue;
      }

      if (this.dropBodyParameter && parameter.details.csharp.isBodyParameter) {
        // we're supposed to use parameters for the body parameter instead of a big object
        const expandedBodyParameter = this.add(new Field('_' + camelCase(parameter.details.csharp.name), td, {
          description: parameter.details.csharp.description,
          initialValue: (parameter.schema.type === SchemaType.Array) ? dotnet.Null : `new ${parameter.schema.language.csharp?.fullname}()`,
          access: Access.Private
        }));
        this.thingsToSerialize.push(expandedBodyParameter);

        for (const vParam of vps.body) {
          const vSchema = vParam.schema;
          const schemaProperty = <NewVirtualProperty>vParam.origin;
          const propertyType = this.state.project.schemaDefinitionResolver.resolveTypeDeclaration(vSchema, true, this.state, this.state.project.fixedArray);

          // we need to know if the actual underlying property is actually nullable.
          const nullable = this.state.project.schemaDefinitionResolver.resolveTypeDeclaration(vSchema, !!(schemaProperty.required && schemaProperty.read && schemaProperty.create && schemaProperty.update), this.state, this.state.project.fixedArray).isNullable;
          let cmdletParameter: Property;
          if (propertyType.schema.type !== SchemaType.Array || this.state.project.fixedArray) {
            if (vParam.name === 'IdentityType' && !this.disableTransformIdentityType &&
              (this.operation.commandType === CommandType.ManagedIdentityNew || this.operation.commandType === CommandType.ManagedIdentityUpdate)) {
              const enableSystemAssignedIdentity = new Property('EnableSystemAssignedIdentity', operation.details.csharp.verb.toLowerCase() === 'new' ? SwitchParameter : NullableBoolean, {
                set: operation.details.csharp.verb.toLowerCase() === 'new' ? toExpression(`${expandedBodyParameter.value}.${getVirtualPropertyName((<any>vParam.origin)) || vParam.origin.name} = value.IsPresent ? "SystemAssigned": null `) : undefined
              });
              enableSystemAssignedIdentity.description = 'Determines whether to enable a system-assigned identity for the resource.';
              enableSystemAssignedIdentity.add(new Attribute(ParameterAttribute, { parameters: [new LiteralExpression(`Mandatory = ${vParam.required && operation.details.csharp.verb.toLowerCase() !== 'new' ? 'true' : 'false'}`), new LiteralExpression(`HelpMessage = "${escapeString(enableSystemAssignedIdentity.description || '.')}"`)] }));
              if (length(vParam.alias) > 0) {
                enableSystemAssignedIdentity.add(new Attribute(Alias, { parameters: vParam.alias.map(x => '"' + x + '"') }));
              }
              this.add(enableSystemAssignedIdentity);
              continue;
            }

            if (vParam.name === 'IdentityUserAssignedIdentity' || vParam.name === 'UserAssignedIdentity') {
              if (this.flattenUserAssignedIdentity && vParam.schema.type === 'dictionary') {
                const userAssignedIdentity = new Property('UserAssignedIdentity', dotnet.StringArray);
                userAssignedIdentity.description = 'The array of user assigned identities associated with the resource. The elements in array will be ARM resource ids in the form: \'/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName}.\'';
                userAssignedIdentity.add(new Attribute(ParameterAttribute, { parameters: [new LiteralExpression(`Mandatory = ${vParam.required ? 'true' : 'false'}`), new LiteralExpression(`HelpMessage = "${escapeString(userAssignedIdentity.description || '.')}"`)] }));
                userAssignedIdentity.add(new Attribute(AllowEmptyCollectionAttribute));
                if (length(vParam.alias) > 0) {
                  userAssignedIdentity.add(new Attribute(Alias, { parameters: vParam.alias.map(x => '"' + x + '"') }));
                }
                this.add(userAssignedIdentity);
                continue;
              }
            }
            cmdletParameter = new Property(vParam.name, propertyType, {
              get: toExpression(`${expandedBodyParameter.value}.${getVirtualPropertyName((<any>vParam.origin)) || vParam.origin.name}${!nullable ? '' : ` ?? ${propertyType.defaultOfType}`}`), // /* ${inspect(vParam.origin)} */
              // get: toExpression(`null == ${expandedBodyParameter.value}.${vParam.origin.name} ? ${propertyType.defaultOfType} : (${propertyType.declaration}) ${expandedBodyParameter.value}.${vParam.origin.name}`),
              set: toExpression(`${expandedBodyParameter.value}.${getVirtualPropertyName((<any>vParam.origin)) || vParam.origin.name} = value`),
              new: PropertiesRequiringNew.has(vParam.name) ? Modifier.New : Modifier.None
            });
          } else {
            const fixedArrayPropertyType = this.state.project.schemaDefinitionResolver.resolveTypeDeclaration(vSchema, true, this.state, true);
            cmdletParameter = new Property(vParam.name, fixedArrayPropertyType, {
              get: toExpression(`${expandedBodyParameter.value}.${getVirtualPropertyName((<any>vParam.origin)) || vParam.origin.name}?.ToArray()${` ?? ${fixedArrayPropertyType.defaultOfType}`}`),
              set: toExpression(`${expandedBodyParameter.value}.${getVirtualPropertyName((<any>vParam.origin)) || vParam.origin.name} = (value != null ? new ${propertyType.declaration}(value) : null)`),
              new: PropertiesRequiringNew.has(vParam.name) ? Modifier.New : Modifier.None
            });
          }
          if (vParam.schema.language.csharp?.byReference) {
            // this parameter's schema is marked as 'by-reference' which means we should
            // tag it with an ExportAs attribute for the I*Reference type.
            cmdletParameter.add(new Attribute(ExportAsAttribute, { parameters: [`typeof(${vParam.schema.language.csharp.referenceInterface})`] }));
          }

          if (vParam.schema.type === SchemaType.Array) {
            //skip-for-time-being
            // if ((<ArraySchema>vParam.schema). && vParam.schema.items.details.csharp.byReference) {
            //   cmdletParameter.add(new Attribute(ExportAsAttribute, { parameters: [`typeof(${vParam.schema.items.details.csharp.referenceInterface}[])`] }));
            // }
            cmdletParameter.add(new Attribute(AllowEmptyCollectionAttribute));
          }
          const dictSchema = vSchema.type === SchemaType.Dictionary ? vSchema :
            vSchema.type === SchemaType.Object ? (<ObjectSchema>vSchema).parents?.immediate?.find((s) => s.type === SchemaType.Dictionary) :
              undefined;
          if (dictSchema) {
            // we have to figure out if this is a standalone dictionary or a hybrid object/dictionary.
            // if it's a hybrid, we have to create another parameter like -<XXX>AdditionalProperties and have that dump the contents into the dictionary
            // if it's a standalone dictionary, we can just use hashtable instead
            if (length((<ObjectSchema>vSchema).properties) === 0) {
              // it's a pure dictionary
              // add an attribute for changing the exported type.
              cmdletParameter.add(new Attribute(ExportAsAttribute, { parameters: [`typeof(${System.Collections.Hashtable})`] }));
            } else {
              // it's a hybrid. We need to add an additional property that puts its items into the target container

            }

          }

          const desc = (vParam.description || '.').replace(/[\r\n]/gm, '');
          cmdletParameter.description = desc;

          // check if this parameter is a byte array, which would indicate that it should really be a file input
          if (cmdletParameter.type.declaration === dotnet.Binary.declaration) {
            // set the generated parameter to internal
            cmdletParameter.setAccess = Access.Internal;
            cmdletParameter.getAccess = Access.Internal;

            // create a InputFileXXX for the parameter
            const ifname = vParam.name.toLowerCase() === 'value' ? 'InputFile' : pascalCase([vParam.name, 'Input', 'File']);

            const inputFileParameter = new Property(ifname, dotnet.String, {
              // get: toExpression(`${expandedBodyParameter.value}.${vParam.origin.name}${vParam.required ? '' : ` ?? ${propertyType.defaultOfType}`}`),
              set: function* () {
                const provider = Local('provider');
                provider.initializer = undefined;
                const paths = Local('paths', `this.SessionState.Path.GetResolvedProviderPathFromPSPath(value, out ${provider.declarationExpression})`);
                yield paths.declarationStatement;
                yield If(`${provider.value}.Name != "FileSystem" || ${paths.value}.Count == 0`, 'ThrowTerminatingError( new System.Management.Automation.ErrorRecord(new global::System.Exception("Invalid input path."),string.Empty, global::System.Management.Automation.ErrorCategory.InvalidArgument, value) );');
                yield If(`${paths.value}.Count > 1`, 'ThrowTerminatingError( new System.Management.Automation.ErrorRecord(new global::System.Exception("Multiple input paths not allowed."),string.Empty, global::System.Management.Automation.ErrorCategory.InvalidArgument, value) );');
                yield cmdletParameter.assign(`global::System.IO.File.ReadAllBytes(${paths.value}[0])`);
              },
              description: `Input File for ${cmdletParameter.name} (${escapeString(desc)})`
            });

            inputFileParameter.add(new Attribute(ParameterAttribute, { parameters: [new LiteralExpression(`Mandatory = ${vParam.required ? 'true' : 'false'}`), new LiteralExpression(`HelpMessage = "Input File for ${cmdletParameter.name} (${escapeString(desc || '.')})"`)] }));
            inputFileParameter.add(new Attribute(CategoryAttribute, { parameters: [`${ParameterCategory}.Body`] }));
            if (length(vParam.alias) > 0) {
              inputFileParameter.add(new Attribute(Alias, { parameters: vParam.alias.map(x => '"' + x + '"') }));
            }
            $this.add(inputFileParameter);
          } else {
            cmdletParameter.add(new Attribute(ParameterAttribute, { parameters: [new LiteralExpression(`Mandatory = ${vParam.required ? 'true' : 'false'}`), new LiteralExpression(`HelpMessage = "${escapeString(desc || '.')}"`)] }));
            cmdletParameter.add(new Attribute(CategoryAttribute, { parameters: [`${ParameterCategory}.Body`] }));
            NewAddInfoAttribute(cmdletParameter, propertyType, !!vParam.required, false, desc, (<NewVirtualProperty>vParam.origin).property.serializedName);
            NewAddCompleterInfo(cmdletParameter, vParam);
            addParameterBreakingChange(cmdletParameter, vParam);
            addParameterPreviewMessage(cmdletParameter, vParam);
            addDefaultInfo(cmdletParameter, vParam);
            this.addDoNotExport(cmdletParameter, vParam);
          }

          const addArgumentCompleter = isEnumImplementation(vParam.schema) || propertyType instanceof ArrayOf && isEnumImplementation((<ArraySchema>propertyType.schema).elementType);
          if (addArgumentCompleter) {
            propertyType instanceof ArrayOf ? addPSArgumentCompleterAttribute(cmdletParameter, (<ArraySchema>propertyType?.schema)?.elementType) : addPSArgumentCompleterAttribute(cmdletParameter, vParam.schema);
          }

          // add aliases if there is any
          if (length(vParam.alias) > 0) {
            cmdletParameter.add(new Attribute(Alias, { parameters: vParam.alias.map(x => '"' + x + '"') }));
          }
          this.add(cmdletParameter);
        }
        const paramDictSchema = parameter.schema.type === SchemaType.Dictionary ? parameter.schema :
          parameter.schema.type === SchemaType.Object ? (<ObjectSchema>parameter.schema).parents?.immediate?.find((s) => s.type === SchemaType.Dictionary) :
            undefined;
        if (paramDictSchema) {
          // if there is an additional properties on this type
          // add a hashtable parameter for additionalProperties
          let apPropName = '';
          const options = ['AdditionalProperties', 'MoreProperties', 'ExtendedProperties', 'Properties'];
          for (const n of options) {
            if (this.properties.find(each => each.name === n)) {
              continue;
            }
            apPropName = n;
            break;
          }

          this.apProp = this.add(new Property(apPropName, System.Collections.Hashtable));
          this.apProp.add(new Attribute(ParameterAttribute, {
            parameters: ['Mandatory = false', 'HelpMessage = "Additional Parameters"']
          }));
          this.bodyParameterInfo = {
            type: {
              declaration: parameter.schema.language.csharp?.fullname
            },
            valueType: (<DictionarySchema>paramDictSchema).elementType.type === SchemaType.Any ? System.Object :
              this.state.project.schemaDefinitionResolver.resolveTypeDeclaration((<DictionarySchema>paramDictSchema).elementType, true, this.state, this.state.project.fixedArray)
          };
        }

        this.bodyParameter = expandedBodyParameter;
        continue;
      }
    }

    if (this.isViaIdentity) {
      const viaIdentityRegex = /ViaIdentity\d?/g;
      this.inputObjectParameterName = `${this.name.split(viaIdentityRegex)[1].split('Expanded')[0]}InputObject`;
      // add in the pipeline parameter for the identity
      const idschema = values(this.state.project.model.schemas.objects).first(each => each.language.default.uid === 'universal-parameter-type');
      const idtd = this.state.project.schemaDefinitionResolver.resolveTypeDeclaration(idschema, true, this.state, this.state.project.fixedArray);
      const idParam = this.add(new BackedProperty(this.inputObjectParameterName, idtd, {
        description: 'Identity Parameter'
      }));
      const parameters = [new LiteralExpression('Mandatory = true'), new LiteralExpression('HelpMessage = "Identity Parameter"'), new LiteralExpression('ValueFromPipeline = true')];
      idParam.add(new Attribute(ParameterAttribute, { parameters }));
      idParam.add(new Attribute(CategoryAttribute, { parameters: [`${ParameterCategory}.Path`] }));
    }
    for (const vParam of values(vps.operation)) {
      if (vParam.name === 'Host') {
        // skip 'Host'
        continue;
      }
      let regularCmdletParameter: BackedProperty;
      let origin = null;
      let propertyType = null;
      if (vParam.type) {
        // Handle parameters added through directives
        regularCmdletParameter = this.add(new BackedProperty(vParam.name, new ClassType('', vParam.type), {
          description: vParam.description
        }));
      } else {
        const vSchema = vParam.schema;
        propertyType = this.state.project.schemaDefinitionResolver.resolveTypeDeclaration(vSchema, true, this.state, this.state.project.fixedArray);


        origin = <NewIParameter>vParam.origin;

        regularCmdletParameter = (this.state.project.azure && vParam.name === 'SubscriptionId' && operation.details.csharp.verb.toLowerCase() === 'get') ?

          // special case for subscription id
          this.add(new BackedProperty(vParam.name, dotnet.StringArray, {
            metadata: {
              parameterDefinition: origin.details.csharp.httpParameter
            },
            description: vParam.description
          })) :

          // everything else
          this.add(new BackedProperty(vParam.name, propertyType, {
            metadata: {
              parameterDefinition: origin.details.csharp.httpParameter
            },
            description: vParam.description
          }));

        const dictSchema = vSchema.type === SchemaType.Dictionary ? vSchema :
          vSchema.type === SchemaType.Object ? (<ObjectSchema>vSchema).parents?.immediate?.find((s) => s.type === SchemaType.Dictionary) :
            undefined;
        if (dictSchema) {
          // we have to figure out if this is a standalone dictionary or a hybrid object/dictionary.
          // if it's a hybrid, we have to create another parameter like -<XXX>AdditionalProperties and have that dump the contents into the dictionary
          // if it's a standalone dictionary, we can just use hashtable instead
          if (length((<ObjectSchema>vSchema).properties) === 0) {
            // it's a pure dictionary
            // change the property type to hashtable.
            // add an attribute to change the exported type.
            regularCmdletParameter.add(new Attribute(ExportAsAttribute, { parameters: [`typeof(${System.Collections.Hashtable})`] }));
          } else {
            // it's a hybrid. We need to add an additional property that puts its items into the target container

          }

        }
      }
      this.thingsToSerialize.push(regularCmdletParameter);

      const parameters = [new LiteralExpression(`Mandatory = ${vParam.required ? 'true' : 'false'}`), new LiteralExpression(`HelpMessage = "${escapeString(vParam.description) || '.'}"`)];
      if (!!origin && origin.details.csharp.isBodyParameter) {
        parameters.push(new LiteralExpression('ValueFromPipeline = true'));
        this.bodyParameter = regularCmdletParameter;
      }
      regularCmdletParameter.add(new Attribute(ParameterAttribute, { parameters }));
      if (!vParam.type && vParam.schema.type === SchemaType.Array) {
        regularCmdletParameter.add(new Attribute(AllowEmptyCollectionAttribute));
      }
      if (!!origin && !!propertyType) {
        NewAddInfoAttribute(regularCmdletParameter, propertyType, vParam.required ?? false, false, vParam.description, origin.name);
      }
      NewAddCompleterInfo(regularCmdletParameter, vParam);
      addParameterBreakingChange(regularCmdletParameter, vParam);
      addParameterPreviewMessage(regularCmdletParameter, vParam);
      addDefaultInfo(regularCmdletParameter, vParam);
      this.addDoNotExport(regularCmdletParameter, vParam);

      // add aliases if there is any
      if (length(vParam.alias) > 0) {
        regularCmdletParameter.add(new Attribute(Alias, { parameters: vParam.alias.map(x => '"' + x + '"') }));
      }

      const httpParam = origin ? origin.details.csharp.httpParameter : null;
      //const uid = httpParam ? httpParam.details.csharp.uid : 'no-parameter';

      if (httpParam) {
        // xichen: Is it safe to compare by csharp serializedName? Because we no longer have uid
        const cat = this.apiCall.parameters?.find((param) => !param.language.csharp?.constantValue && param.language.csharp?.serializedName === httpParam.language.csharp?.serializedName);

        if (cat) {
          regularCmdletParameter.add(new Attribute(CategoryAttribute, { parameters: [`${ParameterCategory}.${pascalCase((cat.protocol.http?.in))}`] }));
        }
      } else {
        const isBodyParameter = origin ? origin.details.csharp.isBodyParameter : false;
        if (isBodyParameter) {
          regularCmdletParameter.add(
            new Attribute(CategoryAttribute, {
              parameters: [`${ParameterCategory}.Body`],
            })
          );
        }
      }

      const addArgumentCompleter = isEnumImplementation(vParam.schema) || propertyType instanceof ArrayOf && isEnumImplementation((<ArraySchema>propertyType.schema).elementType);
      if (addArgumentCompleter) {
        propertyType instanceof ArrayOf ? addPSArgumentCompleterAttribute(regularCmdletParameter, (<ArraySchema>propertyType?.schema)?.elementType) : addPSArgumentCompleterAttribute(regularCmdletParameter, vParam.schema);
      }

    }
    const ifmatch = this.properties.find((v) => v.name.toLowerCase() === 'ifmatch');
    if (ifmatch) {
      //no sure why there is an empty block
    }

  }