private void ParseGenericParameters(AssemblyComponent com, ref string nameString)
        {
            Match genericParams = Regex.Match(nameString, "(`+[0-9])");

            if (genericParams.Success)
            {
                int    genericCount = 0;
                string generic      = "";

                if (int.TryParse(genericParams.Value.Replace("`", ""), out genericCount))
                {
                    if (genericCount > 1)
                    {
                        for (int i = 0; i < genericCount; i++)
                        {
                            com.GenericParameters.Add(new ComponentParameter()
                            {
                                Name = $"T{i + 1}",
                            });
                        }
                    }
                    else
                    {
                        com.GenericParameters.Add(new ComponentParameter()
                        {
                            Name = "T"
                        });
                    }
                }

                nameString = nameString.Replace(genericParams.Value, generic);
            }
        }
예제 #2
0
        private string ParseSummaryText(AssemblyComponent assembly, string innerXml)
        {
            string result   = innerXml;
            Match  xmlMatch = Regex.Match(result, @"(<.*?/>)|(<.*?>\S*</.*?>)");

            while (xmlMatch.Success)
            {
                XmlDocument inlineDoc = new XmlDocument();
                inlineDoc.LoadXml(xmlMatch.Value);

                foreach (XmlNode child in inlineDoc.ChildNodes)
                {
                    foreach (XmlAttribute att in child.Attributes)
                    {
                        string attName = att.Name.ToLower();
                        switch (attName)
                        {
                        case "cref":
                            AssemblyComponent com = _nameParser.Parse(assembly, att.Value);
                            result = result.Replace(xmlMatch.Value, com.QualifiedName);
                            break;
                        }
                    }
                }

                xmlMatch = xmlMatch.NextMatch();
            }

            return(result);
        }
예제 #3
0
        private AssemblyComponent ParseAssembly(ref string xml)
        {
            XmlDocument xmlDoc = new XmlDocument();

            xmlDoc.LoadXml(xml);

            AssemblyComponent assembly = new AssemblyComponent(ComponentType.Assembly);
            XmlNode           root     = xmlDoc["doc"];

            foreach (XmlNode node in root.ChildNodes)
            {
                switch (node.Name.ToLower())
                {
                case "assembly":
                    ParseAssemblyNode(assembly, node);
                    break;

                case "members":
                    ParseMembers(assembly, node);
                    break;
                }
            }

            return(assembly);
        }
        private void ParseIndexerParameters(AssemblyComponent com, ref string nameString)
        {
            Match indexerParams = Regex.Match(nameString, @"\[(.*?)\]");

            if (indexerParams.Success)
            {
                nameString = nameString.Replace(indexerParams.Value, "");
            }
        }
예제 #5
0
 private void ParseAssemblyNode(AssemblyComponent assembly, XmlNode assemblyNode)
 {
     foreach (XmlNode node in assemblyNode.ChildNodes)
     {
         switch (node.Name.ToLower())
         {
         case "name":
             assembly.ShortName = node.InnerText;
             break;
         }
     }
 }
예제 #6
0
 private void ParseSummary(AssemblyComponent assembly, AssemblyComponent component, XmlNode node)
 {
     foreach (XmlNode child in node.ChildNodes)
     {
         string nName = child.Name.ToLower();
         switch (nName)
         {
         case "summary":
             component.Summary = ParseSummaryText(assembly, child.InnerXml);
             break;
         }
     }
 }
예제 #7
0
        private void GenerateIndexPage(AssemblyComponent component, StreamWriter writer, int depth, string path)
        {
            if (component.Parent != null && component.ComponentType == ComponentType.Namespace)
            {
                string ns = component.ShortName;

                // Get full namespace by travelling backup the tree.
                AssemblyComponent p = component.Parent;
                while (p != null && p.ComponentType == ComponentType.Namespace)
                {
                    ns = $"{p.ShortName}.{ns}";
                    p  = p.Parent;
                }

                depth = 1;
                writer.Write("  " + Environment.NewLine);
                writer.Write($"* {ns}");
            }
            else
            {
                if (!string.IsNullOrEmpty(path) && component.ComponentType == ComponentType.Type)
                {
                    string indent = "";
                    for (int i = 0; i < depth - 1; i++)
                    {
                        indent += "    ";
                    }
                    indent += "* ";

                    writer.Write("  " + Environment.NewLine);
                    string fn = SanitizePath($"{path}/{component.GenericName}");
                    writer.Write($"{indent} [{component.Definition}]({fn}.md)");
                    GenerateTypePage(path, component);
                }

                depth++;
            }

            List <AssemblyComponent> children = component.Children.Values.ToList();

            children.Sort(_namespaceComparer);

            foreach (AssemblyComponent child in children)
            {
                GenerateIndexPage(child, writer, depth + 1, $"{path}/{component.GenericName}");
            }
        }
        private void ParseMethodParameters(AssemblyComponent com, ref string nameString)
        {
            Match methodParams = Regex.Match(nameString, @"\((.*?)\)");

            if (methodParams.Success)
            {
                nameString = nameString.Replace(methodParams.Value, "");
                string[] parameters = methodParams.Value.Replace("(", "").Replace(")", "").Split(",");
                for (int i = 0; i < parameters.Length; i++)
                {
                    com.InputParameters.Add(new ComponentParameter()
                    {
                        Name = parameters[i],
                    });
                }
            }
        }
