public override void CreateModelTypeForOptionalClientProperties(CodeModelTS cm)
        {
            List <string> predefinedOptionalProperties = new List <string>()
            {
                "requestOptions", "filters", "noRetryPolicy", "apiVersion",
                "acceptLanguage", "longRunningOperationRetryTimeout",
                "generateClientRequestId", "rpRegistrationRetryTimeout"
            };
            var optionalProperitesOnClient = cm.Properties.Where(
                p => (!p.IsRequired || p.IsRequired && !string.IsNullOrEmpty(p.DefaultValue)) &&
                !p.IsConstant && !predefinedOptionalProperties.Contains(p.Name));

            if (optionalProperitesOnClient.Count() > 0)
            {
                string modelTypeName = cm.Name + "Options";
                var    modelType     = new CompositeTypeTS(modelTypeName);
                modelType.BaseModelType = New <CompositeType>(new { Name = "AzureServiceClientOptions", SerializedName = "AzureServiceClientOptions" });
                // We could end up having a property that is required but has a default value based on the above condition. If so then make it optional.
                optionalProperitesOnClient.Where(p => p.IsRequired && !string.IsNullOrEmpty(p.DefaultValue)).ForEach(prop => prop.IsRequired = false);
                modelType.AddRange(optionalProperitesOnClient);
                var modelTypeFound = cm.ModelTypes.FirstOrDefault(m => m.Name.EqualsIgnoreCase(modelTypeName));
                if (modelTypeFound != null)
                {
                    cm.Remove(modelTypeFound);
                }
                cm.Add(modelType);
                cm.OptionalParameterTypeForClientConstructor = "Models." + modelTypeName;
            }
        }
Exemple #2
0
        /// <summary>
        /// Finds the UberParent for a given Composite type.
        /// An uber parent is the closest parent that defines the polymorphicDiscriminator
        /// </summary>
        /// <param name="composite">The composite type to find the uberParent for</param>
        /// <returns>The uberParent or itself if it has no uberParent</returns>
        private static CompositeType GetUberParent(CompositeTypeTS composite)
        {
            CompositeType uberParent = composite;

            while (uberParent.BaseModelType != null && string.IsNullOrWhiteSpace(uberParent.PolymorphicDiscriminator))
            {
                uberParent = uberParent.BaseModelType;
            }

            return(uberParent);
        }
        public static CompositeTypeTS CompositeType(string name = null, IEnumerable <PropertyTS> properties = null)
        {
            CompositeTypeTS compositeType = new CompositeTypeTS(name);

            if (properties != null)
            {
                foreach (PropertyTS property in properties)
                {
                    compositeType.Add(property);
                }
            }

            return(compositeType);
        }
        public virtual void CreateModelTypeForOptionalClientProperties(CodeModelTS cm)
        {
            List <string> predefinedOptionalProperties = new List <string>()
            {
                "requestOptions", "filters", "noRetryPolicy"
            };
            var optionalProperitesOnClient = cm.Properties.Where(
                p => (!p.IsRequired || p.IsRequired && !string.IsNullOrEmpty(p.DefaultValue)) &&
                !p.IsConstant && !predefinedOptionalProperties.Contains(p.Name));

            if (optionalProperitesOnClient.Count() > 0)
            {
                string modelTypeName = cm.Name + "Options";
                var    modelType     = new CompositeTypeTS(modelTypeName);
                modelType.BaseModelType = New <CompositeType>(new { Name = "ServiceClientOptions", SerializedName = "ServiceClientOptions" });
                // We could end up having a property that is required but has a default value based on the above condition. If so then make it optional.
                optionalProperitesOnClient.Where(p => p.IsRequired && !string.IsNullOrEmpty(p.DefaultValue)).ForEach(prop => prop.IsRequired = false);
                modelType.AddRange(optionalProperitesOnClient);
                cm.Add(modelType);
                cm.OptionalParameterTypeForClientConstructor = "Models." + modelTypeName;
            }
        }
