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));
}
}