Beispiel #1
0
        void BuildTable <T>(MarkdownBuilder mb, string label, T[] array, IEnumerable <XmlDocumentComment> docs, Func <T, string> type, Func <T, string> name, Func <T, string> finalName)
        {
            if (array.Any())
            {
                mb.AppendLine(label);
                mb.AppendLine();

                string[] head = new[] { "Type", "Name", "Summary" };

                IEnumerable <T> seq = array;

                IEnumerable <string[]> data = seq.Select(item2 => {
                    string summary = docs.FirstOrDefault(x => x.MemberName == name(item2))?.Summary ?? "";
                    return(new string[] { MarkdownBuilder.MarkdownCodeQuote(type(item2)), finalName(item2), summary });
                });

                mb.Table(head, data);
                mb.AppendLine();
            }
        }
        void BuildTable <T>(MarkdownBuilder mb, string label, T[] array, IEnumerable <XmlDocumentComment> docs, Func <T, string> type, Func <T, string> name, Func <T, string> finalName)
        {
            if (array.Any())
            {
                mb.AppendLine(label);
                mb.AppendLine();

                string[] head = (this.type.IsEnum)
                    ? new[] { "Value", "Name", "Summary" }
                    : new[] { "Type", "Name", "Summary" };

                IEnumerable <T> seq = array;
                if (!this.type.IsEnum)
                {
                    seq = array.OrderBy(x => name(x));
                }

                var data = seq.Select(item2 =>
                {
                    var candidates = docs.Where(x => x.MemberName == name(item2) || x.MemberName.StartsWith(name(item2) + "`")).ToArray();
                    if (candidates.Count() >= 2 && item2 is MethodBase)
                    {
                        // Attempt to identify method overloads
                        var methodParameterNames = (item2 as MethodBase).GetParameters().Select(p => p.Name);
                        var overloadCandidates   = candidates.Where(x => x.Parameters.Keys.SequenceEqual(methodParameterNames)).ToArray();
                        if (overloadCandidates.Any())
                        {
                            candidates = overloadCandidates;
                        }
                    }
                    var summary = candidates.FirstOrDefault()?.Summary ?? "";
                    return(new[] { MarkdownBuilder.MarkdownCodeQuote(type(item2)), finalName(item2), summary });
                });

                mb.Table(head, data);
                mb.AppendLine();
            }
        }
