Example #1
0
 public ResourceNode(ResourceNode parent, string key, Type classType)
     : this()
 {
     Parent = parent;
     Key = key;
     Class = classType;
 }
Example #2
0
        public ExampleStore(string baseDirectory, ResourceNode resourceTree)
        {
            _Examples = new Dictionary<string, Example>();

            string[] filenames = Directory.GetFiles(baseDirectory, string.Concat("*.md"), SearchOption.AllDirectories);
            foreach (string filename in filenames)
            {
                ReadExamples(baseDirectory, filename, resourceTree);
            }

            Console.WriteLine(string.Concat("Read ", _Examples.Count, " examples from ", baseDirectory, "."));
        }
Example #3
0
        private void AddSchemas(ResourceNode node)
        {
            if (node.Method != null)
            {
                MethodDocumentationAttribute attribute = node.Method.GetCustomAttributes<MethodDocumentationAttribute>().FirstOrDefault();

                if (attribute != null)
                {
                    AddSchemas(attribute.RequestTypes);
                    AddSchemas(attribute.ResponseTypes);
                }
            }
            foreach (ResourceNode child in node.Children.Values)
            {
                AddSchemas(child);
            }
        }
Example #4
0
        public ResourceNode Find(string className, string methodName)
        {
            ResourceNode node = null;

            if (Class != null && Class.Name.Equals(className) && Method != null && Method.Name.Equals(methodName))
            {
                node = this;
            }
            else
            {
                foreach (ResourceNode child in Children.Values)
                {
                    node = child.Find(className, methodName);
                    if (node != null)
                    {
                        break;
                    }
                }
            }
            return(node);
        }
Example #5
0
        private static ResourceNode CreateResourceNode(ResourceNode parent, string path, Type classType)
        {
            string[] parts = path.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);

            if (parts.Length > 0)
            {
                if (parent.Parent == null && IsHTTPVerb(parts[0]))
                {
                    parent = parent.Children[API_ENTRYPOINT];
                }

                for (int i = 0; i < parts.Length; i++)
                {
                    ResourceNode child = null;

                    if (!parent.Children.TryGetValue(parts[i], out child))
                    {
                        child = new ResourceNode(parent, parts[i], classType);
                        parent.Children.Add(parts[i], child);
                    }
                    parent = child;
                }
            }
            else
            {
                // handle API entrypoint
                if (parent.Children.ContainsKey(API_ENTRYPOINT))
                {
                    throw new NotSupportedException("API entrypoint already exists");
                }
                ResourceNode apiEntryPoint = new ResourceNode(parent, API_ENTRYPOINT, classType);
                parent.Children.Add(API_ENTRYPOINT, apiEntryPoint);
                parent = apiEntryPoint;
            }

            return(parent);
        }
