protected string Generate() { var resultBuilder = new StringBuilder(); var graph = new QuickGraph.AdjacencyGraph <Type, QuickGraph.Edge <Type> >(false); graph.AddVertexRange(_types); var typeDefinitions = new Dictionary <Type, String>(); resultBuilder.AppendLine(this._options.NamespaceDefinitionExpression(this._options.NamespaceVarName)); resultBuilder.AppendLine(); GenerateTypeDefinitions(this._options.NamespaceVarName, graph, typeDefinitions); foreach (var type in graph.TopologicalSort().Reverse()) { string definition; if (typeDefinitions.TryGetValue(type, out definition)) { resultBuilder.Append(definition); } else if (false == type.Assembly.Equals(Assembly.GetAssembly(typeof(string)))) { resultBuilder.AppendLine("// unknown: " + type.Name + Environment.NewLine); } } return(resultBuilder.ToString()); }
protected void GenerateTypeDefinition(string closureNamespaceVar, QuickGraph.AdjacencyGraph <Type, QuickGraph.Edge <Type> > graph, Dictionary <Type, string> typeDefinitions, Type type) { if (type.IsClass) { var typeResultBuilder = GenerateClassDefinition(type, graph); typeDefinitions.Add(type, typeResultBuilder.ToString()); } if (type.IsEnum) { var typeResultBuilder = GenerateEnumDefinition(type, graph); typeDefinitions.Add(type, typeResultBuilder.ToString()); } }
protected StringBuilder GenerateEnumDefinition(Type type, QuickGraph.AdjacencyGraph <Type, QuickGraph.Edge <Type> > graph) { Console.Error.WriteLine("Generating Enum: " + type.Name); var typeResultBuilder = new StringBuilder(); AppendTypeComment(typeResultBuilder, type); typeResultBuilder.AppendLine("/** @enum {string} */"); typeResultBuilder.AppendLine(GetFullTypeName(type) + " = {"); foreach (var pair in WithIsLast(Enum.GetNames(type))) { typeResultBuilder.AppendFormat(" {0}: '{0}'{1}{2}", pair.Item1, pair.Item2 ? String.Empty : ",", Environment.NewLine); } typeResultBuilder.AppendLine("};"); typeResultBuilder.AppendLine(); return(typeResultBuilder); }
protected string GetJSTypeName(Type sourceType, Type propertyType, QuickGraph.AdjacencyGraph <Type, QuickGraph.Edge <Type> > graph) { if (propertyType.IsGenericParameter) { return(propertyType.Name); } var overrideTypeName = this._options.TryGetTypeName(propertyType); if (String.IsNullOrWhiteSpace(overrideTypeName)) { if (propertyType.IsGenericType) { if (IsGenericTypeNullable(propertyType)) { return("?" + GetJSTypeName(sourceType, Nullable.GetUnderlyingType(propertyType), graph)); } var dictionaryType = propertyType.GetInterfaces().SingleOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition().Equals(typeof(IDictionary <,>))); if (null != dictionaryType) { var typeArgs = dictionaryType.GetGenericArguments().ToArray(); var keyType = typeArgs[0]; var valueType = typeArgs[1]; return(GetJSObjectTypeName(sourceType, keyType, valueType, graph)); } var enumerableType = propertyType.GetInterfaces().SingleOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition().Equals(typeof(IEnumerable <>))); if (null != enumerableType) { return(GetJSArrayTypeName(sourceType, enumerableType.GetGenericArguments().Single(), graph)); } } if (propertyType.IsArray) { var elementType = propertyType.GetElementType(); return(GetJSArrayTypeName(sourceType, elementType, graph)); } } graph.AddVertex(propertyType); graph.AddVertex(sourceType); if (InAllowedAssemblies(propertyType)) { graph.AddEdge(new QuickGraph.Edge <Type>(sourceType, propertyType)); return(this.GetFullTypeName(propertyType)); } return(overrideTypeName ?? GetTypeName(propertyType)); }
protected StringBuilder GenerateClassDefinition(Type type, QuickGraph.AdjacencyGraph <Type, QuickGraph.Edge <Type> > graph) { Console.Error.WriteLine("Generating Class: " + type.Name); var typeResultBuilder = new StringBuilder(); var className = this.GetFullTypeName(type); AppendTypeComment(typeResultBuilder, type); typeResultBuilder.AppendLine("/** @constructor"); if (type.IsGenericTypeDefinition) { typeResultBuilder.AppendLine(" * @template " + String.Join(", ", type.GetGenericArguments().Select(x => x.Name))); } foreach (var annotation in this._options.ConstructorAnnotations(className)) { typeResultBuilder.AppendLine(" * " + annotation); } typeResultBuilder.AppendLine(" */"); typeResultBuilder.AppendLine(className + " = " + this._options.ConstructorExpression(className) + ";"); var properties = type.GetProperties(); foreach (var propertyPair in WithIsLast(properties)) { var property = propertyPair.Item1; var isLast = propertyPair.Item2; string propertyName = this.GetPropertyName(type, property.Name); var mappedType = MapType(property.PropertyType); var jsTypeName = GetJSTypeName(type, mappedType, graph); typeResultBuilder.AppendLine(String.Format("/** @type {{{0}}} */", jsTypeName)); typeResultBuilder.AppendLine(String.Format("{0}.prototype.{1} = {2};", className, propertyName, GetDefaultJSValue(mappedType))); } typeResultBuilder.AppendLine(); return(typeResultBuilder); }
protected void GenerateTypeDefinitions(string closureNamespaceVar, QuickGraph.AdjacencyGraph <Type, QuickGraph.Edge <Type> > graph, Dictionary <Type, string> typeDefinitions) { // Every time we generate a type, we may find new type dependencies and they will be added to the graph. // We keep generating types as long as the graph contains items that were not generated. var processedTypes = new HashSet <Type>(); while (true) { var unprocessedTypes = graph.Vertices.Except(processedTypes).ToArray(); if (false == unprocessedTypes.Any()) { break; } foreach (var type in unprocessedTypes) { processedTypes.Add(type); if (false == InAllowedAssemblies(type)) { continue; } GenerateTypeDefinition(closureNamespaceVar, graph, typeDefinitions, type); } } }
private string GetJSObjectTypeName(Type sourceType, Type keyType, Type valueType, QuickGraph.AdjacencyGraph <Type, QuickGraph.Edge <Type> > graph) { return("Object.<" + GetJSTypeName(sourceType, keyType, graph) + ", " + GetJSTypeName(sourceType, valueType, graph) + ">"); }
private string GetJSArrayTypeName(Type sourceType, Type propertyType, QuickGraph.AdjacencyGraph <Type, QuickGraph.Edge <Type> > graph) { return("Array.<" + GetJSTypeName(sourceType, propertyType, graph) + ">"); }