Beispiel #3
0
        private void BuildTable <T> (MarkdownBuilder mb, string label, T[] array, IEnumerable <XmlDocumentComment> docs, Func <T, string> type, Func <T, string> name, Func <T, string> finalName)
        {
            if (array.Any())
            {
                mb.Header(4, label);
                mb.AppendLine();

                var head = Type.IsEnum ? new[] { "Value", "Name", "Summary" } : new[] { "Type", "Name", "Summary" };

                IEnumerable <T> seq = array;
                if (!Type.IsEnum)
                {
                    seq = array.OrderBy(x => name(x));
                }

                var data = seq.Select(item2 => {
                    var summary = docs.FirstOrDefault(x => x.MemberName == name(item2) || x.MemberName.StartsWith(name(item2) + "`"))?.Summary ?? "";
                    return(new[] { type(item2), finalName(item2), summary });
                });

                mb.Table(head, data);
                mb.AppendLine();
            }
        }
        public string BuildMethodsPage()
        {
            var mb = new MarkdownBuilder();

            mb.Header(2, Beautifier.BeautifyType(type, false) + " Methods");
            mb.AppendLine();
            mb.AppendLine($"Namespace: {type.Namespace}");
            mb.AppendLine();
            mb.AppendLine($"Assembly: {type.Assembly.ManifestModule.Name}");
            mb.AppendLine();

            var summary = commentLookup[type.FullName].FirstOrDefault(x => x.MemberType == MemberType.Type)?.Summary ?? string.Empty;

            if (summary != string.Empty)
            {
                mb.AppendLine(summary);
            }

            mb.AppendLine();

            BuildTable(mb, "Methods", GetMethods(), commentLookup[type.FullName], x => Beautifier.BeautifyType(x.ReturnType), x => x.Name, x => Beautifier.ToMarkdownMethodInfoWithoutParamNames(x));

            return(mb.ToString());
        }
        // 0 = DLL source path, 1 = destination root
        private static void Main(string[] args)
        {
            // put DLL & XML on same directory.
            string target         = null;
            string dest           = "docs";
            string namespaceMatch = string.Empty;

            if (args.Length == 0)
            {
                Console.WriteLine("DLL file location is a required argument");
                Environment.Exit(1);
            }
            if (args.Length == 1)
            {
                target = args[0];
            }
            else if (args.Length == 2)
            {
                target = args[0];
                dest   = args[1];
            }
            else if (args.Length == 3)
            {
                target         = args[0];
                dest           = args[1];
                namespaceMatch = args[2];
            }

            MarkdownableType[] types = MarkdownGenerator.Load(target, namespaceMatch);

            // Home Markdown Builder
            MarkdownBuilder homeBuilder = new MarkdownBuilder();

            homeBuilder.Header(1, "References");
            homeBuilder.AppendLine();

            foreach (IGrouping <string, MarkdownableType> g in types.GroupBy(x => x.Namespace).OrderBy(x => x.Key))
            {
                if (!Directory.Exists(dest))
                {
                    Directory.CreateDirectory(dest);
                }

                homeBuilder.HeaderWithLink(2, g.Key, g.Key);
                homeBuilder.AppendLine();

                StringBuilder sb = new StringBuilder();
                foreach (MarkdownableType item in g.OrderBy(x => x.Name))
                {
                    homeBuilder.ListLink(MarkdownBuilder.MarkdownCodeQuote(item.BeautifyName), g.Key + "#" + item.BeautifyName.Replace("<", "").Replace(">", "").Replace(",", "").Replace(" ", "-").ToLower());

                    sb.Append(item.ToString());
                }

                File.WriteAllText(Path.Combine(dest, g.Key + ".md"), sb.ToString());
                homeBuilder.AppendLine();
            }

            // Gen Home
            File.WriteAllText(Path.Combine(dest, "Home.md"), homeBuilder.ToString());
        }
