private NewAddClassAttributes()

in powershell/cmdlets/class.ts [2149:2352]


  private NewAddClassAttributes(operation: CommandOperation, variantName: string) {
    const cmdletAttribParams: Array<ExpressionOrLiteral> = [
      category[operation.details.csharp.verb] ? verbEnum(category[operation.details.csharp.verb], operation.details.csharp.verb) : `"${operation.details.csharp.verb}"`,
      new StringExpression(variantName)
    ];

    if (isWritableCmdlet(operation) && !operation.details.csharp.supportShouldProcess) {
      cmdletAttribParams.push('SupportsShouldProcess = true');
    }

    if (this.clientsidePagination) {
      cmdletAttribParams.push('SupportsPaging = true');
    }

    if (operation.details.csharp.hidden) {
      this.add(new Attribute(InternalExportAttribute));
      const noun = `${operation.details.csharp.subjectPrefix}${operation.details.csharp.subject}`;
      const cmdletName = `${operation.details.csharp.verb}-${noun}${operation.details.csharp.name ? `_${operation.details.csharp.name}` : ''}`;
      this.state.message({ Channel: Channel.Debug, Text: `[DIRECTIVE] Applied 'hide' directive to ${cmdletName}. Added attribute ${InternalExportAttribute.declaration} to cmdlet.` });
    }

    this.add(new Attribute(CmdletAttribute, { parameters: cmdletAttribParams }));

    // add alias attribute if there is any aliases for this cmdlet
    if (length(operation.details.csharp.alias) > 0) {
      this.add(new Attribute(Alias, { parameters: operation.details.csharp.alias.map((x: string) => '"' + x + '"') }));
    }

    let shouldAddPassThru = false;
    // set to hold the output types
    const outputTypes = new Set<string>();
    for (const httpOperation of values(operation.callGraph)) {
      const pageableInfo = httpOperation.language.csharp?.pageable;
      const v = httpOperation.responses && httpOperation.responses.length > 0 && httpOperation.responses[0] instanceof SchemaResponse;
      // Add this for binary response in m4
      for (const binary of values(httpOperation.responses).selectNonNullable(each => (<BinaryResponse>each).binary)) {
        if (binary) {
          // if this is a stream, skip the output type.
          this.hasStreamOutput = true;
          shouldAddPassThru = true;
          outputTypes.add(`typeof(${dotnet.Bool})`);
        }
      }
      for (const schema of values(httpOperation.responses).selectNonNullable(each => (<SchemaResponse>each).schema)) {

        const props = NewGetAllProperties(schema);

        // does the target type just wrap a single output?
        const resultSchema = <NewSchema>schema;

        // make sure return type for boolean stays boolean!
        if (resultSchema.type === SchemaType.Boolean ||
          (resultSchema.type === SchemaType.Choice && (<any>resultSchema).choiceType.type === SchemaType.Boolean && (<ChoiceSchema>resultSchema).choices.length === 1) ||
          (resultSchema.type === SchemaType.SealedChoice && (<any>resultSchema).choiceType.type === SchemaType.Boolean && (<SealedChoiceSchema>resultSchema).choices.length === 1)) {
          outputTypes.add(`typeof(${dotnet.Bool})`);
        } else {
          const typeDeclaration = this.state.project.schemaDefinitionResolver.resolveTypeDeclaration(resultSchema, true, this.state, this.state.project.fixedArray);

          if (typeDeclaration.declaration === System.IO.Stream.declaration || typeDeclaration.declaration === dotnet.Binary.declaration) {
            // if this is a stream, skip the output type.
            this.hasStreamOutput = true;
            shouldAddPassThru = true;
            outputTypes.add(`typeof(${dotnet.Bool})`);
          } else {

            let type = '';
            if (typeDeclaration instanceof ArrayOf) {
              type = typeDeclaration.elementTypeDeclaration;
            } else if (pageableInfo && pageableInfo.responseType === 'pageable') {
              if (typeDeclaration === undefined || ((<ObjectSchema>typeDeclaration.schema).properties?.find(p => p.serializedName === pageableInfo.itemName) === undefined
                && (<ObjectSchema>typeDeclaration.schema).parents?.all.find(s => isObjectSchema(s) && s.properties?.find((p => p.serializedName === pageableInfo.itemName)) === undefined))) {
                //skip-for-time-being, since operationId does not support in m4 any more
                //throw new Error(`\n\nOn operation:\n  '${httpOperation.operationId}' at '${httpOperation.path}'\n  -- you have used 'x-ms-pageable' and there is no property name '${pageableInfo.itemName}' that is an array.\n\n`);
                throw new Error('An error needs to be more specific');
              }
              const nestedSchema = ((<ObjectSchema>typeDeclaration.schema).properties?.find(p => p.serializedName === pageableInfo.itemName)
                || (<ObjectSchema>(<ObjectSchema>typeDeclaration.schema).parents?.all.find(s => isObjectSchema(s) && s.properties?.find((p => p.serializedName === pageableInfo.itemName)))).properties?.find((p => p.serializedName === pageableInfo.itemName)))?.schema;
              const nestedTypeDeclaration = this.state.project.schemaDefinitionResolver.resolveTypeDeclaration(nestedSchema, true, this.state, this.state.project.fixedArray);
              type = (<ArrayOf>nestedTypeDeclaration).elementTypeDeclaration;
            } else {
              type = typeDeclaration.declaration;
            }
            // check if this is a stream output
            if (type) {
              outputTypes.add(`typeof(${type})`);
            }
          }
        }

      }
    }

    // if any response does not return,
    // the cmdlet should have a PassThru parameter
    shouldAddPassThru = shouldAddPassThru || values(operation.callGraph)
      .selectMany(httpOperation => values((httpOperation.responses || []).concat(httpOperation.exceptions || [])))
      //.selectMany(responsesItem => responsesItem.value)
      .any(value => (<SchemaResponse>value).schema === undefined);
    if (outputTypes.size === 0) {
      outputTypes.add(`typeof(${dotnet.Bool})`);
    }

    //add breaking change attributes for cmdlet, variant, output type
    if (operation.details.csharp.breakingChange) {
      const breakingChange = operation.details.csharp.breakingChange;
      if (breakingChange.cmdlet) {
        const parameters = [];
        if (!breakingChange.cmdlet.deprecateByVersion || !breakingChange.cmdlet.deprecateByAzVersion) {
          throw new Error('Cmdlet breaking change requires both \'deprecateByVersion\' and \'deprecateByAzVersion\', please refer to https://github.com/Azure/azure-powershell/blob/main/documentation/development-docs/breakingchange-for-autogen-module.md for more details.');
        }
        parameters.push(`"${breakingChange.cmdlet.deprecateByAzVersion}"`);
        parameters.push(`"${breakingChange.cmdlet.deprecateByVersion}"`);
        if (breakingChange.cmdlet.changeInEfectByDate) parameters.push(`"${breakingChange.cmdlet.changeInEfectByDate}"`);
        if (breakingChange.cmdlet.replacement) parameters.push(`ReplacementCmdletName = "${breakingChange.cmdlet.replacement}"`);
        if (breakingChange.cmdlet.changeDescription) parameters.push(`ChangeDescription = "${breakingChange.cmdlet.changeDescription}"`);

        this.add(new Attribute(ClientRuntime.CmdletBreakingChangeAttribute, { parameters: parameters }));
      }
      if (breakingChange.variant) {
        const parameters = [];
        parameters.push(`new string[] {"${breakingChange.variant.name}"}`);
        if (!breakingChange.variant.deprecateByVersion || !breakingChange.variant.deprecateByAzVersion) {
          throw new Error('Cmdlet breaking change requires both \'deprecateByVersion\' and \'deprecateByAzVersion\', please refer to https://github.com/Azure/azure-powershell/blob/main/documentation/development-docs/breakingchange-for-autogen-module.md for more details.');
        }
        parameters.push(`"${breakingChange.variant.deprecateByAzVersion}"`);
        parameters.push(`"${breakingChange.variant.deprecateByVersion}"`);
        if (breakingChange.variant.changeInEfectByDate) parameters.push(`"${breakingChange.variant.changeInEfectByDate}"`);
        if (breakingChange.variant.changeDescription) parameters.push(`ChangeDescription = "${breakingChange.variant.changeDescription}"`);

        this.add(new Attribute(ClientRuntime.ParameterSetBreakingChangeAttribute, { parameters: parameters }));
      }
      if (breakingChange.output) {
        const parameters = [];
        // if deprecated output types are set in directive, use it
        if (breakingChange.output.deprecatedCmdLetOutputType) {
          parameters.push(`"${breakingChange.output.deprecatedCmdLetOutputType}"`);
        } else {
          parameters.push(`"${outputTypes.values().next().value.replace(/typeof\((.*)\)/, '$1')}"`);
        }
        if (!breakingChange.output.deprecateByVersion || !breakingChange.output.deprecateByAzVersion) {
          throw new Error('Cmdlet breaking change requires both \'deprecateByVersion\' and \'deprecateByAzVersion\', please refer to https://github.com/Azure/azure-powershell/blob/main/documentation/development-docs/breakingchange-for-autogen-module.md for more details.');
        }
        parameters.push(`"${breakingChange.output.deprecateByAzVersion}"`);
        parameters.push(`"${breakingChange.output.deprecateByVersion}"`);
        if (breakingChange.output.changeInEfectByDate) parameters.push(`"${breakingChange.output.changeInEfectByDate}"`);
        if (breakingChange.output.replacement) parameters.push(`ReplacementCmdletOutputType = "${breakingChange.output.replacement}"`);
        if (breakingChange.output.deprecatedOutputProperties) {
          const properties: Array<string> = Object.assign([], breakingChange.output.deprecatedOutputProperties);
          properties.forEach((element, index) => properties[index] = '"' + element + '"');
          parameters.push(`DeprecatedOutputProperties = new string[] {${properties.join(',')}}`);
        }
        if (breakingChange.output.newOutputProperties) {
          const properties: Array<string> = Object.assign([], breakingChange.output.newOutputProperties);
          properties.forEach((element, index) => properties[index] = '"' + element + '"');
          parameters.push(`NewOutputProperties = new string[] {${properties.join(',')} } `);
        }
        if (breakingChange.output.changeDescription) parameters.push(`ChangeDescription = "${breakingChange.output.changeDescription}"`);

        this.add(new Attribute(ClientRuntime.OutputBreakingChangeAttribute, { parameters: parameters }));
      }
    }

    //add preview message attribute for cmdlet
    if (operation.details.csharp.previewAnnouncement) {
      const parameters = [];
      parameters.push(`"${operation.details.csharp.previewAnnouncement.previewMessage}"`);
      if (operation.details.csharp.previewAnnouncement.estimatedGaDate) parameters.push(`"${operation.details.csharp.previewAnnouncement.estimatedGaDate}"`);
      this.add(new Attribute(ClientRuntime.PreviewMessageAttribute, { parameters: parameters }));
    }

    this.add(new Attribute(OutputTypeAttribute, { parameters: [...outputTypes] }));
    if (shouldAddPassThru) {
      const passThru = this.add(new Property('PassThru', SwitchParameter, { description: 'When specified, forces the cmdlet return a \'bool\' given that there isn\'t a return type by default.' }));
      passThru.add(new Attribute(ParameterAttribute, { parameters: ['Mandatory = false', 'HelpMessage = "Returns true when the command succeeds"'] }));
      passThru.add(new Attribute(CategoryAttribute, { parameters: [`${ParameterCategory}.Runtime`] }));
    }

    this.add(new Attribute(DescriptionAttribute, { parameters: [new StringExpression(this.description)] }));

    // If defines externalDocs for operation
    if (operation.details.default.externalDocs) {
      this.add(new Attribute(ExternalDocsAttribute, {
        parameters: [`${new StringExpression(this.operation.details.default.externalDocs?.url ?? '')}`,
          `${new StringExpression(this.operation.details.default.externalDocs?.description ?? '')}`]
      }));
    }

    this.add(new Attribute(GeneratedAttribute));
    if (operation.extensions && operation.extensions['x-ms-metadata'] && operation.extensions['x-ms-metadata'].profiles) {
      const profileNames = Object.keys(operation.extensions && operation.extensions['x-ms-metadata'].profiles);
      // wrap profile names
      profileNames.forEach((element, index) => {
        profileNames[index] = `"${element}"`;
      });

      this.add(new Attribute(ProfileAttribute, { parameters: [...profileNames] }));
    }
    if (this.operation.callGraph.length === 1) {
      this.add(new Attribute(HttpPathAttribute, { parameters: [`Path = "${this.apiCall.requests?.[0].protocol?.http?.path}"`, `ApiVersion = "${this.apiCall.apiVersions?.[0].version}"`] }));
    }
    if (variantName.includes('ViaJsonString') || variantName.includes('ViaJsonFilePath')) {
      this.add(new Attribute(NotSuggestDefaultParameterSetAttribute));
    }
  }