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