Beispiel #6
0
        private string GeneralToString()
        {
            var mb = new MarkdownBuilder();

            mb.Header(2, Beautifier.BeautifyType(Type, false));
            mb.AppendLine();

            var summary = commentLookup[Type.FullName].FirstOrDefault(x => x.MemberType == MemberType.Type)?.Summary;

            if (!string.IsNullOrWhiteSpace(summary))
            {
                mb.Header(4, "Summary");
                mb.AppendLine(summary);
            }

            var remarks = commentLookup[Type.FullName].FirstOrDefault(x => x.MemberType == MemberType.Type)?.Remarks;

            if (!string.IsNullOrWhiteSpace(remarks))
            {
                mb.Header(4, "Remarks");
                mb.AppendLine(remarks);
            }

            { // Signature code.
                var stat = (Type.IsAbstract && Type.IsSealed) ? "static " : "";
                var abst = (Type.IsAbstract && !Type.IsInterface && !Type.IsSealed) ? "abstract " : "";
                var classOrStructOrEnumOrInterface = Type.IsInterface ? "interface" : Type.IsEnum ? "enum" : Type.IsValueType ? "struct" : "class";

                var sb = new StringBuilder();
                sb.AppendLine($"public {stat}{abst}{classOrStructOrEnumOrInterface} {Beautifier.BeautifyType(Type, true)}");
                var impl = string.Join(", ", new[] { Type.BaseType }.Concat(Type.GetInterfaces()).Where(x => x != null && x != typeof(object) && x != typeof(ValueType)).Select(x => Beautifier.BeautifyType(x)));
                if (impl != "")
                {
                    sb.AppendLine("    : " + impl);
                }

                mb.Code("csharp", sb.ToString());
                mb.AppendLine();
            }

            if (Type.IsEnum)
            {
                var enums = Enum.GetNames(Type)
                            .Select(x => new { Name = x, Value = (int)Enum.Parse(Type, x) })
                            .OrderBy(x => x.Value).ToArray();

                BuildTable(mb, "Enum", enums, commentLookup[Type.FullName], x => x.Value.ToString(), x => x.Name, x => x.Name);
            }
            else
            {
                BuildTable(mb, "Fields", GetFields(), commentLookup[Type.FullName], x => Beautifier.BeautifyType(x.FieldType), x => x.Name, x => x.Name);
                BuildTable(mb, "Properties", GetProperties(), commentLookup[Type.FullName], x => Beautifier.BeautifyType(x.PropertyType), x => x.Name, x => x.Name);
                BuildTable(mb, "Events", GetEvents(), commentLookup[Type.FullName], x => Beautifier.BeautifyType(x.EventHandlerType), x => x.Name, x => x.Name);
                BuildTable(mb, "Methods", GetMethods(), commentLookup[Type.FullName], x => Beautifier.BeautifyType(x.ReturnType), x => x.Name, x => Beautifier.ToMarkdownMethodInfo(x));
                BuildTable(mb, "Static Fields", GetStaticFields(), commentLookup[Type.FullName], x => Beautifier.BeautifyType(x.FieldType), x => x.Name, x => x.Name);
                BuildTable(mb, "Static Properties", GetStaticProperties(), commentLookup[Type.FullName], x => Beautifier.BeautifyType(x.PropertyType), x => x.Name, x => x.Name);
                BuildTable(mb, "Static Methods", GetStaticMethods(), commentLookup[Type.FullName], x => Beautifier.BeautifyType(x.ReturnType), x => x.Name, x => Beautifier.ToMarkdownMethodInfo(x));
                BuildTable(mb, "Static Events", GetStaticEvents(), commentLookup[Type.FullName], x => Beautifier.BeautifyType(x.EventHandlerType), x => x.Name, x => x.Name);
            }

            return(mb.ToString());
        }