Exemple #5
0
        public static CompositeTypeTS CompositeType(string name = null, IEnumerable <PropertyTS> properties = null, string xmlPrefix = null, string xmlName = null)
        {
            CompositeTypeTS compositeType = new CompositeTypeTS(name);

            if (!string.IsNullOrEmpty(xmlPrefix))
            {
                compositeType.XmlProperties = new XmlProperties
                {
                    Name   = xmlName,
                    Prefix = xmlPrefix,
                };
            }

            if (properties != null)
            {
                foreach (PropertyTS property in properties)
                {
                    compositeType.Add(property);
                }
            }

            return(compositeType);
        }
        public static void ConstructMapper(TSObject mapper, IModelType type, string serializedName, IVariable parameter, bool isPageable, bool expandComposite, bool isXML, bool isCaseSensitive = true, string xmlName = null)
        {
            string defaultValue = null;
            bool   isRequired   = false;
            bool   isConstant   = false;
            bool   isReadOnly   = false;
            Dictionary <Constraint, string> constraints = null;
            var property = parameter as Property;

            if (parameter != null)
            {
                defaultValue = parameter.DefaultValue;
                isRequired   = parameter.IsRequired;
                isConstant   = parameter.IsConstant;
                constraints  = parameter.Constraints;
            }

            string xmlPrefix = !isXML ? null : property?.XmlPrefix ?? type?.XmlPrefix;

            bool addXmlNameFromParameterValue = isXML && !string.IsNullOrEmpty(xmlName) && xmlName != serializedName;

            if (addXmlNameFromParameterValue)
            {
                if (!string.IsNullOrEmpty(xmlPrefix))
                {
                    xmlName = $"{xmlPrefix}:{xmlName}";
                }
                mapper.QuotedStringProperty("xmlName", xmlName);
            }

            if (isXML && !string.IsNullOrEmpty(serializedName) && !string.IsNullOrEmpty(xmlPrefix))
            {
                serializedName = $"{xmlPrefix}:{serializedName}";
            }

            if (property != null)
            {
                isReadOnly = property.IsReadOnly;

                if (isXML)
                {
                    if (property.XmlIsAttribute)
                    {
                        mapper.BooleanProperty("xmlIsAttribute", true);
                    }

                    if (property.XmlIsWrapped)
                    {
                        mapper.BooleanProperty("xmlIsWrapped", true);
                    }

                    string propertyXmlName = property.ModelType.XmlProperties?.Name ?? property.XmlName;
                    if (!addXmlNameFromParameterValue && !string.IsNullOrEmpty(propertyXmlName))
                    {
                        if (!string.IsNullOrEmpty(xmlPrefix))
                        {
                            propertyXmlName = $"{xmlPrefix}:{propertyXmlName}";
                        }

                        // For some reason we can't omit xmlName in this scenario if it is equal to
                        // serializedName. It might have to do with whether or not xmlElementName
                        // is present, but I'm not sure at this time.
                        mapper.QuotedStringProperty("xmlName", propertyXmlName);
                    }
                }
            }

            CompositeTypeTS composite = type as CompositeTypeTS;

            if (composite != null && composite.ContainsConstantProperties && (parameter != null && parameter.IsRequired))
            {
                defaultValue = "{}";
            }

            SequenceType sequence = type as SequenceType;

            if (sequence != null && isXML)
            {
                if (sequence.ElementXmlIsWrapped)
                {
                    mapper.BooleanProperty("xmlElementIsWrapped", true);
                }

                string xmlElementName = sequence.ElementType.XmlProperties?.Name ?? sequence.ElementXmlName;
                if (!string.IsNullOrEmpty(xmlElementName))
                {
                    mapper.QuotedStringProperty("xmlElementName", xmlElementName);
                }
            }

            if (isRequired)
            {
                mapper.BooleanProperty("required", true);
            }

            if (parameter?.IsXNullable != null)
            {
                if (parameter.IsXNullable.Value)
                {
                    mapper.BooleanProperty("nullable", true);
                }
                else
                {
                    mapper.BooleanProperty("nullable", false);
                }
            }

            if (isReadOnly)
            {
                mapper.BooleanProperty("readOnly", true);
            }

            if (isConstant)
            {
                mapper.BooleanProperty("isConstant", true);
            }

            if (serializedName != null)
            {
                if (!isCaseSensitive)
                {
                    serializedName = serializedName.ToLower();
                }
                mapper.QuotedStringProperty("serializedName", serializedName);
            }

            if (!string.IsNullOrEmpty(defaultValue))
            {
                mapper.TextProperty("defaultValue", defaultValue);
            }

            DictionaryType dictionary = type as DictionaryType;
            PrimaryType    primary    = type as PrimaryType;
            EnumType       enumType   = type as EnumType;

            void applyConstraints(TSObject obj)
            {
                bool useClientSideValidation = (bool)(Settings.Instance?.CustomSettings[CodeModelTS.ClientSideValidationSettingName] ?? false);

                if (useClientSideValidation && constraints != null && constraints.Any())
                {
                    obj.ObjectProperty("constraints", constraintsObject =>
                    {
                        foreach (KeyValuePair <Constraint, string> constraintEntry in constraints)
                        {
                            Constraint constraint  = constraintEntry.Key;
                            string constraintValue = constraintEntry.Value;
                            if (constraint == Constraint.Pattern)
                            {
                                constraintValue = CreateRegexPatternConstraintValue(constraintValue);
                            }
                            constraintsObject.TextProperty(constraint.ToString(), constraintValue);
                        }
                    });
                }
            }

            // Apply header collection constraints only to dictionary values, not the dictionary itself
            string prefix          = parameter?.Extensions?.GetValue <string>(SwaggerExtensions.HeaderCollectionPrefix);
            bool   skipConstraints = !string.IsNullOrEmpty(prefix) && dictionary != null;

            if (!skipConstraints)
            {
                applyConstraints(mapper);
            }

            if (primary != null)
            {
                switch (primary.KnownPrimaryType)
                {
                case KnownPrimaryType.Base64Url:
                case KnownPrimaryType.Boolean:
                case KnownPrimaryType.ByteArray:
                case KnownPrimaryType.Date:
                case KnownPrimaryType.DateTime:
                case KnownPrimaryType.DateTimeRfc1123:
                case KnownPrimaryType.Object:
                case KnownPrimaryType.Stream:
                case KnownPrimaryType.String:
                case KnownPrimaryType.TimeSpan:
                case KnownPrimaryType.UnixTime:
                case KnownPrimaryType.Uuid:
                    AddTypeProperty(mapper, primary.KnownPrimaryType.ToString());
                    break;

                case KnownPrimaryType.Int:
                case KnownPrimaryType.Long:
                case KnownPrimaryType.Decimal:
                case KnownPrimaryType.Double:
                    AddTypeProperty(mapper, "Number");
                    break;

                default:
                    throw new NotImplementedException($"{primary} is not a supported Type.");
                }
            }
            else if (enumType != null)
            {
                if (enumType.ModelAsString)
                {
                    AddTypeProperty(mapper, "String");
                }
                else
                {
                    AddTypeProperty(mapper, "Enum", typeObject =>
                    {
                        typeObject.ArrayProperty("allowedValues", allowedValues =>
                        {
                            foreach (EnumValue enumValue in enumType.Values)
                            {
                                allowedValues.QuotedString(enumValue.SerializedName);
                            }
                        });
                    });
                }
            }
            else if (sequence != null)
            {
                AddTypeProperty(mapper, "Sequence", typeObject =>
                {
                    typeObject.Property("element", element =>
                    {
                        ConstructMapper(element, sequence.ElementType, null, null, false, false, isXML, isCaseSensitive);
                    });
                });
            }
            else if (dictionary != null)
            {
                AddTypeProperty(mapper, "Dictionary", typeObject =>
                {
                    typeObject.ObjectProperty("value", dictionaryValue =>
                    {
                        ConstructMapper(dictionaryValue, dictionary.ValueType, null, null, false, false, isXML, isCaseSensitive);
                        applyConstraints(dictionaryValue);
                    });
                });

                if (!string.IsNullOrEmpty(prefix))
                {
                    mapper.QuotedStringProperty("headerCollectionPrefix", prefix);
                }
            }
            else if (composite != null)
            {
                AddTypeProperty(mapper, "Composite", typeObject =>
                {
                    if (expandComposite)
                    {
                        if (composite.IsPolymorphic)
                        {
                            // Note: If the polymorphicDiscriminator has a dot in it's name then do not escape that dot for
                            // it's serializedName, the way it is done for other properties. This makes it easy to find the
                            // discriminator property from the responseBody during deserialization. Please, do not get confused
                            // between the definition of the discriminator and the definition of the property that is
                            // marked as the discriminator.
                            typeObject.ObjectProperty("polymorphicDiscriminator", polymorphicDiscriminator =>
                            {
                                polymorphicDiscriminator.QuotedStringProperty("serializedName", composite.PolymorphicDiscriminator);
                                polymorphicDiscriminator.QuotedStringProperty("clientName", Singleton <CodeNamerTS> .Instance.GetPropertyName(composite.PolymorphicDiscriminator));
                            });
                            typeObject.QuotedStringProperty("uberParent", composite.Name);
                        }
                        else
                        {
                            CompositeType baseType = composite;
                            while (baseType.BaseModelType != null)
                            {
                                baseType = baseType.BaseModelType;
                            }
                            if (baseType.IsPolymorphic)
                            {
                                typeObject.TextProperty("polymorphicDiscriminator", baseType.Name + ".type.polymorphicDiscriminator");
                                typeObject.QuotedStringProperty("uberParent", baseType.Name);
                            }
                        }
                    }

                    typeObject.QuotedStringProperty("className", composite.Name);

                    if (expandComposite)
                    {
                        typeObject.ObjectProperty("modelProperties", modelProperties =>
                        {
                            if (composite.BaseModelType != null && composite.BaseModelType.ComposedProperties.Any())
                            {
                                modelProperties.Spread(composite.BaseModelType.Name + ".type.modelProperties");
                            }
                            foreach (Property prop in composite.Properties)
                            {
                                var serializedPropertyName = prop.SerializedName;
                                if (isPageable)
                                {
                                    PropertyInfo itemName     = composite.GetType().GetProperty("ItemName");
                                    PropertyInfo nextLinkName = composite.GetType().GetProperty("NextLinkName");
                                    string nextLinkNameValue  = (string)nextLinkName.GetValue(composite);
                                    if (itemName != null && ((string)itemName.GetValue(composite) == prop.Name))
                                    {
                                        serializedPropertyName = "";
                                    }

                                    if (prop.Name.Contains("nextLink") && nextLinkName != null && nextLinkNameValue == null)
                                    {
                                        continue;
                                    }
                                }

                                if (modelProperties.ContainsProperty(prop.Name))
                                {
                                    // throw new InvalidOperationException($"Mapper \"{serializedName}\" contains multiple modelProperties with the name \"{prop.Name}\".");
                                }
                                else
                                {
                                    modelProperties.Property(prop.Name, propertyValue => ConstructMapper(propertyValue, prop.ModelType, serializedPropertyName, prop, false, false, isXML, isCaseSensitive));
                                }
                            }
                        });
                    }

                    if (composite.AdditionalProperties != null)
                    {
                        typeObject.ObjectProperty("additionalProperties", additionalProperties =>
                        {
                            ConstructMapper(additionalProperties, composite.AdditionalProperties, serializedName: null, parameter: null, isPageable: false, expandComposite: false, isXML: isXML);
                        });
                    }
                    else
                    {
                        CompositeTypeTS baseType = composite;
                        while (true)
                        {
                            baseType = (CompositeTypeTS)baseType.BaseModelType;
                            if (baseType == null)
                            {
                                break;
                            }
                            else if (baseType.AdditionalProperties != null)
                            {
                                typeObject.TextProperty("additionalProperties", $"{baseType.Name}.type.additionalProperties");
                                break;
                            }
                        }
                    }
                });
            }
            else
            {
                throw new NotImplementedException($"{type} is not a supported Type.");
            }
        }
        /// <summary>
        /// Return the TypeScript type (as a string) for specified type.
        /// </summary>
        /// <param name="type">IType to query</param>
        /// <param name="inModelsModule">Pass true if generating the code for the models module, thus model types don't need a "models." prefix</param>
        /// <returns>TypeScript type string for type</returns>
        public static string TSType(this IModelType type, bool inModelsModule)
        {
            CompositeTypeTS composite  = type as CompositeTypeTS;
            SequenceType    sequence   = type as SequenceType;
            DictionaryType  dictionary = type as DictionaryType;
            PrimaryType     primary    = type as PrimaryType;
            EnumType        enumType   = type as EnumType;

            string tsType;

            if (primary != null)
            {
                tsType = primary.PrimaryTSType();
            }
            else if (enumType != null)
            {
                string enumName = enumType.DeclarationName;
                if (inModelsModule || enumName.Contains('.') || enumName == "string")
                {
                    tsType = enumName;
                }
                else
                {
                    tsType = "Models." + enumName.ToPascalCase();
                }
            }
            else if (composite != null)
            {
                // ServiceClientCredentials starts with the "msRest." prefix, so strip msRest./msRestAzure. as we import those
                // types with no module prefix needed
                var compositeName = composite.UnionTypeName;
                if (compositeName.StartsWith("msRest.") || compositeName.StartsWith("msRestAzure."))
                {
                    tsType = compositeName.Substring(compositeName.IndexOf('.') + 1);
                }
                else if (inModelsModule || compositeName.Contains('.'))
                {
                    tsType = compositeName;
                }
                else
                {
                    tsType = "Models." + compositeName;
                }
            }
            else if (sequence != null)
            {
                if (sequence.IsSequenceContainingDateKind())
                {
                    tsType = sequence.ElementType.TSType(inModelsModule) + "[]" + " | string[]";
                }
                else
                {
                    tsType = sequence.ElementType.TSType(inModelsModule) + "[]";
                }
            }
            else if (dictionary != null)
            {
                if (dictionary.IsDictionaryContainingDateKind()) //then provide a union of Date and string
                {
                    tsType = "{ [propertyName: string]: " + dictionary.ValueType.TSType(inModelsModule) + " }" + " | { [propertyName: string]: string }";
                }
                else
                {
                    tsType = "{ [propertyName: string]: " + dictionary.ValueType.TSType(inModelsModule) + " }";
                }
            }
            else
            {
                throw new NotImplementedException($"Type '{type}' not implemented");
            }

            return(tsType);
        }