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());
            }
        }
Exemple #3
0
        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) + ">");
 }