Beispiel #7
0
        private string CommandToString()
        {
            var mb = new MarkdownBuilder();

            if (HasCommandAlias)
            {
                mb.Header(2, CommandAlias);
            }
            else
            {
                var typeName = Beautifier.BeautifyType(Type, false);
                typeName = char.ToLowerInvariant(typeName[0]) + (typeName.Length > 1 ? typeName.Substring(1) : string.Empty);
                mb.Header(2, typeName);
            }
            mb.AppendLine();

            var summary = commentLookup[Type.FullName].FirstOrDefault(x => x.MemberType == MemberType.Type)?.Summary;

            if (!string.IsNullOrWhiteSpace(summary))
            {
                mb.Header(4, "Summary");
                mb.AppendLine(summary);
                mb.AppendLine();
            }

            var remarks = commentLookup[Type.FullName].FirstOrDefault(x => x.MemberType == MemberType.Type)?.Remarks;

            if (!string.IsNullOrWhiteSpace(remarks))
            {
                mb.Header(4, "Remarks");
                mb.AppendLine(remarks);
                mb.AppendLine();
            }

            // Params ----------------------------------------
            var parameters = GetParameters().Where(f => f.Name != "Wait" && f.Name != "ConditionalExpression");

            if (parameters.Count() > 0)
            {
                mb.Header(4, "Parameters");
                mb.Append("\n<div class=\"config-table\">\n\n");
                mb.Append("ID | Type | Description\n");
                mb.Append("--- | --- | ---\n");
                foreach (var parameter in parameters)
                {
                    var paramAlias = parameter.CustomAttributes.FirstOrDefault(a => a.AttributeType.Name == paramAliasAttrName)?.ConstructorArguments[0].Value as string;
                    var paramId    = paramAlias ?? parameter.Name;
                    var isNameless = paramId == string.Empty;
                    var isOptional = !parameter.CustomAttributes.Any(a => a.AttributeType.Name == requiredParamAttrName);
                    if (isNameless)
                    {
                        paramId = parameter.Name;
                    }
                    else
                    {
                        paramId = char.ToLowerInvariant(paramId[0]) + (paramId.Length > 1 ? paramId.Substring(1) : string.Empty);
                    }
                    if (isNameless || !isOptional)
                    {
                        var style = (isNameless ? "command-param-nameless " : string.Empty) + (!isOptional ? "command-param-required" : string.Empty);
                        style = style.Trim();
                        var title = (isNameless ? "Nameless parameter: value should be provided after the command identifer without specifying parameter ID " : string.Empty) +
                                    (!isOptional ? " Required parameter: parameter should always be specified" : string.Empty);
                        title   = title.Trim();
                        paramId = $"<span class=\"{style}\" title=\"{title}\">{paramId}</span>";
                    }

                    var typeName = Beautifier.BeautifyType(parameter.FieldType);

                    var doc      = default(XmlDocumentComment);
                    var baseType = Type;
                    while (baseType != null && doc is null)
                    {
                        var key = baseType.FullName != null && baseType.FullName.Contains("[") ? baseType.FullName.GetBefore("[") : baseType.FullName;
                        doc      = commentLookup[key].FirstOrDefault(x => x.MemberName == parameter.Name || x.MemberName.StartsWith(parameter.Name + "`"));
                        baseType = baseType.BaseType;
                    }
                    var descr = doc?.Summary ?? string.Empty;
                    mb.Append($"{paramId} | {typeName} | {descr}\n");
                }
                mb.Append("\n</div>\n\n");
            }
            // -----------------------------------------------

            var example = commentLookup[Type.FullName].FirstOrDefault(x => x.MemberType == MemberType.Type)?.Example;

            if (!string.IsNullOrWhiteSpace(example))
            {
                mb.Header(4, "Example");
                mb.Code(example);
                mb.AppendLine();
            }

            return(mb.ToString());
        }
        public override string ToString()
        {
            var mb = new MarkdownBuilder();

            var typeCategory = type.IsClass ? " Class" : type.IsInterface ? " Interface" : string.Empty;

            mb.HeaderWithCode(2, Beautifier.BeautifyType(type, false) + typeCategory);
            mb.AppendLine();
            mb.AppendLine($"Namespace: {type.Namespace}");
            mb.AppendLine();
            mb.AppendLine($"Assembly: {type.Assembly.ManifestModule.Name}");
            mb.AppendLine();

            var summary = commentLookup[type.FullName].FirstOrDefault(x => x.MemberType == MemberType.Type)?.Summary ?? "";

            if (summary != "")
            {
                mb.AppendLine(summary);
                mb.AppendLine();
            }

            var sb = new StringBuilder();

            var isStatic = type.IsAbstract && type.IsSealed;
            var @sealed  = !type.IsAbstract && type.IsSealed ? "sealed " : "";
            var stat     = isStatic ? "static " : "";
            var abst     = (type.IsAbstract && !type.IsInterface && !type.IsSealed) ? "abstract " : "";
            var classOrStructOrEnumOrInterface = type.IsInterface ? "interface" : type.IsEnum ? "enum" : type.IsValueType ? "struct" : "class";

            sb.AppendLine($"public {stat}{@sealed}{abst}{classOrStructOrEnumOrInterface} {Beautifier.BeautifyType(type, true)}");
            var impl = string.Join(", ", new[] { type.BaseType }.Concat(type.GetInterfaces()).Where(x => x != null && x != typeof(object) && x != typeof(ValueType)).Select(x => Beautifier.BeautifyType(x)));

            if (impl != "")
            {
                sb.AppendLine("    : " + impl);
            }

            mb.Code("csharp", sb.ToString());

            var typeParameters = commentLookup[type.FullName].FirstOrDefault(x => x.MemberType == MemberType.Type)?.TypeParameters;

            if (typeParameters.Count > 0)
            {
                mb.Header(3, "Type Parameters");
                mb.AppendLine();
                mb.Table(new[] { "Name", "Summary" }, typeParameters.Select(x => new[] { x.Key, x.Value }));
            }

            mb.AppendLine();

            if (type.IsEnum)
            {
                var underlyingEnumType = Enum.GetUnderlyingType(type);

                var enums = Enum.GetNames(type)
                            .Select(x => new { Name = x, Value = (Convert.ChangeType(Enum.Parse(type, x), underlyingEnumType)) })
                            .OrderBy(x => x.Value)
                            .ToArray();

                BuildTable(mb, "Enum", enums, commentLookup[type.FullName], x => x.Value.ToString(), x => x.Name, x => x.Name);
            }
            else
            {
                BuildTable(mb, "Constructors", GetConstructors(), commentLookup[type.FullName], x => Beautifier.BeautifyType(x.DeclaringType), x => "#ctor", x => Beautifier.ToMarkdownConstructorInfo(x));
                BuildTable(mb, "Fields", GetFields(), commentLookup[type.FullName], x => Beautifier.BeautifyType(x.FieldType), x => x.Name, x => x.Name);
                BuildTable(mb, "Properties", GetProperties(), commentLookup[type.FullName], x => Beautifier.BeautifyType(x.PropertyType), x => x.Name, x => x.Name);
                BuildTable(mb, "Events", GetEvents(), commentLookup[type.FullName], x => Beautifier.BeautifyType(x.EventHandlerType), x => x.Name, x => x.Name);
                BuildTable(mb, "Methods", GetMethods(), commentLookup[type.FullName], x => Beautifier.BeautifyType(x.ReturnType), x => x.Name, x => Beautifier.ToMarkdownMethodInfoWithoutParamNames(x));
                BuildTable(mb, "Static Fields", GetStaticFields(), commentLookup[type.FullName], x => Beautifier.BeautifyType(x.FieldType), x => x.Name, x => x.Name);
                BuildTable(mb, "Static Properties", GetStaticProperties(), commentLookup[type.FullName], x => Beautifier.BeautifyType(x.PropertyType), x => x.Name, x => x.Name);
                BuildTable(mb, "Static Methods", GetStaticMethods(), commentLookup[type.FullName], x => Beautifier.BeautifyType(x.ReturnType), x => x.Name, x => Beautifier.ToMarkdownMethodInfo(x));
                BuildTable(mb, "Static Events", GetStaticEvents(), commentLookup[type.FullName], x => Beautifier.BeautifyType(x.EventHandlerType), x => x.Name, x => x.Name);
            }

            return(mb.ToString());
        }
        public string BuildMethodPage(MethodInfo methodInfo)
        {
            var mb = new MarkdownBuilder();

            mb.HeaderWithCode(2, $"{Beautifier.BeautifyType(type)}.{Beautifier.ToMarkdownMethodInfoWithoutParamNames(methodInfo, true)} Method");
            mb.AppendLine();
            mb.AppendLine($"Namespace: {type.Namespace}");
            mb.AppendLine();
            mb.AppendLine($"Assembly: {type.Assembly.ManifestModule.Name}");
            mb.AppendLine();

            var comment = commentLookup[type.FullName].FirstOrDefault(x => x.MemberName == methodInfo.Name || x.MemberName.StartsWith(methodInfo.Name + "`"));

            var summary = comment?.Summary ?? string.Empty;

            if (summary != string.Empty)
            {
                mb.AppendLine(summary);
                mb.AppendLine();
            }

            var sb         = new StringBuilder();
            var stat       = methodInfo.IsStatic ? "static " : "";
            var abst       = methodInfo.IsAbstract ? "abstract " : "";
            var returnType = Beautifier.BeautifyType(methodInfo.ReturnType);

            sb.Append($"public {stat}{abst}{returnType} {Beautifier.ToMarkdownMethodInfo(methodInfo, true)}");
            mb.Code("csharp", sb.ToString());

            mb.AppendLine();

            if (comment.TypeParameters.Count > 0)
            {
                mb.Header(3, "Type Parameters");
                mb.AppendLine();
                foreach (var tp in comment.TypeParameters)
                {
                    mb.CodeQuote(tp.Key);
                    mb.AppendLine();
                    mb.AppendLine();
                    mb.AppendLine(tp.Value);
                }

                mb.AppendLine();
            }

            if (comment.Parameters.Count > 0)
            {
                mb.Header(3, "Parameters");
                mb.AppendLine();
                foreach (var parameter in comment.Parameters)
                {
                    mb.CodeQuote(parameter.Key);
                    mb.AppendLine();
                    mb.AppendLine();
                    mb.AppendLine(parameter.Value);
                }

                mb.AppendLine();
            }

            if (comment.Returns.Length > 0 && !comment.Returns.Equals("void"))
            {
                mb.Header(3, "Returns");
                mb.AppendLine();
                mb.CodeQuote(returnType);
                mb.AppendLine();
                mb.AppendLine();
                mb.AppendLine(comment.Returns);
            }

            return(mb.ToString());
        }