Example #6
0
        private string JsonToXml(Example currentExample, ResourceNode resourceTree, string json)
        {
            string xml = null;
            MethodInfo method = resourceTree.Find(currentExample.ClassName, currentExample.MethodName).Method;
            MethodDocumentationAttribute attribute = method.GetCustomAttributes<MethodDocumentationAttribute>().FirstOrDefault();

            if (attribute != null)
            {
                Type objectType = null;

                if (currentExample.ExampleType == TMessageType.Request)
                {
                    objectType = GetObjectType(attribute.RequestTypes, currentExample);
                }
                else
                {
                    objectType = GetObjectType(attribute.ResponseTypes, currentExample);
                }

                if (objectType != null)
                {
                    try
                    {
                        object deserialisedObject = JsonConvert.DeserializeObject(json, objectType);

                        Stream stream = new MemoryStream();
                        XmlSerializer serializer = new XmlSerializer(objectType);
                        XmlSerializerNamespaces xns = new XmlSerializerNamespaces();
                        xns.Add(string.Empty, string.Empty);
                        serializer.Serialize(stream, deserialisedObject, xns);

                        stream.Position = 0;
                        using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                        {
                            reader.ReadLine();  // skip <?xml version="1.0"?>
                            xml = reader.ReadToEnd().Replace("+json", "+xml");
                        }
                    }
                    catch (InvalidOperationException)
                    {
                        SerialisationLog.Warning(string.Concat("Failed to serialise XML example for ", currentExample.ClassName, ".", currentExample.MethodName));
                    }
                    catch (Exception ex)
                    {
                        if (ex is JsonReaderException || ex is JsonSerializationException)
                        {
                            SerialisationLog.Warning(string.Concat("Failed to deserialise JSON example for ", currentExample.ClassName, ".", currentExample.MethodName));
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
                else
                {
                    SerialisationLog.Warning(string.Concat("No ", currentExample.ExampleType.ToString().ToLower(), " type for ", currentExample.ClassName, ".", currentExample.MethodName));
                }
            }
            else
            {
                SerialisationLog.Warning(string.Concat("Could not convert JSON example to XML due to no method documentation for ", currentExample.ClassName, ".", currentExample.MethodName));
            }
            return xml;
        }
Example #7
0
        public void ReadExamples(string baseDirectory, string filename, ResourceNode resourceTree)
        {
            Example currentExample = null;
            StringBuilder currentExampleBody = null;
            TDataExchangeFormat currentExampleFormat = TDataExchangeFormat.None;
            bool inExample = false;
            string lastHeading = null;
            bool generateXml = true;

            foreach (string line in File.ReadLines(filename))
            {
                string trimmed = line.Trim();
                if (trimmed.StartsWith("#"))
                {
                    lastHeading = trimmed.Replace("#", "").Trim().Replace(" ", "-").ToLower();
                }
                else if (trimmed.StartsWith("[]: [!generateXml]"))
                {
                    generateXml = false;
                }
                if (trimmed.StartsWith("```"))
                {
                    if (currentExample != null)
                    {
                        string exampleFormat = trimmed.Substring("```".Length);
                        if (exampleFormat.Equals(TDataExchangeFormat.Json.ToString().ToLower()))
                        {
                            currentExampleFormat = TDataExchangeFormat.Json;
                            inExample = true;
                        }
                        else if (exampleFormat.Equals(FORM_EXAMPLE))
                        {
                            currentExampleFormat = TDataExchangeFormat.FormUrlEncoded;
                            inExample = true;
                        }
                        else if (inExample && exampleFormat.Length == 0)
                        {
                            if (currentExampleFormat == TDataExchangeFormat.FormUrlEncoded)
                            {
                                currentExample.Content.Add(currentExampleFormat, currentExampleBody.ToString());
                            }
                            else
                            {
                                currentExample.Content.Add(TDataExchangeFormat.Json, currentExampleBody.ToString());
                                if (generateXml)
                                    currentExample.Content.Add(TDataExchangeFormat.Xml, JsonToXml(currentExample, resourceTree, currentExampleBody.ToString()));
                            }
                            currentExample = null;
                            inExample = false;
                            generateXml = true;
                        }
                    }
                }
                else
                {
                    if (inExample)
                    {
                        if (line.Trim().Length > 0)
                        {
                            currentExampleBody.Append(line);// string.Concat(line, "\r\n"));
                        }
                    }
                    else
                    {
                        MatchCollection matches = EXAMPLE_NAME_REGEX.Matches(trimmed);
                        if (matches.Count == 1)
                        {
                            string fullExampleName = matches[0].Value;
                            string prefix = "[]: [";
                            string suffix = "]";
                            string withoutSquareBrackets = fullExampleName.Substring(prefix.Length, matches[0].Value.Length - prefix.Length - suffix.Length);
                            string[] parts = withoutSquareBrackets.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                            string className = parts[0];
                            string methodName = parts[1];
                            string mimeType = trimmed.Substring(fullExampleName.Length);
                            if (mimeType.Length > 0)
                            {
                                if (mimeType.StartsWith("[") && mimeType.EndsWith("]"))
                                {
                                    mimeType = mimeType.Substring(1, mimeType.Length - 2);
                                }
                                else
                                {
                                    SerialisationLog.Warning(string.Concat("Invalid mimetype on example tag: ", trimmed, " in ", filename));
                                    mimeType = "";
                                }
                            }

                            if (resourceTree.Find(className, methodName) != null)
                            {
                                TMessageType messageType = (TMessageType)Enum.Parse(typeof(TMessageType), parts[2]);
                                string exampleFilename = filename.Substring(baseDirectory.Length);
                                currentExample = new Example(exampleFilename, lastHeading, className, methodName, messageType, mimeType);
                                currentExampleBody = new StringBuilder();

                                string key = string.Concat(currentExample.ClassName, currentExample.MethodName, currentExample.ExampleType.ToString(), mimeType);
                                if (!_Examples.ContainsKey(key))
                                {
                                    _Examples.Add(key, currentExample);
                                }
                                else
                                {
                                    SerialisationLog.Error(string.Concat("An example already exists for ", currentExample.ClassName, ".", currentExample.MethodName, ".", currentExample.ExampleType.ToString(), "files: [", currentExample.DocFilename, ", ", _Examples[key].DocFilename, "]"));
                                }
                            }
                            else
                            {
                                SerialisationLog.Error(string.Concat("The method ", className, ".", methodName, " in ", filename, " does not exist"));
                            }
                        }
                    }
                }
            }
        }
Example #8
0
 public SchemaStore(ResourceNode resourceTree)
 {
     Schemas = new Dictionary <Type, Schema>();
     AddSchemas(resourceTree);
 }
Example #9
0
 private static void GenerateDocumentation(ResourceNode resourceTree, DocumentationHeaderSettings headerSettings, SchemaStore schemaStore, ExampleStore exampleStore, string outputFilename)
 {
     IDocumentationSerialiser serialiser = DocumentationSerialiserFactory.GetSerialiser(outputFilename);
     using (FileStream stream = new FileStream(outputFilename, FileMode.Create, FileAccess.Write))
     {
         StreamWriter streamWriter = new StreamWriter(stream);
         serialiser.Serialise(streamWriter, resourceTree, headerSettings, schemaStore, exampleStore);
         streamWriter.Flush();
     }
 }
Example #10
0
 public SchemaStore(ResourceNode resourceTree)
 {
     Schemas = new Dictionary<Type, Schema>();
     AddSchemas(resourceTree);
 }
Example #11
0
 public ResourceNode(ResourceNode parent, string key, Type classType) : this()
 {
     Parent = parent;
     Key    = key;
     Class  = classType;
 }
Example #12
0
        public static void Main(string[] args)
        {
            if (args.Length == 0 || args.Any(a => a.Equals("-h") || a.Equals("--help")))
            {
                WriteHelp();
            }
            else
            {
                string path = null;

                for (int i = 0; i < args.Length - 1; i++)
                {
                    bool argument = true;
                    if (args[i].Equals("-p") || args[i].Equals("--path"))
                    {
                        path = args[i + 1];
                    }
                    else if (args[i].Equals("-r") || args[i].Equals("--ramlVersion"))
                    {
                        DocumentationSerialiserFactory.RAMLVersion = args[i + 1];
                    }
                    else
                    {
                        argument = false;
                    }
                    if (argument)
                    {
                        List <string> temp = args.ToList();
                        temp.RemoveRange(i, 2);
                        args = temp.ToArray();
                        i--;
                    }
                }


                if (path == null)
                {
                    path = FindAssemblyPath();
                }

                if (string.IsNullOrEmpty(path))
                {
                    Console.WriteLine("Could not find Device Server Executable. ");
                    Console.Out.Flush();
                }
                else
                {
                    Assembly assembly = null;
                    try
                    {
                        assembly = AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(path));
                    }
                    catch (Exception exception)
                    {
                        SerialisationLog.Error(string.Concat("Failed to load assembly at ", path, ": ", exception));
                    }

                    if (assembly != null)
                    {
                        ResourceNode resourceTree = null;
                        try
                        {
                            Console.WriteLine("Gathering resources from assembly...");
                            resourceTree = AssemblyReader.ReadAssembly(assembly);
                        }
                        catch (Exception exception)
                        {
                            SerialisationLog.Error(string.Concat("Failed to generate resource tree from assembly at ", path, ": ", exception));
                        }

                        if (resourceTree != null)
                        {
                            IConfigurationBuilder builder = new ConfigurationBuilder()
                                                            .SetBasePath(Directory.GetCurrentDirectory())
                                                            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                                                            .AddEnvironmentVariables();
                            //.AddCommandLine(args);

                            IConfigurationRoot          root           = builder.Build();
                            DocumentationHeaderSettings headerSettings = new DocumentationHeaderSettings();
                            root.GetSection("HeaderSettings").Bind(headerSettings);

                            SchemaStore  schemaStore  = new SchemaStore(resourceTree);
                            ExampleStore exampleStore = new ExampleStore(string.Concat(GetRootDirectory(), "/doc/"), resourceTree);

                            args = args.Where(a => !a.StartsWith("-")).ToArray();  // remove options
                            int numSuccess = 0;
                            for (int i = 0; i < args.Length; i++)
                            {
                                try
                                {
                                    Console.WriteLine(string.Concat("Generating documentation file: ", args[i]));
                                    GenerateDocumentation(resourceTree, headerSettings, schemaStore, exampleStore, args[i]);
                                    numSuccess++;
                                }
                                catch (Exception exception)
                                {
                                    SerialisationLog.Error(string.Concat("Failed to generate documentation for ", args[i], ": ", exception));
                                }
                            }

                            Console.WriteLine(string.Concat(numSuccess, "/", args.Length, " documentation files generated successfully."));
                            Console.WriteLine(string.Concat(SerialisationLog.Errors, " errors, ", SerialisationLog.Warnings, " warnings."));
                        }
                    }
                }
            }
            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }
Example #13
0
        public void ReadExamples(string baseDirectory, string filename, ResourceNode resourceTree)
        {
            Example             currentExample       = null;
            StringBuilder       currentExampleBody   = null;
            TDataExchangeFormat currentExampleFormat = TDataExchangeFormat.None;
            bool   inExample   = false;
            string lastHeading = null;
            bool   generateXml = true;

            foreach (string line in File.ReadLines(filename))
            {
                string trimmed = line.Trim();
                if (trimmed.StartsWith("#"))
                {
                    lastHeading = trimmed.Replace("#", "").Trim().Replace(" ", "-").ToLower();
                }
                else if (trimmed.StartsWith("[]: [!generateXml]"))
                {
                    generateXml = false;
                }
                if (trimmed.StartsWith("```"))
                {
                    if (currentExample != null)
                    {
                        string exampleFormat = trimmed.Substring("```".Length);
                        if (exampleFormat.Equals(TDataExchangeFormat.Json.ToString().ToLower()))
                        {
                            currentExampleFormat = TDataExchangeFormat.Json;
                            inExample            = true;
                        }
                        else if (exampleFormat.Equals(FORM_EXAMPLE))
                        {
                            currentExampleFormat = TDataExchangeFormat.FormUrlEncoded;
                            inExample            = true;
                        }
                        else if (inExample && exampleFormat.Length == 0)
                        {
                            if (currentExampleFormat == TDataExchangeFormat.FormUrlEncoded)
                            {
                                currentExample.Content.Add(currentExampleFormat, currentExampleBody.ToString());
                            }
                            else
                            {
                                currentExample.Content.Add(TDataExchangeFormat.Json, currentExampleBody.ToString());
                                if (generateXml)
                                {
                                    currentExample.Content.Add(TDataExchangeFormat.Xml, JsonToXml(currentExample, resourceTree, currentExampleBody.ToString()));
                                }
                            }
                            currentExample = null;
                            inExample      = false;
                            generateXml    = true;
                        }
                    }
                }
                else
                {
                    if (inExample)
                    {
                        if (line.Trim().Length > 0)
                        {
                            currentExampleBody.Append(line);// string.Concat(line, "\r\n"));
                        }
                    }
                    else
                    {
                        MatchCollection matches = EXAMPLE_NAME_REGEX.Matches(trimmed);
                        if (matches.Count == 1)
                        {
                            string   fullExampleName       = matches[0].Value;
                            string   prefix                = "[]: [";
                            string   suffix                = "]";
                            string   withoutSquareBrackets = fullExampleName.Substring(prefix.Length, matches[0].Value.Length - prefix.Length - suffix.Length);
                            string[] parts      = withoutSquareBrackets.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                            string   className  = parts[0];
                            string   methodName = parts[1];
                            string   mimeType   = trimmed.Substring(fullExampleName.Length);
                            if (mimeType.Length > 0)
                            {
                                if (mimeType.StartsWith("[") && mimeType.EndsWith("]"))
                                {
                                    mimeType = mimeType.Substring(1, mimeType.Length - 2);
                                }
                                else
                                {
                                    SerialisationLog.Warning(string.Concat("Invalid mimetype on example tag: ", trimmed, " in ", filename));
                                    mimeType = "";
                                }
                            }

                            if (resourceTree.Find(className, methodName) != null)
                            {
                                TMessageType messageType     = (TMessageType)Enum.Parse(typeof(TMessageType), parts[2]);
                                string       exampleFilename = filename.Substring(baseDirectory.Length);
                                currentExample     = new Example(exampleFilename, lastHeading, className, methodName, messageType, mimeType);
                                currentExampleBody = new StringBuilder();

                                string key = string.Concat(currentExample.ClassName, currentExample.MethodName, currentExample.ExampleType.ToString(), mimeType);
                                if (!_Examples.ContainsKey(key))
                                {
                                    _Examples.Add(key, currentExample);
                                }
                                else
                                {
                                    SerialisationLog.Error(string.Concat("An example already exists for ", currentExample.ClassName, ".", currentExample.MethodName, ".", currentExample.ExampleType.ToString(), "files: [", currentExample.DocFilename, ", ", _Examples[key].DocFilename, "]"));
                                }
                            }
                            else
                            {
                                SerialisationLog.Error(string.Concat("The method ", className, ".", methodName, " in ", filename, " does not exist"));
                            }
                        }
                    }
                }
            }
        }
Example #14
0
        private string JsonToXml(Example currentExample, ResourceNode resourceTree, string json)
        {
            string     xml    = null;
            MethodInfo method = resourceTree.Find(currentExample.ClassName, currentExample.MethodName).Method;
            MethodDocumentationAttribute attribute = method.GetCustomAttributes <MethodDocumentationAttribute>().FirstOrDefault();

            if (attribute != null)
            {
                Type objectType = null;

                if (currentExample.ExampleType == TMessageType.Request)
                {
                    objectType = GetObjectType(attribute.RequestTypes, currentExample);
                }
                else
                {
                    objectType = GetObjectType(attribute.ResponseTypes, currentExample);
                }

                if (objectType != null)
                {
                    try
                    {
                        object deserialisedObject = JsonConvert.DeserializeObject(json, objectType);

                        Stream                  stream     = new MemoryStream();
                        XmlSerializer           serializer = new XmlSerializer(objectType);
                        XmlSerializerNamespaces xns        = new XmlSerializerNamespaces();
                        xns.Add(string.Empty, string.Empty);
                        serializer.Serialize(stream, deserialisedObject, xns);

                        stream.Position = 0;
                        using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                        {
                            reader.ReadLine();  // skip <?xml version="1.0"?>
                            xml = reader.ReadToEnd().Replace("+json", "+xml");
                        }
                    }
                    catch (InvalidOperationException)
                    {
                        SerialisationLog.Warning(string.Concat("Failed to serialise XML example for ", currentExample.ClassName, ".", currentExample.MethodName));
                    }
                    catch (Exception ex)
                    {
                        if (ex is JsonReaderException || ex is JsonSerializationException)
                        {
                            SerialisationLog.Warning(string.Concat("Failed to deserialise JSON example for ", currentExample.ClassName, ".", currentExample.MethodName));
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
                else
                {
                    SerialisationLog.Warning(string.Concat("No ", currentExample.ExampleType.ToString().ToLower(), " type for ", currentExample.ClassName, ".", currentExample.MethodName));
                }
            }
            else
            {
                SerialisationLog.Warning(string.Concat("Could not convert JSON example to XML due to no method documentation for ", currentExample.ClassName, ".", currentExample.MethodName));
            }
            return(xml);
        }
Example #15
0
        public static ResourceNode ReadAssembly(Assembly assembly)
        {
            ResourceNode tree = new ResourceNode();

            Type[] types = assembly.GetTypes()
                           .Where(t => t.IsSubclassOf(typeof(ControllerBase)) && t.GetCustomAttribute <RouteAttribute>() != null)
                           .OrderBy(t => t.GetCustomAttribute <RouteAttribute>(), new RouteComparer())
                           .ToArray();

            foreach (Type classType in types)
            {
                object[] attributes    = classType.GetCustomAttributes(true);
                string   resourceRoute = classType.GetCustomAttribute <RouteAttribute>().Template;
                if (resourceRoute != null)
                {
                    MethodInfo[] methods = classType.GetMethods()
                                           .Where(m => m.GetCustomAttribute <HttpMethodAttribute>() != null)
                                           .OrderBy(m => m.GetCustomAttribute <HttpMethodAttribute>(), new MethodTemplateComparer())
                                           .ToArray();

                    ResourceNode classNode = CreateResourceNode(tree, resourceRoute, classType);

                    foreach (MethodInfo methodInfo in methods)
                    {
                        HttpMethodAttribute methodAttribute = methodInfo.GetCustomAttribute <HttpMethodAttribute>();
                        string httpMethod   = methodAttribute.HttpMethods.FirstOrDefault().ToLower();
                        string template     = null;
                        bool   rootTemplate = false;
                        if (methodAttribute.Template != null)
                        {
                            template = string.Concat(methodAttribute.Template, "/");
                            if (!template.StartsWith("/"))
                            {
                                template = string.Concat("/", template);
                            }
                            else if (template.StartsWith(resourceRoute))
                            {
                                template = template.Substring(resourceRoute.Length);
                            }
                            else
                            {
                                rootTemplate = true;
                            }
                        }
                        else
                        {
                            template = "/";
                        }

                        string fullPath = string.Concat(template, httpMethod);
                        if (!rootTemplate)
                        {
                            fullPath = string.Concat(resourceRoute, fullPath);
                        }

                        ResourceNode methodNode = CreateResourceNode(tree, fullPath, classType);
                        if (methodNode.Method != null)
                        {
                            SerialisationLog.Error(string.Concat("Multiple versions of ", methodNode.Class.Name, ".", methodNode.Method.Name, " exist"));
                        }
                        methodNode.Method = methodInfo;
                    }
                }
            }

            return(tree);
        }