powershell/llcsharp/model/model-class.ts (443 lines of code) (raw):
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { HeaderProperty, HeaderPropertyType, KnownMediaType, VirtualProperty, getAllVirtualProperties } from '@azure-tools/codemodel-v3';
import { getPascalIdentifier, camelCase, deconstruct, DeepPartial } from '@azure-tools/codegen';
import { items, values } from '@azure-tools/linq';
import { Access, Class, Constructor, Expression, ExpressionOrLiteral, Field, If, Method, Modifier, Namespace, OneOrMoreStatements, Parameter, Statements, System, TypeDeclaration, valueOf, Variable, BackedProperty, Property, Virtual, toExpression, StringExpression, LiteralExpression, Attribute } from '@azure-tools/codegen-csharp';
import { ClientRuntime } from '../clientruntime';
import { State } from '../generator';
import { EnhancedTypeDeclaration } from '../schema/extended-type-declaration';
import { ObjectImplementation } from '../schema/object';
import { ModelInterface } from './interface';
import { JsonSerializableClass } from './model-class-json';
import { ModelProperty } from './property';
import { PropertyOriginAttribute, DoNotFormatAttribute, FormatTableAttribute, ConstantAttribute } from '../csharp-declarations';
import { Schema } from '../code-model';
import { DictionaryImplementation } from './model-class-dictionary';
import { Languages, Language, Schema as NewSchema, SchemaType, ObjectSchema, DictionarySchema } from '@autorest/codemodel';
import { VirtualProperty as NewVirtualProperty, getAllVirtualProperties as newGetAllVirtualProperties } from '../../utils/schema';
export function getVirtualPropertyName(vp?: NewVirtualProperty): string {
if (vp && vp.accessViaMember && vp.accessViaProperty?.accessViaMember) {
return getVirtualPropertyName(vp.accessViaMember);
}
return vp ? vp.name : '';
}
export interface BackingField {
field: Field;
typeDeclaration: TypeDeclaration;
className: string;
}
export class ModelClass extends Class implements EnhancedTypeDeclaration {
deserializeFromContainerMember(mediaType: KnownMediaType, container: ExpressionOrLiteral, serializedName: string, defaultValue: Expression): Expression {
return this.featureImplementation.deserializeFromContainerMember(mediaType, container, serializedName, defaultValue);
}
deserializeFromNode(mediaType: KnownMediaType, node: ExpressionOrLiteral, defaultValue: Expression): Expression {
return this.featureImplementation.deserializeFromNode(mediaType, node, defaultValue);
}
serializeToNode(mediaType: KnownMediaType, value: ExpressionOrLiteral, serializedName: string, mode: Expression): Expression {
return this.featureImplementation.serializeToNode(mediaType, value, serializedName, mode);
}
get defaultOfType() {
return toExpression('null /* model class */');
}
get convertObjectMethod() {
return this.featureImplementation.convertObjectMethod;
}
/** emits an expression serialize this to a HttpContent */
serializeToContent(mediaType: KnownMediaType, value: ExpressionOrLiteral, mode: Expression): Expression {
return this.featureImplementation.serializeToContent(mediaType, value, mode);
}
/** emits an expression to deserialize content from a string */
deserializeFromString(mediaType: KnownMediaType, content: ExpressionOrLiteral, defaultValue: Expression): Expression | undefined {
return this.featureImplementation.deserializeFromString(mediaType, content, defaultValue);
}
/** emits an expression to deserialize content from a content/response */
deserializeFromResponse(mediaType: KnownMediaType, content: ExpressionOrLiteral, defaultValue: Expression): Expression | undefined {
return this.featureImplementation.deserializeFromResponse(mediaType, content, defaultValue);
}
serializeToContainerMember(mediaType: KnownMediaType, value: ExpressionOrLiteral, container: Variable, serializedName: string, mode: Expression): OneOrMoreStatements {
return this.featureImplementation.serializeToContainerMember(mediaType, value, container, serializedName, mode);
}
get isXmlAttribute(): boolean {
return this.featureImplementation.isXmlAttribute;
}
public isNullable = true;
get isRequired(): boolean {
return this.featureImplementation.isRequired;
}
public isPolymorphic = false;
public get schema() { return this.featureImplementation.schema; }
/* @internal */ validateMethod?: Method;
/* @internal */ discriminators: Map<string, ModelClass> = new Map<string, ModelClass>();
/* @internal */ parentModelClasses: Array<ModelClass> = new Array<ModelClass>();
/* @internal */ get modelInterface(): ModelInterface { return <ModelInterface>this.schema.language.csharp?.interfaceImplementation; }
/* @internal */ get internalModelInterface(): ModelInterface { return <ModelInterface>this.schema.language.csharp?.internalInterfaceImplementation; }
/* @internal */ state: State;
/* @internal */ backingFields = new Array<BackingField>();
/* @internal */ featureImplementation: ObjectImplementation;
/* @internal */ validationEventListener: Parameter = new Parameter('eventListener', ClientRuntime.IEventListener, { description: `an <see cref="${ClientRuntime.IEventListener}" /> instance that will receive validation events.` });
/* @internal */ jsonSerializer?: JsonSerializableClass;
// /* @internal */ xmlSerializer?: XmlSerializableClass;
/* @internal */ dictionaryImpl?: DictionaryImplementation;
/* @internal */ constructorMethod?: Method;
private readonly validationStatements = new Statements();
public ownedProperties = new Array<ModelProperty>();
private pMap = new Map<NewVirtualProperty, ModelProperty>();
// public hasHeaderProperties: boolean;
constructor(namespace: Namespace, schemaWithFeatures: ObjectImplementation, state: State, objectInitializer?: DeepPartial<ModelClass>) {
super(namespace, schemaWithFeatures.schema.language.csharp?.name || '');
this.featureImplementation = schemaWithFeatures;
this.schema.language.csharp = this.schema.language.csharp || new Language();
this.schema.language.csharp.classImplementation = this; // mark the code-model with the class we're creating.
this.state = state;
this.apply(objectInitializer);
if (this.schema.language.csharp.suppressFormat) {
this.add(new Attribute(DoNotFormatAttribute));
}
// must be a partial class
this.partial = true;
this.handleDiscriminator();
// create an interface for this model class
if (!this.schema.language.csharp.interfaceImplementation) {
(this.schema.language.csharp.interfaceImplementation = new ModelInterface(this.namespace, this.schema.language.csharp.interfaceName || `I${this.schema.language.csharp.name}`, this, this.state));
}
this.interfaces.push(this.modelInterface);
if (!this.schema.language.csharp.internalInterfaceImplementation) {
(this.schema.language.csharp.internalInterfaceImplementation = new ModelInterface(this.namespace, this.schema.language.csharp.internalInterfaceName || `I${this.schema.language.csharp.name}Internal`, this, this.state, { accessModifier: Access.Internal }));
}
this.interfaces.push(this.internalModelInterface);
this.schema.language.csharp.internalInterfaceImplementation.init();
this.schema.language.csharp.interfaceImplementation.init();
// add default constructor
this.constructorMethod = this.addMethod(new Constructor(this, { description: `Creates an new <see cref="${this.name}" /> instance.` })); // default constructor for fits and giggles.
// handle parent interface implementation
if (!this.handleAllOf()) {
// handle the AdditionalProperties if used
const dictSchema = (<NewSchema>this.schema).type === SchemaType.Dictionary ? this.schema :
this.schema.parents?.immediate?.find((schema) => schema.type === SchemaType.Dictionary);
if (dictSchema) {
this.dictionaryImpl = new DictionaryImplementation(this).init();
}
}
// create the properties for this schema
this.createProperties();
// add validation implementation
this.addValidation();
// add header properties for this model.
// DISABLED.
this.addHeaderDeserializer();
if (this.state.project.jsonSerialization) {
this.jsonSerializer = new JsonSerializableClass(this);
}
}
private nested(virtualProperty: NewVirtualProperty, internal: boolean): string {
if (virtualProperty.accessViaProperty) {
if (virtualProperty.accessViaProperty.accessViaProperty) {
// return `/*1*/${getVirtualPropertyName(virtualProperty.accessViaMember)}.${this.nested(virtualProperty.accessViaProperty.accessViaProperty, internal)}`;
return `${getVirtualPropertyName(virtualProperty.accessViaMember)}.${this.nested(virtualProperty.accessViaProperty.accessViaProperty, internal)}`;
}
}
//return `/*2*/${getVirtualPropertyName(virtualProperty.accessViaMember)}`;
return `${getVirtualPropertyName(virtualProperty.accessViaMember)}`;
}
private accessor(virtualProperty: NewVirtualProperty, internal = false): string {
if (virtualProperty.accessViaProperty) {
const prefix = virtualProperty.accessViaProperty.accessViaProperty ? this.nested(virtualProperty.accessViaProperty.accessViaProperty, internal) : '';
const containingProperty = this.pMap.get(virtualProperty.accessViaProperty);
if (containingProperty && virtualProperty.accessViaMember) {
//return `/*3*/((${virtualProperty.accessViaMember.originalContainingSchema.details.csharp.fullInternalInterfaceName})${containingProperty.name}${prefix}).${getVirtualPropertyName(virtualProperty.accessViaMember)}`;
return `((${virtualProperty.accessViaMember.originalContainingSchema.language.csharp?.fullInternalInterfaceName})${containingProperty.name}${prefix}).${getVirtualPropertyName(virtualProperty.accessViaMember)}`;
}
}
// return `/*4* ${virtualProperty.name}/${virtualProperty.accessViaMember?.name}/${virtualProperty.accessViaProperty?.name} */${getVirtualPropertyName(virtualProperty.accessViaMember) || '/*!!*/' + virtualProperty.name}`;
return `${getVirtualPropertyName(virtualProperty.accessViaMember) || virtualProperty.name}`;
}
private createProperties() {
// generate a protected backing field for each
// and then expand the nested properties into this class forwarding to the member.
// add properties
if (this.schema.language.csharp?.virtualProperties) {
/* Owned Properties */
for (const virtualProperty of values(<Array<NewVirtualProperty>>(this.schema.language.csharp.virtualProperties.owned))) {
let isPolymorphic = false;
if (virtualProperty.private && virtualProperty.property.schema.type === SchemaType.Object && (<ObjectSchema>virtualProperty.property.schema).discriminator) {
isPolymorphic = true;
}
const actualProperty = virtualProperty.property;
let n = 0;
const isRequired = !!(virtualProperty.required && virtualProperty.read && virtualProperty.create && virtualProperty.update);
const decl = this.state.project.modelsNamespace.NewResolveTypeDeclaration(<NewSchema>actualProperty.schema, isRequired, this.state.path('schema'));
/* public property */
const myProperty = new ModelProperty(virtualProperty.name, <NewSchema>actualProperty.schema, isRequired, actualProperty.serializedName, actualProperty.language.csharp?.description || '', this.state.path('properties', n++), {
initializer: actualProperty.language.csharp?.constantValue ? typeof actualProperty.language.csharp.constantValue === 'string' ? new StringExpression(actualProperty.language.csharp.constantValue) : new LiteralExpression(actualProperty.language.csharp.constantValue) : undefined
});
if (virtualProperty.readOnly || actualProperty.language.csharp?.readOnly || actualProperty.readOnly) {
myProperty.set = undefined;
}
myProperty.language = virtualProperty.property.language;
if (actualProperty.language.csharp?.constantValue !== undefined) {
myProperty.setAccess = Access.Internal;
myProperty.set = undefined;
}
if (virtualProperty.private && !isPolymorphic) {
// when properties are inlined, the container accessor can be internalized. I think.
myProperty.setAccess = Access.Internal;
myProperty.getAccess = Access.Internal;
}
if (virtualProperty.private) {
this.pMap.set(virtualProperty, myProperty);
}
this.ownedProperties.push(this.add(myProperty));
if (myProperty.getAccess !== Access.Public || myProperty.setAccess !== Access.Public || myProperty.set === undefined || isPolymorphic) {
/* internal interface property */
this.add(new Property(`${virtualProperty.originalContainingSchema.language.csharp?.internalInterfaceImplementation.fullName}.${virtualProperty.name}`, decl, {
description: `Internal Acessors for ${virtualProperty.name}`,
getAccess: Access.Explicit,
setAccess: Access.Explicit,
get: myProperty.get,
set: myProperty.assignPrivate('value')
}));
}
myProperty.add(new Attribute(PropertyOriginAttribute, { parameters: [`${this.state.project.serviceNamespace}.PropertyOrigin.Owned`] }));
this.addFormatAttributesToProperty(myProperty, virtualProperty);
}
/* Inherited properties. */
for (const virtualProperty of values(<Array<NewVirtualProperty>>(this.schema.language.csharp.virtualProperties.inherited))) {
let isPolymorphic = false;
if (virtualProperty.private && virtualProperty.property.schema.type === SchemaType.Object && (<ObjectSchema>virtualProperty.property.schema).discriminator) {
isPolymorphic = true;
}
// so each parent property that is getting exposed
// has to be accessed via the field in this.backingFields
const parentField = <BackingField>this.backingFields.find(each => virtualProperty.accessViaSchema ? virtualProperty.accessViaSchema.language.csharp?.interfaceImplementation.fullName === each.typeDeclaration.declaration : false);
const isRequired = !!(virtualProperty.required && virtualProperty.read && virtualProperty.create && virtualProperty.update);
const propertyType = this.state.project.modelsNamespace.NewResolveTypeDeclaration(<NewSchema>virtualProperty.property.schema, isRequired, this.state);
const requiredPropertyType = this.state.project.modelsNamespace.NewResolveTypeDeclaration(<NewSchema>virtualProperty.property.schema, true, this.state);
const opsType = this.state.project.modelsNamespace.NewResolveTypeDeclaration(<NewSchema>virtualProperty.originalContainingSchema, false, this.state);
const via = <NewVirtualProperty>virtualProperty.accessViaProperty;
const parentCast = `(${virtualProperty.originalContainingSchema.language.csharp?.internalInterfaceImplementation.fullName})`;
let getFunc = toExpression(`(${parentCast}${parentField.field.name}).${this.accessor(virtualProperty)}`);
let setFunc = (virtualProperty.readOnly || virtualProperty.property.language.csharp?.constantValue) ? undefined : toExpression(`(${parentCast}${parentField.field.name}).${this.accessor(virtualProperty)} = value ${isRequired ? '' : ` ?? ${requiredPropertyType.defaultOfType}`}`);
let isConstant = false;
if (virtualProperty.property.isDiscriminator && this.schema.discriminatorValue) {
for (const parent of values(this.schema.parents?.all)) {
if ((<ObjectSchema>parent).discriminator?.property === virtualProperty.property) {
getFunc = toExpression(`"${this.schema.discriminatorValue}"`);
setFunc = toExpression(`(${parentCast}${parentField.field.name}).${this.accessor(virtualProperty)} = "${this.schema.discriminatorValue}"`);
isConstant = true;
if (virtualProperty.property.language.csharp?.constantValue === undefined && !virtualProperty.readOnly) {
this.constructorMethod?.add(`this.${parentField.field.name}.${this.accessor(virtualProperty)} = "${this.schema.discriminatorValue}";`);
}
break;
}
}
}
const vp = this.add(new Property(virtualProperty.name, propertyType, {
description: virtualProperty.property.language.csharp?.description,
get: getFunc,
set: setFunc
}));
if (virtualProperty.property.language.csharp?.constantValue !== undefined) {
vp.setAccess = Access.Internal;
vp.set = undefined;
}
if (virtualProperty.private && !isPolymorphic) {
vp.setAccess = Access.Internal;
vp.getAccess = Access.Internal;
}
if (vp.getAccess !== Access.Public || vp.setAccess !== Access.Public || vp.set === undefined || isPolymorphic) {
this.add(new Property(`${virtualProperty.originalContainingSchema.language.csharp?.internalInterfaceImplementation.fullName}.${virtualProperty.name}`, propertyType, {
description: `Internal Acessors for ${virtualProperty.name}`,
getAccess: Access.Explicit,
setAccess: Access.Explicit,
get: toExpression(`(${parentCast}${parentField.field.name}).${via.name}`),
set: toExpression(`(${parentCast}${parentField.field.name}).${via.name} = value`)
}));
}
if (isConstant) {
vp.add(new Attribute(ConstantAttribute));
}
vp.add(new Attribute(PropertyOriginAttribute, { parameters: [`${this.state.project.serviceNamespace}.PropertyOrigin.Inherited`] }));
this.addFormatAttributesToProperty(vp, virtualProperty);
}
/* Inlined properties. */
for (const virtualProperty of values(<Array<NewVirtualProperty>>this.schema.language.csharp.virtualProperties.inlined)) {
let isPolymorphic = false;
if (virtualProperty.private && virtualProperty.property.schema.type === SchemaType.Object && (<ObjectSchema>virtualProperty.property.schema).discriminator) {
// continue;
// can't remove it, it has to be either public or internally implemented.
isPolymorphic = true;
}
const isRequired = !!(virtualProperty.required && virtualProperty.read && virtualProperty.create && virtualProperty.update);
if (virtualProperty.accessViaProperty) {
const containingProperty = this.pMap.get(virtualProperty.accessViaProperty);
if (containingProperty) {
const propertyType = this.state.project.modelsNamespace.NewResolveTypeDeclaration(<NewSchema>virtualProperty.property.schema, isRequired, this.state);
const requiredPropertyType = this.state.project.modelsNamespace.NewResolveTypeDeclaration(<NewSchema>virtualProperty.property.schema, true, this.state);
// regular inlined property
const vp = new Property(virtualProperty.name, propertyType, {
description: virtualProperty.property.language.csharp?.description,
get: toExpression(`${this.accessor(virtualProperty)}`),
set: (virtualProperty.readOnly || virtualProperty.property.language.csharp?.constantValue) ? undefined : toExpression(`${this.accessor(virtualProperty)} = value ${isRequired ? '' : ` ?? ${requiredPropertyType.defaultOfType}`}`)
});
if (!virtualProperty.private || isPolymorphic) {
this.add(vp);
}
if (virtualProperty.private || vp.getAccess !== Access.Public || vp.setAccess !== Access.Public || vp.set === undefined || isPolymorphic) {
this.add(new Property(`${virtualProperty.originalContainingSchema.language.csharp?.internalInterfaceImplementation.fullName}.${virtualProperty.name}`, propertyType, {
description: `Internal Acessors for ${virtualProperty.name}`,
getAccess: Access.Explicit,
setAccess: Access.Explicit,
get: vp.get,
set: toExpression(`${this.accessor(virtualProperty)} = value`)
}));
}
if (virtualProperty.property.language.csharp?.constantValue !== undefined) {
vp.setAccess = Access.Internal;
vp.set = undefined;
}
vp.add(new Attribute(PropertyOriginAttribute, { parameters: [`${this.state.project.serviceNamespace}.PropertyOrigin.Inlined`] }));
this.addFormatAttributesToProperty(vp, virtualProperty);
}
}
}
/* Appended properties. */
if (this.state.project.resourceGroupAppend && this.state.project.azure && this.schema.extensions && this.schema.extensions['is-return-object']) {
this.appendResourceGroupName();
}
}
}
private addFormatAttributesToProperty(property: Property, virtualProperty: NewVirtualProperty) {
if (virtualProperty.format) {
if (virtualProperty.format.suppressFormat) {
property.add(new Attribute(DoNotFormatAttribute));
} else {
const parameters = [];
if (virtualProperty.format.index !== undefined) {
parameters.push(`Index = ${virtualProperty.format.index}`);
}
if (virtualProperty.format.label !== undefined) {
parameters.push(`Label = ${new StringExpression(virtualProperty.format.label)}`);
}
if (virtualProperty.format.width !== undefined) {
parameters.push(`Width = ${virtualProperty.format.width}`);
}
property.add(new Attribute(FormatTableAttribute, { parameters }));
}
}
}
private addValidation() {
if (this.validationStatements.implementation.trim()) {
// we do have something to valdiate!
// add the IValidates implementation to this object.
this.interfaces.push(ClientRuntime.IValidates);
this.validateMethod = this.addMethod(new Method('Validate', System.Threading.Tasks.Task(), {
async: Modifier.Async,
parameters: [this.validationEventListener],
description: 'Validates that this object meets the validation criteria.',
returnsDescription: `A <see cref = "${System.Threading.Tasks.Task()}" /> that will be complete when validation is completed.`
}));
this.validateMethod.add(this.validationStatements);
}
}
private additionalPropertiesType(aSchema: NewSchema): TypeDeclaration | undefined {
const schema = aSchema.type === SchemaType.Dictionary ? aSchema :
aSchema.type === SchemaType.Object ? (<ObjectSchema>aSchema).parents?.immediate?.find((s) => s.type === SchemaType.Dictionary) :
undefined;
if (schema) {
const dictSchema = <DictionarySchema>schema;
if (dictSchema.elementType.type === SchemaType.Any) {
return System.Object;
} else {
// we're going to implement IDictionary<string, schema.additionalProperties>
return this.state.project.modelsNamespace.NewResolveTypeDeclaration(dictSchema.elementType, true, this.state);
}
} else
for (const each of values((<ObjectSchema>aSchema).parents?.immediate)) {
const r = this.additionalPropertiesType(each);
if (r) {
return r;
}
}
return undefined;
}
private handleAllOf() {
let hasAdditionalPropertiesInParent = false;
// handle <allOf>s
// add an 'implements' for the interface for the allOf.
for (const { key: eachSchemaIndex, value: eachSchemaValue } of items(this.schema.parents?.immediate)) {
if (eachSchemaValue.type === SchemaType.Dictionary) {
continue;
}
const aSchema = eachSchemaValue;
const aState = this.state.path('allOf', eachSchemaIndex);
const td = this.state.project.modelsNamespace.NewResolveTypeDeclaration(aSchema, true, aState);
const parentClass = (<ModelClass>aSchema.language.csharp?.classImplementation);
const className = parentClass.fullName;
const fieldName = camelCase(deconstruct(className.replace(/^.*\./, '')));
// add the interface as a parent to our interface.
const iface = <ModelInterface>aSchema.language.csharp?.interfaceImplementation;
// add a field for the inherited values
const backingField = this.addField(new Field(`__${fieldName}`, td, { initialValue: `new ${className}()`, access: Access.Private, description: `Backing field for Inherited model <see cref= "${td.declaration}" /> ` }));
this.backingFields.push({
className,
typeDeclaration: td,
field: backingField
});
this.validationStatements.add(td.validatePresence(this.validationEventListener, backingField));
this.validationStatements.add(td.validateValue(this.validationEventListener, backingField));
this.internalModelInterface.interfaces.push(<ModelInterface>aSchema.language.csharp?.internalInterfaceImplementation);
this.modelInterface.interfaces.push(iface);
//
const addlPropType = this.additionalPropertiesType(aSchema);
if (addlPropType) {
this.dictionaryImpl = new DictionaryImplementation(this).init(addlPropType, backingField);
hasAdditionalPropertiesInParent = true;
}
}
return hasAdditionalPropertiesInParent;
}
private handleDiscriminator() {
if (this.schema.discriminator) {
// this has a discriminator property.
// our children are expected to tell us who they are
this.isPolymorphic = true;
// we'll add a deserializer factory method a bit later..
}
if (this.schema.discriminatorValue) {
// we have a discriminator value, and we should tell our parent who we are so that they can build a proper deserializer method.
// um. just how do we *really* know which allOf is polymorphic?
// that's really sad.
for (const { key: eachAllOfIndex, value: eachAllOfValue } of items(this.schema.parents?.all)) {
const parentSchema = eachAllOfValue;
const aState = this.state.path('allOf', eachAllOfIndex);
// ensure the parent schema has it's class created first.
this.state.project.modelsNamespace.NewResolveTypeDeclaration(parentSchema, true, aState);
const parentClass = <ModelClass>parentSchema.language.csharp?.classImplementation;
if (!!parentClass && parentClass.isPolymorphic) {
// remember this class for later.
this.parentModelClasses.push(parentClass);
// tell that parent who we are.
parentClass.addDiscriminator(this.schema.discriminatorValue, this);
}
}
}
}
private addHeaderDeserializer() {
const avp = newGetAllVirtualProperties(this.schema.language.csharp?.virtualProperties);
const headers = new Parameter('headers', System.Net.Http.Headers.HttpResponseHeaders);
const readHeaders = new Method(`${ClientRuntime.IHeaderSerializable}.ReadHeaders`, undefined, {
access: Access.Explicit,
parameters: [headers],
});
let used = false;
let i = 0;
for (const headerProperty of values(avp).where(each => each.property.language.csharp?.[HeaderProperty] === HeaderPropertyType.HeaderAndBody || each.property.language.csharp?.[HeaderProperty] === HeaderPropertyType.Header)) {
used = true;
const t = `((${headerProperty.originalContainingSchema.language.csharp?.fullInternalInterfaceName})this)`;
const values = `__${camelCase([...deconstruct(headerProperty.property.serializedName), 'Header'])}`;
const td = this.state.project.modelsNamespace.NewResolveTypeDeclaration(headerProperty.property.schema, false, this.state);
readHeaders.add(If(`${valueOf(headers)}.TryGetValues("${headerProperty.property.serializedName}", out var ${values}${i})`, `${t}.${headerProperty.name} = ${td.deserializeFromContainerMember(KnownMediaType.Header, headers, values + i, td.defaultOfType)};`));
i++;
}
if (used) {
this.interfaces.push(ClientRuntime.IHeaderSerializable);
this.add(readHeaders);
}
}
private appendResourceGroupName() {
const virtualProperties = newGetAllVirtualProperties(this.schema.language.csharp?.virtualProperties);
const idProperties = values(virtualProperties).where(each => each.name === 'Id').toArray();
const resourceGroupNameProperties = values(virtualProperties).where(each => each.name === 'ResourceGroupName').toArray();
if (idProperties.length == 1 && resourceGroupNameProperties.length === 0) {
const idProperty = idProperties[0];
const resourceGroupNamePropertyName = getPascalIdentifier('ResourceGroupName');
const resourceGroupNameDescription = 'Gets the resource group name';
const actualResourceGroupProperty = idProperty.property;
actualResourceGroupProperty.serializedName = resourceGroupNamePropertyName;
const decl = this.state.project.modelsNamespace.NewResolveTypeDeclaration(<NewSchema>actualResourceGroupProperty.schema, false, this.state.path('schema'));
const resourceGroupNameProperty = new Property(`${resourceGroupNamePropertyName}`, decl, {
description: resourceGroupNameDescription,
getAccess: Access.Public,
setAccess: Access.Public,
get: toExpression('(new global::System.Text.RegularExpressions.Regex("^/subscriptions/(?<subscriptionId>[^/]+)/resourceGroups/(?<resourceGroupName>[^/]+)/providers/", global::System.Text.RegularExpressions.RegexOptions.IgnoreCase).Match(this.Id).Success ? new global::System.Text.RegularExpressions.Regex("^/subscriptions/(?<subscriptionId>[^/]+)/resourceGroups/(?<resourceGroupName>[^/]+)/providers/", global::System.Text.RegularExpressions.RegexOptions.IgnoreCase).Match(this.Id).Groups["resourceGroupName"].Value : null)')
});
const format = this.state.project.formats[`${this.schema.language.csharp?.name}`];
const virtualResourceGroupNameProperty = {
name: resourceGroupNamePropertyName,
property: actualResourceGroupProperty,
private: false,
nameComponents: [resourceGroupNamePropertyName],
nameOptions: [resourceGroupNamePropertyName],
description: resourceGroupNameDescription,
originalContainingSchema: actualResourceGroupProperty.schema,
alias: [],
required: false,
format: format
};
resourceGroupNameProperty.add(new Attribute(PropertyOriginAttribute, { parameters: [`${this.state.project.serviceNamespace}.PropertyOrigin.Owned`] }));
this.addFormatAttributesToProperty(resourceGroupNameProperty, virtualResourceGroupNameProperty);
this.add(resourceGroupNameProperty);
}
}
public validateValue(eventListener: Variable, property: Variable): OneOrMoreStatements {
return this.featureImplementation.validateValue(eventListener, property);
}
public validatePresence(eventListener: Variable, property: Variable): OneOrMoreStatements {
return this.featureImplementation.validatePresence(eventListener, property);
}
public addDiscriminator(discriminatorValue: string, modelClass: ModelClass) {
this.discriminators.set(discriminatorValue, modelClass);
// tell any polymorphic parents incase we're doing subclass of a subclass.
for (const each of this.parentModelClasses) {
each.addDiscriminator(discriminatorValue, modelClass);
}
}
}