Beispiel #10
0
        // 0 = dll src path, 1 = dest root
        static void Main(string[] args)
        {
            // put dll & xml on same diretory.
            var    target         = "UniRx.dll"; // :)
            string dest           = "md";
            string namespaceMatch = string.Empty;

            if (args.Length == 1)
            {
                target = args[0];
            }
            else if (args.Length == 2)
            {
                target = args[0];
                dest   = args[1];
            }
            else if (args.Length == 3)
            {
                target         = args[0];
                dest           = args[1];
                namespaceMatch = args[2];
            }

            var types = new List <MarkdownableType>();

            if (target.EndsWith(".dll"))
            {
                types.AddRange(MarkdownGenerator.Load(target, namespaceMatch).Where(x => x.Name.EndsWith("Extensions")));
            }
            else
            {
                //assume directory:
                var assemblies = Directory.GetFiles(target, namespaceMatch);
                foreach (var assembly in assemblies)
                {
                    if (!assembly.EndsWith(".Tests.dll"))
                    {
                        types.AddRange(MarkdownGenerator.Load(assembly, "").Where(x => x.Name.EndsWith("Extensions")));
                    }
                }
            }

            // Home Markdown Builder
            var homeBuilder = new MarkdownBuilder();

            homeBuilder.Header(1, "Extension Method Library");
            homeBuilder.AppendLine();

            foreach (var g in types.GroupBy(x => x.Namespace).OrderBy(x => x.Key))
            {
                if (!Directory.Exists(dest))
                {
                    Directory.CreateDirectory(dest);
                }

                homeBuilder.HeaderWithLink(2, g.Key, g.Key);
                homeBuilder.AppendLine();

                var sb = new StringBuilder();
                foreach (var item in g.OrderBy(x => x.Name))
                {
                    homeBuilder.ListLink(MarkdownBuilder.MarkdownCodeQuote(item.BeautifyName), g.Key + "#" + item.BeautifyName.Replace("<", "").Replace(">", "").Replace(",", "").Replace(" ", "-").ToLower());

                    sb.Append(item.ToString());
                }

                File.WriteAllText(Path.Combine(dest, g.Key + ".md"), sb.ToString());
                homeBuilder.AppendLine();
            }

            // Gen Home
            File.WriteAllText(Path.Combine(dest, "Home.md"), homeBuilder.ToString());
        }