예제 #9
0
 /// <summary>
 /// Gets a child component with the specified name. If the child does not exist, it will be created.
 /// </summary>
 /// <param name="childName">The name of the child component to be retrieved.</param>
 /// <returns>A <see cref="AssemblyComponent"/>.</returns>
 public AssemblyComponent this[string childName]
 {
     get
     {
         if (Children.TryGetValue(childName, out AssemblyComponent child))
         {
             return(child);
         }
         else
         {
             child           = new AssemblyComponent(ComponentType.Namespace);
             child.ShortName = childName;
             child.Parent    = this;
             Children.Add(childName, child);
             return(child);
         }
     }
 }
예제 #10
0
        /// <summary>
        /// Generates Markdown file from Visual Studio XML documentation.
        /// </summary>
        /// <param name="path">The path to store the markdown files.</param>
        /// <param name="xml">The xml documentation string.</param>
        /// <returns></returns>
        public void ToMarkdown(string path, string xml)
        {
            AssemblyComponent assembly = ParseAssembly(ref xml);

            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            using (FileStream stream = new FileStream($"{path}/{assembly.ShortName}.md", FileMode.Create, FileAccess.Write))
            {
                using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8))
                {
                    writer.Write($"# {assembly.ShortName}");
                    GenerateIndexPage(assembly, writer, 0, "");
                }
            }
        }
예제 #11
0
        private void GenerateTypePage(string path, AssemblyComponent typeComponent)
        {
            path = SanitizePath(path);
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            string fn = SanitizePath(typeComponent.GenericName);

            using (FileStream stream = new FileStream($"{path}/{fn}.md", FileMode.Create, FileAccess.Write))
            {
                using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8))
                {
                    GenerateTypeIndex(typeComponent, writer, 0, path);
                }
            }
        }
예제 #12
0
        private void ParseMembers(AssemblyComponent assembly, XmlNode membersNode)
        {
            foreach (XmlNode node in membersNode.ChildNodes)
            {
                if (node.Name == "#comment")
                {
                    Console.WriteLine("Documentation warning: " + node.InnerText);
                    continue;
                }

                // Parts: 0 = member type, 1 = namespace and name.
                AssemblyComponent com = _nameParser.Parse(assembly, node.Attributes["name"].Value);
                if (com == null)
                {
                    continue;
                }

                ParseSummary(assembly, com, node);
            }
        }
예제 #13
0
        private void GenerateTypeIndex(AssemblyComponent component, StreamWriter writer, int depth, string path)
        {
            if (!string.IsNullOrEmpty(path))
            {
                string indent = "";

                if (depth > 0)
                {
                    for (int i = 0; i < depth - 1; i++)
                    {
                        indent += "    ";
                    }
                    indent += "* ";
                }

                writer.Write("  " + Environment.NewLine);
                string fn = SanitizePath($"{path}/{component.ShortName}");

                if (depth > 0)
                {
                    writer.Write($"{indent} [{component.Definition}]({fn}.md)");
                }
                else
                {
                    writer.WriteLine($"# {component.QualifiedName}");
                    writer.WriteLine($"{component.Summary}");
                }
            }

            List <AssemblyComponent> children = component.Children.Values.ToList();

            children.Sort(_namespaceComparer);

            foreach (AssemblyComponent child in children)
            {
                GenerateTypeIndex(child, writer, depth + 1, $"{path}/{component.ShortName}");
            }
        }
예제 #14
0
        internal AssemblyComponent Parse(AssemblyComponent assembly, string nameString)
        {
            AssemblyComponent com = new AssemblyComponent(ComponentType.Namespace);

            ParseGenericParameters(com, ref nameString);
            ParseMethodParameters(com, ref nameString);
            ParseIndexerParameters(com, ref nameString);

            string[] nameParts  = nameString.Split(":");
            string[] tnParts    = nameParts[1].Split("~");
            string[] nsParts    = tnParts[0].Split(".");
            int      typeNameID = nsParts.Length - 1;
            string   returnType = tnParts.Length > 1 ? tnParts[1] : "";

            int i = 0;

            if (nsParts[0] == assembly.ShortName)
            {
                i++;
            }

            // Add or locate namespace components
            AssemblyComponent parent = assembly;

            for (; i < typeNameID; i++)
            {
                AssemblyComponent newParent = parent[nsParts[i]];
                if (parent != assembly)
                {
                    newParent.ParentNamespace = parent.ParentNamespace != null ? $"{parent.ParentNamespace}.{parent.ShortName}" : parent.ShortName;
                }

                parent = newParent;
            }

            if (parent.ComponentType == ComponentType.OperatorMethod)
            {
                return(null);
            }

            com.ShortName       = nsParts[typeNameID];
            com.Parent          = parent;
            com.ReturnType      = returnType;
            com.ParentNamespace = $"{parent.ParentNamespace}.{parent.ShortName}";

            switch (nameParts[0])
            {
            case "F":     // Field
                parent.ComponentType = ComponentType.Type;
                com.ComponentType    = ComponentType.Field;
                break;

            case "T":     // Type:
                com.ComponentType = ComponentType.Type;
                break;

            case "M":     // Method
                parent.ComponentType = ComponentType.Type;
                com.ComponentType    = ComponentType.Method;
                break;

            case "P":     // Property
                parent.ComponentType = ComponentType.Type;
                if (com.InputParameters.Count == 0)
                {
                    com.ComponentType = ComponentType.Property;
                }
                else
                {
                    com.ComponentType = ComponentType.IndexerProperty;
                }
                break;

            case "E":     // Event
                parent.ComponentType = ComponentType.Type;
                com.ComponentType    = ComponentType.Event;
                break;
            }

            // TODO improve this. Do not create a new component
            if (!parent.Children.ContainsKey(com.Definition))
            {
                parent.Children.Add(com.Definition, com);
            }

            return(com);
        }