@microsoft.azure/autorest.incubator
Version:
AutoRest incubator project
205 lines • 12.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const dictionary_1 = require("../../../common/dictionary");
const text_manipulation_1 = require("../../../common/text-manipulation");
const access_modifier_1 = require("../../../csharp/code-dom/access-modifier");
const class_1 = require("../../../csharp/code-dom/class");
const constructor_1 = require("../../../csharp/code-dom/constructor");
const expression_1 = require("../../../csharp/code-dom/expression");
const field_1 = require("../../../csharp/code-dom/field");
const method_1 = require("../../../csharp/code-dom/method");
const dotnet = require("../../../csharp/code-dom/mscorlib");
const parameter_1 = require("../../../csharp/code-dom/parameter");
const if_1 = require("../../../csharp/code-dom/statements/if");
const statement_1 = require("../../../csharp/code-dom/statements/statement");
const clientruntime_1 = require("../../../csharp/lowlevel-generator/clientruntime");
const tweak_model_1 = require("../../../remodeler/tweak-model");
const interface_1 = require("./interface");
const property_1 = require("./property");
const proxy_property_1 = require("./proxy-property");
const model_class_json_1 = require("../../../csharp/lowlevel-generator/model/model-class-json");
const media_types_1 = require("../../../common/media-types");
const model_class_xml_1 = require("../../../csharp/lowlevel-generator/model/model-class-xml");
class ModelClass extends class_1.Class {
constructor(namespace, schemaWithFeatures, state, objectInitializer) {
super(namespace, schemaWithFeatures.schema.details.csharp.name);
/* @internal */ this.backingFields = new Array();
this.implementation = schemaWithFeatures;
this.isPolymorphic = false;
this.discriminators = new Map();
this.parentModelClasses = new Array();
this.state = state;
this.addGeneratedCodeAttribute = true;
this.apply(objectInitializer);
this.partial = true;
// create an interface for this model class
// mark the code-model with the class we're creating.
this.schema.details.csharp.classImplementation = this;
// get all the header properties for this model
this.hasHeaderProperties = dictionary_1.values(this.schema.properties).linq.any(property => property.details.csharp[tweak_model_1.HeaderProperty] === tweak_model_1.HeaderPropertyType.Header || property.details.csharp[tweak_model_1.HeaderProperty] === tweak_model_1.HeaderPropertyType.Header);
const modelInterface = this.schema.details.csharp.interfaceImplementation || new interface_1.ModelInterface(this.namespace, this.schema, this, this.state);
this.modelInterface = modelInterface;
this.interfaces.push(modelInterface);
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.extensions['x-ms-discriminator-value']) {
// 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 eachAllOf of dictionary_1.items(this.schema.allOf)) {
const parentSchema = eachAllOf.value;
const aState = this.state.path('allOf', eachAllOf.key);
const parentDecl = this.state.project.modelsNamespace.resolveTypeDeclaration(parentSchema, true, aState);
const parentClass = parentSchema.details.csharp.classImplementation;
if (parentClass.isPolymorphic) {
// remember this class for later.
this.parentModelClasses.push(parentClass);
// tell that parent who we are.
parentClass.addDiscriminator(this.schema.extensions['x-ms-discriminator-value'], this);
}
}
}
const defaultConstructor = this.addMethod(new constructor_1.Constructor(this)); // default constructor for fits and giggles.
const validationStatements = new statement_1.Statements();
// handle <allOf>s
// add an 'implements' for the interface for the allOf.
for (const eachSchema of dictionary_1.items(this.schema.allOf)) {
// gs01: Critical -- pull thru parent allOf's!
const aSchema = eachSchema.value;
const aState = this.state.path('allOf', eachSchema.key);
const td = this.state.project.modelsNamespace.resolveTypeDeclaration(aSchema, true, aState);
const className = aSchema.details.csharp.classImplementation.fullName;
const fieldName = text_manipulation_1.camelCase(text_manipulation_1.deconstruct(className.replace(/^.*\./, '')));
// add the interface as a parent to our interface.
const iface = aSchema.details.csharp.interfaceImplementation;
this.modelInterface.interfaces.push(iface);
// add a field for the inherited values
const backingField = this.addField(new field_1.InitializedField(`_${fieldName}`, td, { value: `new ${className}()` }, { access: access_modifier_1.Access.Private }));
this.backingFields.push({
className,
typeDeclaration: td,
field: backingField
});
// now, create proxy properties for the members
iface.allProperties.map((each) => {
// make sure we don't over expose read-only properties.
const p = this.add(new proxy_property_1.ProxyProperty(backingField, each, this.state));
if (each.setAccess === access_modifier_1.Access.Internal) {
p.setterStatements = undefined;
}
return p;
});
validationStatements.add(td.validatePresence(backingField));
validationStatements.add(td.validateValue(backingField));
}
// generate a protected backing field for each
// and then expand the nested properties into this class forwarding to the member.
// add properties
for (const { key: propertyName, value: property } of dictionary_1.items(this.schema.properties)) {
const prop = new property_1.ModelProperty(this, property, property.serializedName || propertyName, this.state.path('properties', propertyName));
this.add(prop);
validationStatements.add(prop.validatePresenceStatement);
validationStatements.add(prop.validationStatement);
}
if (this.schema.additionalProperties) {
if (this.schema.additionalProperties === true) {
// we should generate an additionalProperties property that catches all extra properties as object
const valueSchema = {};
}
else {
// we should generate an additionalProperties property that catches all extra properties as the type specified by
const valueSchema = this.schema.additionalProperties;
}
}
if (!this.state.project.storagePipeline) {
if (validationStatements.implementation.trim()) {
// we do have something to valdiate!
// add the IValidates implementation to this object.
this.interfaces.push(clientruntime_1.ClientRuntime.IValidates);
this.validateMethod = this.addMethod(new method_1.Method('Validate', dotnet.System.Threading.Tasks.Task(), {
async: access_modifier_1.Modifier.Async,
parameters: [new parameter_1.Parameter('listener', clientruntime_1.ClientRuntime.IEventListener)],
}));
this.validateMethod.add(validationStatements);
}
}
// add from headers method if class or any of the parents pulls in header values.
// FromHeaders( headers IEnumerable<KeyValuePair<string, IEnumerable<string>>> ) { ... }
const headerProperties = dictionary_1.values(this.properties).linq.where(p => p.IsHeaderProperty);
if (this.hasHeaderProperties) {
// add header deserializer method
const httpResponse = new parameter_1.Parameter('response', dotnet.System.Net.Http.HttpResponseMessage);
const readHeaders = new method_1.Method('ReadHeaders', this, {
access: access_modifier_1.Access.Internal,
parameters: [httpResponse],
*body() {
for (const hp of headerProperties) {
const hparam = hp;
const prefix = hparam.schema.extensions['x-ms-header-collection-prefix'];
if (prefix) {
yield `${hparam.backingName} = System.Linq.Enumerable.ToDictionary(System.Linq.Enumerable.Where(${expression_1.valueOf(httpResponse)}.Headers, header => header.Key.StartsWith("${prefix}",System.StringComparison.InvariantCulture)), header => header.Key.Substring(10), header => System.Linq.Enumerable.FirstOrDefault(header.Value));`;
}
else {
const values = `__${text_manipulation_1.camelCase(['header', ...text_manipulation_1.deconstruct(hparam.serializedName)])}Values`;
yield if_1.If(`${expression_1.valueOf(httpResponse)}.GetHeader("${hparam.serializedName}", out var ${values})`, `${hparam.assignPrivate(hparam.deserializeFromNode(media_types_1.KnownMediaType.Header, values))}`);
}
}
yield `return this;`;
}
}).addTo(this);
}
const hasNonHeaderProperties = dictionary_1.values(this.properties).linq.any(p => !p.IsHeaderProperty);
if (hasNonHeaderProperties) {
if (!this.state.project.storagePipeline) {
this.jsonSerializer = new model_class_json_1.JsonSerializableClass(this);
}
this.xmlSerializer = new model_class_xml_1.XmlSerializableClass(this);
}
}
deserializeFromContainerMember(mediaType, container, serializedName, defaultValue) {
return this.implementation.deserializeFromContainerMember(mediaType, container, serializedName, defaultValue);
}
deserializeFromNode(mediaType, node, defaultValue) {
return this.implementation.deserializeFromNode(mediaType, node, defaultValue);
}
serializeToNode(mediaType, value, serializedName) {
return this.implementation.serializeToNode(mediaType, value, serializedName);
}
/** emits an expression serialize this to a HttpContent */
serializeToContent(mediaType, value) {
return this.implementation.serializeToContent(mediaType, value);
}
/** emits an expression to deserialize content from a string */
deserializeFromString(mediaType, content, defaultValue) {
return this.implementation.deserializeFromString(mediaType, content, defaultValue);
}
serializeToContainerMember(mediaType, value, container, serializedName) {
return this.implementation.serializeToContainerMember(mediaType, value, container, serializedName);
}
get isXmlAttribute() {
return this.implementation.isXmlAttribute;
}
get isRequired() {
return this.implementation.isRequired;
}
/* @internal */ get schema() { return this.implementation.schema; }
validateValue(property) {
return this.implementation.validateValue(property);
}
validatePresence(property) {
return this.implementation.validatePresence(property);
}
addDiscriminator(discriminatorValue, 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);
}
}
}
exports.ModelClass = ModelClass;
//# sourceMappingURL=model-class.js.map