/// <summary> /// Builds an array property. /// </summary> /// <param name="sb">The string builder.</param> /// <param name="propEntry">The property entry.</param> /// <param name="options">The options.</param> private static void BuildArrayProperty(StringBuilder sb, PropertyBag propEntry, JsGeneratorOptions options) { sb.AppendLine(string.Format("\tthis.{0} = new Array(cons.{0} == null ? 0 : cons.{1}.length );", Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase), Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase))); sb.AppendLine($"\tif(cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} != null) {{"); sb.AppendLine( $"\t\tfor (i = 0, length = cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.length; i < length; i++) {{"); var collectionType = propEntry.CollectionInnerTypes.First(); if (!collectionType.IsPrimitiveType) { sb.AppendLine( $"\t\t\tif (!overrideObj.{Helpers.GetName(collectionType.Type.Name, options.ClassNameConstantsToRemove)}) {{"); sb.AppendLine( $"\t\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i] = new {options.OutputNamespace}.{Helpers.GetName(collectionType.Type.Name, options.ClassNameConstantsToRemove)}(cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i]);"); sb.AppendLine("\t\t\t} else {"); sb.AppendLine( $"\t\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i] = new overrideObj.{Helpers.GetName(collectionType.Type.Name, options.ClassNameConstantsToRemove)}(cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i], overrideObj);"); sb.AppendLine("\t\t\t}"); } else { sb.AppendLine( $"\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i] = cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i];"); } sb.AppendLine("\t\t}"); sb.AppendLine("\t}"); }
/// <summary> /// Generates a string containing js definitions of the provided types and all implied descendant types. /// </summary> /// <param name="typesToGenerate">The types to generate.</param> /// <param name="generatorOptions">The generator options. Uses global settings if not provided.</param> /// <returns></returns> public static string Generate(IEnumerable <Type> typesToGenerate, JsGeneratorOptions generatorOptions = null) { var propertyClassCollection = GetPropertyDictionaryForTypeGeneration(typesToGenerate); var js = GenerateJs(propertyClassCollection, generatorOptions); return(js); }
/// <summary> /// Determines whether the property has a default value specified by the DefaultValue attribute. /// </summary> /// <param name="propertyInfo">The property information.</param> /// <param name="generatorOptions">The generator options.</param> /// <returns></returns> public static bool HasDefaultValue(PropertyInfo propertyInfo, JsGeneratorOptions generatorOptions) { if (!generatorOptions.RespectDefaultValueAttribute) return false; var customAttributes = propertyInfo.GetCustomAttributes(true); if (customAttributes.All(p => (p as DefaultValueAttribute) == null)) return false; return true; }
/// <summary> /// Determines whether the property should be generated in the Js model. /// </summary> /// <param name="propertyInfo">The property information.</param> /// <param name="generatorOptions">The generator options.</param> /// <returns></returns> public static bool ShouldGenerateMember(PropertyInfo propertyInfo, JsGeneratorOptions generatorOptions) { if (!generatorOptions.RespectDataMemberAttribute) { return(true); } var customAttributes = propertyInfo.GetCustomAttributes(true); return(customAttributes.All(p => (p as IgnoreDataMemberAttribute) == null)); }
/// <summary> /// Generates a string containing js definitions of the provided types and all implied descendant types. /// </summary> /// <param name="typesToGenerate">The types to generate.</param> /// <param name="generatorOptions">The generator options. Uses global settings if not provided.</param> /// <returns></returns> public static string Generate(IEnumerable<Type> typesToGenerate, JsGeneratorOptions generatorOptions = null) { var passedOptions = generatorOptions ?? Options; if (passedOptions == null) { throw new ArgumentNullException(nameof(passedOptions), "Options cannot be null."); } var propertyClassCollection = TypePropertyDictionaryGenerator.GetPropertyDictionaryForTypeGeneration(typesToGenerate, passedOptions); var js = GenerateJs(propertyClassCollection, passedOptions); return js; }
/// <summary> /// Gets the name of the property. /// </summary> /// <param name="propertyInfo">The property information.</param> /// <param name="generatorOptions">The generator options.</param> /// <returns></returns> public static string GetPropertyName(PropertyInfo propertyInfo, JsGeneratorOptions generatorOptions) { if (!generatorOptions.RespectDataMemberAttribute) return propertyInfo.Name; var customAttributes = propertyInfo.GetCustomAttributes(true); if (customAttributes.All(p => (p as DataMemberAttribute) == null)) return propertyInfo.Name; var dataMemberAttribute = (DataMemberAttribute)customAttributes.First(p => (p as DataMemberAttribute) != null); return !string.IsNullOrWhiteSpace(dataMemberAttribute.Name) ? dataMemberAttribute.Name : propertyInfo.Name; }
/// <summary> /// Generates a string containing js definitions of the provided types and all implied descendant types. /// </summary> /// <param name="typesToGenerate">The types to generate.</param> /// <param name="generatorOptions">The generator options. Uses global settings if not provided.</param> /// <returns></returns> public static string Generate(IEnumerable <Type> typesToGenerate, JsGeneratorOptions generatorOptions = null) { var passedOptions = generatorOptions ?? Options; if (passedOptions == null) { throw new ArgumentNullException(nameof(passedOptions), "Options cannot be null."); } var propertyClassCollection = TypePropertyDictionaryGenerator.GetPropertyDictionaryForTypeGeneration(typesToGenerate, passedOptions); var js = GenerateJs(propertyClassCollection, passedOptions); return(js); }
/// <summary> /// Determines whether the property has a default value specified by the DefaultValue attribute. /// </summary> /// <param name="propertyInfo">The property information.</param> /// <param name="generatorOptions">The generator options.</param> /// <returns></returns> public static bool HasDefaultValue(PropertyInfo propertyInfo, JsGeneratorOptions generatorOptions) { if (!generatorOptions.RespectDefaultValueAttribute) { return(false); } var customAttributes = propertyInfo.GetCustomAttributes(true); if (customAttributes.All(p => (p as DefaultValueAttribute) == null)) { return(false); } return(true); }
/// <summary> /// Gets the name of the property. /// </summary> /// <param name="propertyInfo">The property information.</param> /// <param name="generatorOptions">The generator options.</param> /// <returns></returns> public static string GetPropertyName(PropertyInfo propertyInfo, JsGeneratorOptions generatorOptions) { if (!generatorOptions.RespectDataMemberAttribute) { return(propertyInfo.Name); } var customAttributes = propertyInfo.GetCustomAttributes(true); if (customAttributes.All(p => (p as DataMemberAttribute) == null)) { return(propertyInfo.Name); } var dataMemberAttribute = (DataMemberAttribute)customAttributes.First(p => (p as DataMemberAttribute) != null); return(!string.IsNullOrWhiteSpace(dataMemberAttribute.Name) ? dataMemberAttribute.Name : propertyInfo.Name); }
/// <summary> /// Builds an object/reference property. /// </summary> /// <param name="sb">The string builder.</param> /// <param name="propEntry">The property entry.</param> /// <param name="options">The options.</param> private static void BuildObjectProperty(StringBuilder sb, PropertyBag propEntry, JsGeneratorOptions options) { sb.AppendLine($"\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = null;"); sb.AppendLine($"\tif (cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine( $"\t\tif (!overrideObj.{Helpers.GetName(propEntry.PropertyType.Name, options.ClassNameConstantsToRemove)}) {{"); sb.AppendLine( $"\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = new {options.OutputNamespace}.{Helpers.GetName(propEntry.PropertyType.Name, options.ClassNameConstantsToRemove)}(cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)});"); sb.AppendLine("\t\t} else {"); sb.AppendLine( $"\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = new overrideObj.{Helpers.GetName(propEntry.PropertyType.Name, options.ClassNameConstantsToRemove)}(cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}, overrideObj);"); sb.AppendLine("\t\t}"); sb.AppendLine("\t}"); }
/// <summary> /// Builds a primitive property. /// </summary> /// <param name="propEntry">The property entry.</param> /// <param name="sb">The string builder.</param> /// <param name="options">The options.</param> private static void BuildPrimitiveProperty(PropertyBag propEntry, StringBuilder sb, JsGeneratorOptions options) { if (propEntry.TypeDefinition.IsEnum) { sb.AppendLine( propEntry.PropertyType == typeof(string) ? $"\t{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}: '{propEntry.DefaultValue}'," : $"\t{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}: {propEntry.DefaultValue},"); } else if (propEntry.HasDefaultValue) { var writtenValue = propEntry.DefaultValue is bool ?propEntry.DefaultValue.ToString().ToLower() : propEntry.DefaultValue; sb.AppendLine( $"\tif (!cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine( propEntry.PropertyType == typeof(string) ? $"\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = '{writtenValue}';" : $"\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = {writtenValue};"); sb.AppendLine("\t} else {"); sb.AppendLine( $"\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)};"); sb.AppendLine("\t}"); } else { sb.AppendLine( $"\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)};"); } }
/// <summary> /// Builds a dictionary property. /// </summary> /// <param name="sb">The string builder.</param> /// <param name="propEntry">The property entry.</param> /// <param name="options">The options.</param> private static void BuildDictionaryProperty(StringBuilder sb, PropertyBag propEntry, JsGeneratorOptions options) { sb.AppendLine($"\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = {{}};"); sb.AppendLine($"\tif(cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} != null) {{"); sb.AppendLine( $"\t\tfor (var key in cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine( $"\t\t\tif (cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.hasOwnProperty(key)) {{"); var keyType = propEntry.CollectionInnerTypes.First(p => p.IsDictionaryKey); if (!AllowedDictionaryKeyTypes.Contains(keyType.Type)) { throw new Exception( $"Dictionaries must have strings, enums, or integers as keys, error found in type: {propEntry.TypeName}"); } var valueType = propEntry.CollectionInnerTypes.First(p => !p.IsDictionaryKey); if (!valueType.IsPrimitiveType) { sb.AppendLine( $"\t\t\t\tif (!overrideObj.{Helpers.GetName(valueType.Type.Name, options.ClassNameConstantsToRemove)}) {{"); sb.AppendLine( $"\t\t\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key] = new {options.OutputNamespace}.{Helpers.GetName(valueType.Type.Name, options.ClassNameConstantsToRemove)}(cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key]);"); sb.AppendLine("\t\t\t\t} else {"); sb.AppendLine( $"\t\t\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key] = new overrideObj.{Helpers.GetName(valueType.Type.Name, options.ClassNameConstantsToRemove)}(cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key], overrideObj);"); sb.AppendLine("\t\t\t\t}"); } else { sb.AppendLine( $"\t\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key] = cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key];"); } sb.AppendLine("\t\t\t}"); sb.AppendLine("\t\t}"); sb.AppendLine("\t}"); }
/// <summary> /// Builds the class constructor. /// </summary> /// <param name="type">The type.</param> /// <param name="sb">The string builder.</param> /// <param name="options">The options.</param> private static void BuildClassConstructor(IGrouping<string, PropertyBag> type, StringBuilder sb, JsGeneratorOptions options) { if ( type.Any( p => (p.CollectionInnerTypes != null && p.CollectionInnerTypes.Any(q => !q.IsPrimitiveType)) || p.TransformablePropertyType == PropertyBag.TransformablePropertyTypeEnum.ReferenceType)) { sb.AppendLine( $"{options.OutputNamespace}.{Helpers.GetName(type.First().TypeName, options.ClassNameConstantsToRemove)} = function (cons, overrideObj) {{"); sb.AppendLine("\tif (!overrideObj) { overrideObj = { }; }"); sb.AppendLine("\tif (!cons) { cons = { }; }"); } else if (type.First().TypeDefinition.IsEnum) { sb.AppendLine( $"{options.OutputNamespace}.{Helpers.GetName(type.First().TypeName, options.ClassNameConstantsToRemove)} = {{"); } else { sb.AppendLine( $"{options.OutputNamespace}.{Helpers.GetName(type.First().TypeName, options.ClassNameConstantsToRemove)} = function (cons) {{"); sb.AppendLine("\tif (!cons) { cons = { }; }"); } }
/// <summary> /// Builds the equals function for a type. /// </summary> /// <param name="sb">The string builder.</param> /// <param name="propList">The property list.</param> /// <param name="options">The options.</param> private static void BuildEqualsFunctionForClass(StringBuilder sb, IEnumerable<PropertyBag> propList, JsGeneratorOptions options) { //Generate an equals function for two objects sb.AppendLine("\tthis.$equals = function (compareObj) {"); sb.AppendLine("\t\tif (!compareObj) { return false; }"); foreach (var propEntry in propList) { switch (propEntry.TransformablePropertyType) { case PropertyBag.TransformablePropertyTypeEnum.CollectionType: sb.AppendLine( $"\t\tif (compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} !== this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\tif (!compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\t\treturn false;"); sb.AppendLine($"\t\t\t}}"); sb.AppendLine($"\t\t\tif (!this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\t\treturn false;"); sb.AppendLine($"\t\t\t}}"); sb.AppendLine($"\t\t\tif (compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.length != this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.length) {{"); sb.AppendLine($"\t\t\t\treturn false;"); sb.AppendLine($"\t\t\t}}"); sb.AppendLine( $"\t\t\tfor (i = 0; i < this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.length; i++) {{"); var collectionType = propEntry.CollectionInnerTypes.First(); if (!collectionType.IsPrimitiveType) { sb.AppendLine( $"\t\t\t\tif (!this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i].$equals(compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i])) {{ return false; }};"); } else { sb.AppendLine( $"\t\t\t\tif (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i] !== compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i]) {{ return false; }};"); } sb.AppendLine($"\t\t\t}}"); sb.AppendLine($"\t\t}}"); break; case PropertyBag.TransformablePropertyTypeEnum.DictionaryType: sb.AppendLine( $"\t\tif (compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} !== this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\tif (!compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\t\treturn false;"); sb.AppendLine($"\t\t\t}}"); sb.AppendLine($"\t\t\tif (!this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\t\treturn false;"); sb.AppendLine($"\t\t\t}}"); /*sb.AppendLine( $"\t\tif (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} != null) {{");*/ sb.AppendLine( $"\t\t\tfor (var key in this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine( $"\t\t\t\tif (!compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.hasOwnProperty(key)) {{"); sb.AppendLine( $"\t\t\t\t\treturn false;"); sb.AppendLine("\t\t\t\t}"); var valueType = propEntry.CollectionInnerTypes.First(p => !p.IsDictionaryKey); if (!valueType.IsPrimitiveType) { sb.AppendLine( $"\t\t\t\tif (!this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key].$equals(compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key])) {{ return false; }};"); } else { sb.AppendLine( $"\t\t\t\tif (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key] !== compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key]) {{ return false; }};"); } sb.AppendLine("\t\t\t}"); sb.AppendLine("\t\t}"); break; case PropertyBag.TransformablePropertyTypeEnum.ReferenceType: sb.AppendLine( $"\t\tif (compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} !== this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\tif (!compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\t\treturn false;"); sb.AppendLine($"\t\t\t}}"); sb.AppendLine($"\t\t\tif (!this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\t\treturn false;"); sb.AppendLine($"\t\t\t}}"); sb.AppendLine( $"\t\t\tif (!this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.$equals(compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)})) {{ return false; }};"); sb.AppendLine("\t\t}"); break; case PropertyBag.TransformablePropertyTypeEnum.Primitive: sb.AppendLine( $"\t\tif (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} !== compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{ return false; }};"); break; } } sb.AppendLine("\treturn true;"); sb.AppendLine("\t}"); }
/// <summary> /// Builds the merge function for a type. /// </summary> /// <param name="sb">The string builder.</param> /// <param name="propList">The property list.</param> /// <param name="options">The options.</param> private static void BuildMergeFunctionForClass(StringBuilder sb, IEnumerable<PropertyBag> propList, JsGeneratorOptions options) { //Generate a merge function to merge two objects sb.AppendLine("\tthis.$merge = function (mergeObj) {"); sb.AppendLine("\t\tif (!mergeObj) { mergeObj = { }; }"); foreach (var propEntry in propList) { switch (propEntry.TransformablePropertyType) { case PropertyBag.TransformablePropertyTypeEnum.CollectionType: sb.AppendLine( $"\t\tif (!mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = [];"); sb.AppendLine("\t\t}"); sb.AppendLine( $"\t\tif (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} != null) {{"); sb.AppendLine(string.Format("\t\t\tthis.{0}.splice(0, this.{0}.length);", Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase))); sb.AppendLine("\t\t}"); sb.AppendLine( $"\t\tif (mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine( $"\t\t\tif (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} === null) {{"); sb.AppendLine($"\t\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = [];"); sb.AppendLine("\t\t\t}"); sb.AppendLine( $"\t\t\tfor (i = 0; i < mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.length; i++) {{"); sb.AppendLine(string.Format("\t\t\t\tthis.{0}.push(mergeObj.{0}[i]);", Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase))); sb.AppendLine("\t\t\t}"); sb.AppendLine("\t\t}"); break; case PropertyBag.TransformablePropertyTypeEnum.DictionaryType: sb.AppendLine( $"\t\tif (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} != null) {{"); sb.AppendLine( $"\t\t\tfor (var key in this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine( $"\t\t\t\tif (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.hasOwnProperty(key)) {{"); sb.AppendLine( $"\t\t\t\t\tdelete this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key];"); sb.AppendLine("\t\t\t\t}"); sb.AppendLine("\t\t\t}"); sb.AppendLine("\t\t}"); sb.AppendLine( $"\t\tif (mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine( $"\t\t\tfor (var key in mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine( $"\t\t\t\tif (mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.hasOwnProperty(key)) {{"); sb.AppendLine( $"\t\t\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key] = mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key];"); sb.AppendLine("\t\t\t\t}"); sb.AppendLine("\t\t\t}"); sb.AppendLine("\t\t}"); break; case PropertyBag.TransformablePropertyTypeEnum.ReferenceType: sb.AppendLine( $"\t\tif (mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} == null) {{"); sb.AppendLine($"\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = null;"); sb.AppendLine( $"\t\t}} else if (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} != null) {{"); sb.AppendLine( $"\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.$merge(mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)});"); sb.AppendLine("\t\t} else {"); sb.AppendLine( $"\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)};"); sb.AppendLine("\t\t}"); break; case PropertyBag.TransformablePropertyTypeEnum.Primitive: sb.AppendLine( $"\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)};"); break; } } sb.AppendLine("\t}"); }
/// <summary> /// Generates the js. /// </summary> /// <param name="propertyCollection">The property collection derived from the types to be converted.</param> /// <param name="generationOptions">The generation options.</param> /// <returns></returns> private static string GenerateJs(IEnumerable<PropertyBag> propertyCollection, JsGeneratorOptions generationOptions) { var options = generationOptions; var sbOut = new StringBuilder(); foreach (var type in propertyCollection.GroupBy(r => r.TypeName)) { var typeDefinition = type.First().TypeDefinition; var sb = new StringBuilder(); BuildClassConstructor(type, sb, options); //initialize array variables if any are present in this type if ( type.Any( p => p.TransformablePropertyType == PropertyBag.TransformablePropertyTypeEnum.CollectionType || p.TransformablePropertyType == PropertyBag.TransformablePropertyTypeEnum.DictionaryType)) { sb.AppendLine("\tvar i, length;"); } sb.AppendLine(); var propList = type.GroupBy(t => t.PropertyName).Select(t => t.First()).ToList(); foreach (var propEntry in propList) { switch (propEntry.TransformablePropertyType) { case PropertyBag.TransformablePropertyTypeEnum.CollectionType: BuildArrayProperty(sb, propEntry, options); break; case PropertyBag.TransformablePropertyTypeEnum.DictionaryType: BuildDictionaryProperty(sb, propEntry, options); break; case PropertyBag.TransformablePropertyTypeEnum.ReferenceType: BuildObjectProperty(sb, propEntry, options); break; case PropertyBag.TransformablePropertyTypeEnum.Primitive: BuildPrimitiveProperty(propEntry, sb, options); break; } } if (options.IncludeMergeFunction && !typeDefinition.IsEnum) { sb.AppendLine(); BuildMergeFunctionForClass(sb, propList, options); } if (options.IncludeEqualsFunction && !typeDefinition.IsEnum) { sb.AppendLine(); BuildEqualsFunctionForClass(sb, propList, options); } if (options.CustomFunctionProcessors?.Any() == true) { foreach (var customProcessor in options.CustomFunctionProcessors) { sb.AppendLine(); customProcessor(sb, propList, options); } } BuildClassClosure(sb); sbOut.AppendLine(sb.ToString()); sbOut.AppendLine(); } return sbOut.ToString(); }
/// <summary> /// Builds a primitive property. /// </summary> /// <param name="propEntry">The property entry.</param> /// <param name="sb">The string builder.</param> /// <param name="options">The options.</param> private static void BuildPrimitiveProperty(PropertyBag propEntry, StringBuilder sb, JsGeneratorOptions options) { if (propEntry.TypeDefinition.IsEnum) { sb.AppendLine( propEntry.PropertyType == typeof(string) ? $"\t{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}: '{propEntry.DefaultValue}'," : $"\t{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}: {propEntry.DefaultValue},"); } else if (propEntry.HasDefaultValue) { var writtenValue = propEntry.DefaultValue is bool ? propEntry.DefaultValue.ToString().ToLower() : propEntry.DefaultValue; sb.AppendLine( $"\tif (!cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine( propEntry.PropertyType == typeof(string) ? $"\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = '{writtenValue}';" : $"\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = {writtenValue};"); sb.AppendLine("\t} else {"); sb.AppendLine( $"\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)};"); sb.AppendLine("\t}"); } else { sb.AppendLine( $"\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = cons.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)};"); } }
/// <summary> /// Generates the js. /// </summary> /// <param name="propertyCollection">The property collection derived from the types to be converted.</param> /// <param name="generationOptions">The generation options.</param> /// <returns></returns> private static string GenerateJs(IEnumerable <PropertyBag> propertyCollection, JsGeneratorOptions generationOptions) { var options = generationOptions; var sbOut = new StringBuilder(); foreach (var type in propertyCollection.GroupBy(r => r.TypeName)) { var typeDefinition = type.First().TypeDefinition; var sb = new StringBuilder(); BuildClassConstructor(type, sb, options); //initialize array variables if any are present in this type if ( type.Any( p => p.TransformablePropertyType == PropertyBag.TransformablePropertyTypeEnum.CollectionType || p.TransformablePropertyType == PropertyBag.TransformablePropertyTypeEnum.DictionaryType)) { sb.AppendLine("\tvar i, length;"); } sb.AppendLine(); var propList = type.GroupBy(t => t.PropertyName).Select(t => t.First()).ToList(); foreach (var propEntry in propList) { switch (propEntry.TransformablePropertyType) { case PropertyBag.TransformablePropertyTypeEnum.CollectionType: BuildArrayProperty(sb, propEntry, options); break; case PropertyBag.TransformablePropertyTypeEnum.DictionaryType: BuildDictionaryProperty(sb, propEntry, options); break; case PropertyBag.TransformablePropertyTypeEnum.ReferenceType: BuildObjectProperty(sb, propEntry, options); break; case PropertyBag.TransformablePropertyTypeEnum.Primitive: BuildPrimitiveProperty(propEntry, sb, options); break; } } if (options.IncludeMergeFunction && !typeDefinition.IsEnum) { sb.AppendLine(); BuildMergeFunctionForClass(sb, propList, options); } if (options.IncludeEqualsFunction && !typeDefinition.IsEnum) { sb.AppendLine(); BuildEqualsFunctionForClass(sb, propList, options); } if (options.CustomFunctionProcessors?.Any() == true) { foreach (var customProcessor in options.CustomFunctionProcessors) { sb.AppendLine(); customProcessor(sb, propList, options); } } BuildClassClosure(sb); sbOut.AppendLine(sb.ToString()); sbOut.AppendLine(); } return(sbOut.ToString()); }
/// <summary> /// Gets the property dictionary to be used for type generation. /// </summary> /// <param name="types">The types to generate property information for.</param> /// <param name="generatorOptions">The generator options.</param> /// <param name="propertyTypeCollection">The output collection of properties discovered through reflection of the supplied classes.</param> /// <returns></returns> public static IEnumerable <PropertyBag> GetPropertyDictionaryForTypeGeneration(IEnumerable <Type> types, JsGeneratorOptions generatorOptions, List <PropertyBag> propertyTypeCollection = null) { if (propertyTypeCollection == null) { propertyTypeCollection = new List <PropertyBag>(); } foreach (var type in types) { if (type.IsEnum) { var getVals = type.GetEnumNames(); var typeName = type.Name; foreach (var enumVal in getVals) { if (generatorOptions.TreatEnumsAsStrings) { propertyTypeCollection.Add(new PropertyBag(typeName, type, enumVal, typeof(string), null, PropertyBag.TransformablePropertyTypeEnum.Primitive, true, enumVal)); } else { var trueVal = Convert.ChangeType(Enum.Parse(type, enumVal), type.GetEnumUnderlyingType()); propertyTypeCollection.Add(new PropertyBag(typeName, type, enumVal, type.GetEnumUnderlyingType(), null, PropertyBag.TransformablePropertyTypeEnum.Primitive, true, trueVal)); } } } else { var props = type.GetProperties(); var typeName = type.Name; foreach (var prop in props) { if (!Helpers.ShouldGenerateMember(prop, generatorOptions)) { continue; } var propertyName = Helpers.GetPropertyName(prop, generatorOptions); var propertyType = prop.PropertyType; if (!Helpers.IsPrimitive(propertyType)) { if (Helpers.IsCollectionType(propertyType)) { var collectionInnerTypes = GetCollectionInnerTypes(propertyType); var isDictionaryType = Helpers.IsDictionaryType(propertyType); propertyTypeCollection.Add(new PropertyBag(typeName, type, propertyName, propertyType, collectionInnerTypes, isDictionaryType ? PropertyBag.TransformablePropertyTypeEnum.DictionaryType : PropertyBag.TransformablePropertyTypeEnum.CollectionType, false, null)); //if primitive, no need to reflect type if (collectionInnerTypes.All(p => p.IsPrimitiveType)) { continue; } foreach (var collectionInnerType in collectionInnerTypes.Where(p => !p.IsPrimitiveType)) { var innerTypeName = collectionInnerType.Type.Name; if (propertyTypeCollection.All(p => p.TypeName != innerTypeName)) { GetPropertyDictionaryForTypeGeneration(new[] { collectionInnerType.Type }, generatorOptions, propertyTypeCollection); } } } else { propertyTypeCollection.Add(new PropertyBag(typeName, type, propertyName, propertyType, null, PropertyBag.TransformablePropertyTypeEnum.ReferenceType, false, null)); if (propertyTypeCollection.All(p => p.TypeName != propertyType.Name)) { GetPropertyDictionaryForTypeGeneration(new[] { propertyType }, generatorOptions, propertyTypeCollection); } } } else { var hasDefaultValue = Helpers.HasDefaultValue(prop, generatorOptions); if (hasDefaultValue) { var val = Helpers.ReadDefaultValueFromAttribute(prop); propertyTypeCollection.Add(new PropertyBag(typeName, type, propertyName, propertyType, null, PropertyBag.TransformablePropertyTypeEnum.Primitive, true, val)); } else { propertyTypeCollection.Add(new PropertyBag(typeName, type, propertyName, propertyType, null, PropertyBag.TransformablePropertyTypeEnum.Primitive, false, null)); } if (propertyType.IsEnum) { if (propertyTypeCollection.All(p => p.TypeName != propertyType.Name)) { GetPropertyDictionaryForTypeGeneration(new[] { propertyType }, generatorOptions, propertyTypeCollection); } } } } } } return(propertyTypeCollection); }
/// <summary> /// Builds the class constructor. /// </summary> /// <param name="type">The type.</param> /// <param name="sb">The string builder.</param> /// <param name="options">The options.</param> private static void BuildClassConstructor(IGrouping <string, PropertyBag> type, StringBuilder sb, JsGeneratorOptions options) { if ( type.Any( p => (p.CollectionInnerTypes != null && p.CollectionInnerTypes.Any(q => !q.IsPrimitiveType)) || p.TransformablePropertyType == PropertyBag.TransformablePropertyTypeEnum.ReferenceType)) { sb.AppendLine( $"{options.OutputNamespace}.{Helpers.GetName(type.First().TypeName, options.ClassNameConstantsToRemove)} = function (cons, overrideObj) {{"); sb.AppendLine("\tif (!overrideObj) { overrideObj = { }; }"); sb.AppendLine("\tif (!cons) { cons = { }; }"); } else if (type.First().TypeDefinition.IsEnum) { sb.AppendLine( $"{options.OutputNamespace}.{Helpers.GetName(type.First().TypeName, options.ClassNameConstantsToRemove)} = {{"); } else { sb.AppendLine( $"{options.OutputNamespace}.{Helpers.GetName(type.First().TypeName, options.ClassNameConstantsToRemove)} = function (cons) {{"); sb.AppendLine("\tif (!cons) { cons = { }; }"); } }
/// <summary> /// Generates a string containing js definitions of the provided types and all implied descendant types. /// </summary> /// <param name="typesToGenerate">The types to generate.</param> /// <param name="generatorOptions">The generator options. Uses global settings if not provided.</param> /// <returns></returns> public static string Generate(IEnumerable<Type> typesToGenerate, JsGeneratorOptions generatorOptions = null) { var propertyClassCollection = GetPropertyDictionaryForTypeGeneration(typesToGenerate); var js = GenerateJs(propertyClassCollection, generatorOptions); return js; }
/// <summary> /// Determines whether the property should be generated in the Js model. /// </summary> /// <param name="propertyInfo">The property information.</param> /// <param name="generatorOptions">The generator options.</param> /// <returns></returns> public static bool ShouldGenerateMember(PropertyInfo propertyInfo, JsGeneratorOptions generatorOptions) { if (!generatorOptions.RespectDataMemberAttribute) return true; var customAttributes = propertyInfo.GetCustomAttributes(true); return customAttributes.All(p => (p as IgnoreDataMemberAttribute) == null); }
/// <summary> /// Generates the js. /// </summary> /// <param name="propertyCollection">The property collection derived from the types to be converted.</param> /// <param name="generationOptions">The generation options.</param> /// <returns></returns> private static string GenerateJs(IEnumerable <PropertyBag> propertyCollection, JsGeneratorOptions generationOptions) { var options = generationOptions ?? Options; if (options == null) { throw new ArgumentNullException(nameof(options), "Options cannot be null."); } var sbOut = new StringBuilder(); foreach (var type in propertyCollection.GroupBy(r => r.TypeName)) { var sb = new StringBuilder(); if (type.Any(p => !p.IsPrimitiveType)) { sb.AppendLine( $"{options.OutputNamespace}.{GetName(type.First().TypeName, options.ClassNameConstantsToRemove)} = function (cons, overrideObj) {{"); sb.AppendLine("\tif (!overrideObj) { overrideObj = { }; }"); } else { sb.AppendLine( $"{options.OutputNamespace}.{GetName(type.First().TypeName, options.ClassNameConstantsToRemove)} = function (cons) {{"); } sb.AppendLine("\tif (!cons) { cons = { }; }"); if (type.Any(p => p.IsArray)) { sb.AppendLine("\tvar i, length;"); } sb.AppendLine(); var propList = type.GroupBy(t => t.PropertyName).Select(t => t.First()).ToList(); foreach (var propEntry in propList) { if (propEntry.IsArray) { sb.AppendLine(string.Format("\tthis.{0} = new Array(cons.{0} == null ? 0 : cons.{1}.length );", ToCamelCase(propEntry.PropertyName, options.CamelCase), ToCamelCase(propEntry.PropertyName, options.CamelCase))); sb.AppendLine($"\tif(cons.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} != null) {{"); sb.AppendLine( $"\t\tfor (i = 0, length = cons.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}.length; i < length; i++) {{"); if (!propEntry.IsPrimitiveType) { sb.AppendLine( $"\t\t\tif (!overrideObj.{ GetName(propEntry.PropertyTypeName, options.ClassNameConstantsToRemove) }) {{"); sb.AppendLine( $"\t\t\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i] = new {options.OutputNamespace}.{ GetName(propEntry.PropertyTypeName, options.ClassNameConstantsToRemove) }(cons.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i]);"); sb.AppendLine("\t\t\t} else {"); sb.AppendLine( $"\t\t\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i] = new overrideObj.{ GetName(propEntry.PropertyTypeName, options.ClassNameConstantsToRemove) }(cons.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i], overrideObj);"); sb.AppendLine("\t\t\t}"); } else { sb.AppendLine( $"\t\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i] = cons.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i];"); } sb.AppendLine("\t\t}"); sb.AppendLine("\t}"); } else if (!propEntry.IsPrimitiveType) { sb.AppendLine( $"\tif (!overrideObj.{ GetName(propEntry.PropertyTypeName, options.ClassNameConstantsToRemove) }) {{"); sb.AppendLine( $"\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} = new {options.OutputNamespace}.{ GetName(propEntry.PropertyTypeName, options.ClassNameConstantsToRemove) }(cons.{ToCamelCase(propEntry.PropertyName, options.CamelCase)});"); sb.AppendLine("\t} else {"); sb.AppendLine( $"\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} = new overrideObj.{ GetName(propEntry.PropertyTypeName, options.ClassNameConstantsToRemove) }(cons.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}, overrideObj);"); sb.AppendLine("\t}"); } else { sb.AppendLine( $"\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} = cons.{ToCamelCase(propEntry.PropertyName, options.CamelCase)};"); } } if (options.IncludeMergeFunction) { //Generate a merge function to merge two objects sb.AppendLine(); sb.AppendLine("\tthis.$merge = function (mergeObj) {"); sb.AppendLine("\t\tif (!mergeObj) { mergeObj = { }; }"); foreach (var propEntry in propList) { if (propEntry.IsArray) { sb.AppendLine( $"\t\tif (!mergeObj.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} = null;"); sb.AppendLine("\t\t}"); sb.AppendLine( $"\t\tif (this.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} != null) {{"); sb.AppendLine(string.Format("\t\t\tthis.{0}.splice(0, this.{0}.length);", ToCamelCase(propEntry.PropertyName, options.CamelCase))); sb.AppendLine("\t\t}"); sb.AppendLine( $"\t\tif (mergeObj.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine( $"\t\t\tif (this.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} === null) {{"); sb.AppendLine($"\t\t\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} = [];"); sb.AppendLine("\t\t\t}"); sb.AppendLine( $"\t\t\tfor (i = 0; i < mergeObj.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}.length; i++) {{"); sb.AppendLine(string.Format("\t\t\t\tthis.{0}.push(mergeObj.{0}[i]);", ToCamelCase(propEntry.PropertyName, options.CamelCase))); sb.AppendLine("\t\t\t}"); sb.AppendLine("\t\t}"); } else if (!propEntry.IsPrimitiveType) { sb.AppendLine( $"\t\tif (mergeObj.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} == null) {{"); sb.AppendLine($"\t\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} = null;"); sb.AppendLine( $"\t\t}} else if (this.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} != null) {{"); sb.AppendLine( $"\t\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}.$merge(mergeObj.{ToCamelCase(propEntry.PropertyName, options.CamelCase)});"); sb.AppendLine("\t\t} else {"); sb.AppendLine( $"\t\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} = mergeObj.{ToCamelCase(propEntry.PropertyName, options.CamelCase)};"); sb.AppendLine("\t\t}"); } else { sb.AppendLine( $"\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} = mergeObj.{ToCamelCase(propEntry.PropertyName, options.CamelCase)};"); } } sb.AppendLine("\t}"); } sb.AppendLine("}"); sbOut.AppendLine(sb.ToString()); sbOut.AppendLine(); } return(sbOut.ToString()); }
/// <summary> /// Builds the equals function for a type. /// </summary> /// <param name="sb">The string builder.</param> /// <param name="propList">The property list.</param> /// <param name="options">The options.</param> private static void BuildEqualsFunctionForClass(StringBuilder sb, IEnumerable <PropertyBag> propList, JsGeneratorOptions options) { //Generate an equals function for two objects sb.AppendLine("\tthis.$equals = function (compareObj) {"); sb.AppendLine("\t\tif (!compareObj) { return false; }"); foreach (var propEntry in propList) { switch (propEntry.TransformablePropertyType) { case PropertyBag.TransformablePropertyTypeEnum.CollectionType: sb.AppendLine( $"\t\tif (compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} !== this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\tif (!compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\t\treturn false;"); sb.AppendLine($"\t\t\t}}"); sb.AppendLine($"\t\t\tif (!this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\t\treturn false;"); sb.AppendLine($"\t\t\t}}"); sb.AppendLine($"\t\t\tif (compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.length != this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.length) {{"); sb.AppendLine($"\t\t\t\treturn false;"); sb.AppendLine($"\t\t\t}}"); sb.AppendLine( $"\t\t\tfor (i = 0; i < this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.length; i++) {{"); var collectionType = propEntry.CollectionInnerTypes.First(); if (!collectionType.IsPrimitiveType) { sb.AppendLine( $"\t\t\t\tif (!this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i].$equals(compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i])) {{ return false; }};"); } else { sb.AppendLine( $"\t\t\t\tif (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i] !== compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i]) {{ return false; }};"); } sb.AppendLine($"\t\t\t}}"); sb.AppendLine($"\t\t}}"); break; case PropertyBag.TransformablePropertyTypeEnum.DictionaryType: sb.AppendLine( $"\t\tif (compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} !== this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\tif (!compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\t\treturn false;"); sb.AppendLine($"\t\t\t}}"); sb.AppendLine($"\t\t\tif (!this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\t\treturn false;"); sb.AppendLine($"\t\t\t}}"); /*sb.AppendLine( * $"\t\tif (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} != null) {{");*/ sb.AppendLine( $"\t\t\tfor (var key in this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine( $"\t\t\t\tif (!compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.hasOwnProperty(key)) {{"); sb.AppendLine( $"\t\t\t\t\treturn false;"); sb.AppendLine("\t\t\t\t}"); var valueType = propEntry.CollectionInnerTypes.First(p => !p.IsDictionaryKey); if (!valueType.IsPrimitiveType) { sb.AppendLine( $"\t\t\t\tif (!this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key].$equals(compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key])) {{ return false; }};"); } else { sb.AppendLine( $"\t\t\t\tif (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key] !== compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key]) {{ return false; }};"); } sb.AppendLine("\t\t\t}"); sb.AppendLine("\t\t}"); break; case PropertyBag.TransformablePropertyTypeEnum.ReferenceType: sb.AppendLine( $"\t\tif (compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} !== this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\tif (!compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\t\treturn false;"); sb.AppendLine($"\t\t\t}}"); sb.AppendLine($"\t\t\tif (!this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\t\treturn false;"); sb.AppendLine($"\t\t\t}}"); sb.AppendLine( $"\t\t\tif (!this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.$equals(compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)})) {{ return false; }};"); sb.AppendLine("\t\t}"); break; case PropertyBag.TransformablePropertyTypeEnum.Primitive: sb.AppendLine( $"\t\tif (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} !== compareObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{ return false; }};"); break; } } sb.AppendLine("\treturn true;"); sb.AppendLine("\t}"); }
/// <summary> /// Gets the property dictionary to be used for type generation. /// </summary> /// <param name="types">The types to generate property information for.</param> /// <param name="generatorOptions">The generator options.</param> /// <param name="propertyTypeCollection">The output collection of properties discovered through reflection of the supplied classes.</param> /// <returns></returns> public static IEnumerable<PropertyBag> GetPropertyDictionaryForTypeGeneration(IEnumerable<Type> types, JsGeneratorOptions generatorOptions, List<PropertyBag> propertyTypeCollection = null) { if (propertyTypeCollection == null) { propertyTypeCollection = new List<PropertyBag>(); } foreach (var type in types) { if (type.IsEnum) { var getVals = type.GetEnumNames(); var typeName = type.Name; foreach (var enumVal in getVals) { if (generatorOptions.TreatEnumsAsStrings) { propertyTypeCollection.Add(new PropertyBag(typeName, type, enumVal, typeof (string), null, PropertyBag.TransformablePropertyTypeEnum.Primitive, true, enumVal)); } else { var trueVal = Convert.ChangeType(Enum.Parse(type, enumVal), type.GetEnumUnderlyingType()); propertyTypeCollection.Add(new PropertyBag(typeName, type, enumVal, type.GetEnumUnderlyingType(), null, PropertyBag.TransformablePropertyTypeEnum.Primitive, true, trueVal)); } } } else { var props = type.GetProperties(); var typeName = type.Name; foreach (var prop in props) { if (!Helpers.ShouldGenerateMember(prop, generatorOptions)) continue; var propertyName = Helpers.GetPropertyName(prop, generatorOptions); var propertyType = prop.PropertyType; if (!Helpers.IsPrimitive(propertyType)) { if (Helpers.IsCollectionType(propertyType)) { var collectionInnerTypes = GetCollectionInnerTypes(propertyType); var isDictionaryType = Helpers.IsDictionaryType(propertyType); propertyTypeCollection.Add(new PropertyBag(typeName, type, propertyName, propertyType, collectionInnerTypes, isDictionaryType ? PropertyBag.TransformablePropertyTypeEnum.DictionaryType : PropertyBag.TransformablePropertyTypeEnum.CollectionType, false, null)); //if primitive, no need to reflect type if (collectionInnerTypes.All(p => p.IsPrimitiveType)) continue; foreach (var collectionInnerType in collectionInnerTypes.Where(p => !p.IsPrimitiveType)) { var innerTypeName = collectionInnerType.Type.Name; if (propertyTypeCollection.All(p => p.TypeName != innerTypeName)) { GetPropertyDictionaryForTypeGeneration(new[] {collectionInnerType.Type}, generatorOptions, propertyTypeCollection); } } } else { propertyTypeCollection.Add(new PropertyBag(typeName, type, propertyName, propertyType, null, PropertyBag.TransformablePropertyTypeEnum.ReferenceType, false, null)); if (propertyTypeCollection.All(p => p.TypeName != propertyType.Name)) { GetPropertyDictionaryForTypeGeneration(new[] {propertyType}, generatorOptions, propertyTypeCollection); } } } else { var hasDefaultValue = Helpers.HasDefaultValue(prop, generatorOptions); if (hasDefaultValue) { var val = Helpers.ReadDefaultValueFromAttribute(prop); propertyTypeCollection.Add(new PropertyBag(typeName, type, propertyName, propertyType, null, PropertyBag.TransformablePropertyTypeEnum.Primitive, true, val)); } else { propertyTypeCollection.Add(new PropertyBag(typeName, type, propertyName, propertyType, null, PropertyBag.TransformablePropertyTypeEnum.Primitive, false, null)); } if (propertyType.IsEnum) { if (propertyTypeCollection.All(p => p.TypeName != propertyType.Name)) { GetPropertyDictionaryForTypeGeneration(new[] {propertyType}, generatorOptions, propertyTypeCollection); } } } } } } return propertyTypeCollection; }
/// <summary> /// Generates the js. /// </summary> /// <param name="propertyCollection">The property collection derived from the types to be converted.</param> /// <param name="generationOptions">The generation options.</param> /// <returns></returns> private static string GenerateJs(IEnumerable<PropertyBag> propertyCollection, JsGeneratorOptions generationOptions) { var options = generationOptions ?? Options; if (options == null) { throw new ArgumentNullException(nameof(options), "Options cannot be null."); } var sbOut = new StringBuilder(); foreach (var type in propertyCollection.GroupBy(r => r.TypeName)) { var sb = new StringBuilder(); if (type.Any(p => !p.IsPrimitiveType)) { sb.AppendLine( $"{options.OutputNamespace}.{GetName(type.First().TypeName, options.ClassNameConstantsToRemove)} = function (cons, overrideObj) {{"); sb.AppendLine("\tif (!overrideObj) { overrideObj = { }; }"); } else { sb.AppendLine( $"{options.OutputNamespace}.{GetName(type.First().TypeName, options.ClassNameConstantsToRemove)} = function (cons) {{"); } sb.AppendLine("\tif (!cons) { cons = { }; }"); if (type.Any(p => p.IsArray)) { sb.AppendLine("\tvar i, length;"); } sb.AppendLine(); var propList = type.GroupBy(t => t.PropertyName).Select(t => t.First()).ToList(); foreach (var propEntry in propList) { if (propEntry.IsArray) { sb.AppendLine(string.Format("\tthis.{0} = new Array(cons.{0} == null ? 0 : cons.{1}.length );", ToCamelCase(propEntry.PropertyName, options.CamelCase), ToCamelCase(propEntry.PropertyName, options.CamelCase))); sb.AppendLine($"\tif(cons.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} != null) {{"); sb.AppendLine( $"\t\tfor (i = 0, length = cons.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}.length; i < length; i++) {{"); if (!propEntry.IsPrimitiveType) { sb.AppendLine( $"\t\t\tif (!overrideObj.{ GetName(propEntry.PropertyTypeName, options.ClassNameConstantsToRemove) }) {{"); sb.AppendLine( $"\t\t\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i] = new {options.OutputNamespace}.{ GetName(propEntry.PropertyTypeName, options.ClassNameConstantsToRemove) }(cons.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i]);"); sb.AppendLine("\t\t\t} else {"); sb.AppendLine( $"\t\t\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i] = new overrideObj.{ GetName(propEntry.PropertyTypeName, options.ClassNameConstantsToRemove) }(cons.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i], overrideObj);"); sb.AppendLine("\t\t\t}"); } else { sb.AppendLine( $"\t\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i] = cons.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}[i];"); } sb.AppendLine("\t\t}"); sb.AppendLine("\t}"); } else if (!propEntry.IsPrimitiveType) { sb.AppendLine( $"\tif (!overrideObj.{ GetName(propEntry.PropertyTypeName, options.ClassNameConstantsToRemove) }) {{"); sb.AppendLine( $"\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} = new {options.OutputNamespace}.{ GetName(propEntry.PropertyTypeName, options.ClassNameConstantsToRemove) }(cons.{ToCamelCase(propEntry.PropertyName, options.CamelCase)});"); sb.AppendLine("\t} else {"); sb.AppendLine( $"\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} = new overrideObj.{ GetName(propEntry.PropertyTypeName, options.ClassNameConstantsToRemove) }(cons.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}, overrideObj);"); sb.AppendLine("\t}"); } else { sb.AppendLine( $"\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} = cons.{ToCamelCase(propEntry.PropertyName, options.CamelCase)};"); } } if (options.IncludeMergeFunction) { //Generate a merge function to merge two objects sb.AppendLine(); sb.AppendLine("\tthis.$merge = function (mergeObj) {"); sb.AppendLine("\t\tif (!mergeObj) { mergeObj = { }; }"); foreach (var propEntry in propList) { if (propEntry.IsArray) { sb.AppendLine( $"\t\tif (!mergeObj.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} = null;"); sb.AppendLine("\t\t}"); sb.AppendLine( $"\t\tif (this.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} != null) {{"); sb.AppendLine(string.Format("\t\t\tthis.{0}.splice(0, this.{0}.length);", ToCamelCase(propEntry.PropertyName, options.CamelCase))); sb.AppendLine("\t\t}"); sb.AppendLine( $"\t\tif (mergeObj.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine( $"\t\t\tif (this.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} === null) {{"); sb.AppendLine($"\t\t\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} = [];"); sb.AppendLine("\t\t\t}"); sb.AppendLine( $"\t\t\tfor (i = 0; i < mergeObj.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}.length; i++) {{"); sb.AppendLine(string.Format("\t\t\t\tthis.{0}.push(mergeObj.{0}[i]);", ToCamelCase(propEntry.PropertyName, options.CamelCase))); sb.AppendLine("\t\t\t}"); sb.AppendLine("\t\t}"); } else if (!propEntry.IsPrimitiveType) { sb.AppendLine( $"\t\tif (mergeObj.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} == null) {{"); sb.AppendLine($"\t\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} = null;"); sb.AppendLine( $"\t\t}} else if (this.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} != null) {{"); sb.AppendLine( $"\t\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)}.$merge(mergeObj.{ToCamelCase(propEntry.PropertyName, options.CamelCase)});"); sb.AppendLine("\t\t} else {"); sb.AppendLine( $"\t\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} = mergeObj.{ToCamelCase(propEntry.PropertyName, options.CamelCase)};"); sb.AppendLine("\t\t}"); } else { sb.AppendLine( $"\t\tthis.{ToCamelCase(propEntry.PropertyName, options.CamelCase)} = mergeObj.{ToCamelCase(propEntry.PropertyName, options.CamelCase)};"); } } sb.AppendLine("\t}"); } sb.AppendLine("}"); sbOut.AppendLine(sb.ToString()); sbOut.AppendLine(); } return sbOut.ToString(); }
/// <summary> /// Builds the merge function for a type. /// </summary> /// <param name="sb">The string builder.</param> /// <param name="propList">The property list.</param> /// <param name="options">The options.</param> private static void BuildMergeFunctionForClass(StringBuilder sb, IEnumerable <PropertyBag> propList, JsGeneratorOptions options) { //Generate a merge function to merge two objects sb.AppendLine("\tthis.$merge = function (mergeObj) {"); sb.AppendLine("\t\tif (!mergeObj) { mergeObj = { }; }"); foreach (var propEntry in propList) { switch (propEntry.TransformablePropertyType) { case PropertyBag.TransformablePropertyTypeEnum.CollectionType: sb.AppendLine( $"\t\tif (!mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine($"\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = [];"); sb.AppendLine("\t\t}"); sb.AppendLine( $"\t\tif (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} != null) {{"); sb.AppendLine(string.Format("\t\t\tthis.{0}.splice(0, this.{0}.length);", Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase))); sb.AppendLine("\t\t}"); sb.AppendLine( $"\t\tif (mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine( $"\t\t\tif (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} === null) {{"); sb.AppendLine($"\t\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = [];"); sb.AppendLine("\t\t\t}"); sb.AppendLine( $"\t\t\tfor (i = 0; i < mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.length; i++) {{"); sb.AppendLine(string.Format("\t\t\t\tthis.{0}.push(mergeObj.{0}[i]);", Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase))); sb.AppendLine("\t\t\t}"); sb.AppendLine("\t\t}"); break; case PropertyBag.TransformablePropertyTypeEnum.DictionaryType: sb.AppendLine( $"\t\tif (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} != null) {{"); sb.AppendLine( $"\t\t\tfor (var key in this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine( $"\t\t\t\tif (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.hasOwnProperty(key)) {{"); sb.AppendLine( $"\t\t\t\t\tdelete this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key];"); sb.AppendLine("\t\t\t\t}"); sb.AppendLine("\t\t\t}"); sb.AppendLine("\t\t}"); sb.AppendLine( $"\t\tif (mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine( $"\t\t\tfor (var key in mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}) {{"); sb.AppendLine( $"\t\t\t\tif (mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.hasOwnProperty(key)) {{"); sb.AppendLine( $"\t\t\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key] = mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}[key];"); sb.AppendLine("\t\t\t\t}"); sb.AppendLine("\t\t\t}"); sb.AppendLine("\t\t}"); break; case PropertyBag.TransformablePropertyTypeEnum.ReferenceType: sb.AppendLine( $"\t\tif (mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} == null) {{"); sb.AppendLine($"\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = null;"); sb.AppendLine( $"\t\t}} else if (this.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} != null) {{"); sb.AppendLine( $"\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)}.$merge(mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)});"); sb.AppendLine("\t\t} else {"); sb.AppendLine( $"\t\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)};"); sb.AppendLine("\t\t}"); break; case PropertyBag.TransformablePropertyTypeEnum.Primitive: sb.AppendLine( $"\t\tthis.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)} = mergeObj.{Helpers.ToCamelCase(propEntry.PropertyName, options.CamelCase)};"); break; } } sb.AppendLine("\t}"); }