/specificator/performer.cs
C# | 472 lines | 412 code | 49 blank | 11 comment | 74 complexity | d7ac6363ba526f2140fa7f74fb6b5f98 MD5 | raw file
- using jeyjen.extension;
- using Mono.Cecil;
- using Newtonsoft.Json.Linq;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Text;
- using System.Xml.Linq;
- namespace specificator
- {
- public class performer
- {
- Dictionary<string, details> _methods;
- Dictionary<string, details> _classes;
- Dictionary<string, details> _properties;
- Dictionary<string, JObject> _definitions;
- private string _name;
- public performer()
- {
- _methods = new Dictionary<string, details>();
- _classes = new Dictionary<string, details>();
- _properties = new Dictionary<string, details>();
- _definitions = new Dictionary<string, JObject>();
- }
- public string name
- {
- get
- {
- return _name;
- }
- }
- public string swagger(string path, string version)
- {
- if (!File.Exists(path))
- throw new Exception("assembly does not found");
- var file = Path.GetFileNameWithoutExtension(path);
- var xml = Path.Combine(Path.GetDirectoryName(path), "{0}.xml".format(file));
- if (File.Exists(xml))
- parse_xml_doc(xml);
- return prepare_specification(path, version);
- }
-
- private void parse_xml_doc(string path)
- {
- var doc = XDocument.Parse(File.ReadAllText(path));
- var ms = doc.Element("doc")
- .Element("members")
- .Elements("member");
- foreach (var m in ms)
- {
- var d = new details();
- var summary = m.Element("summary");
- if (!summary.is_null())
- d.summary = summary.Value.Trim();
- var see = m.Element("see");
- if (!see.is_null())
- {
- var href = see.Attribute("href");
- if (!href.is_null())
- {
- d.href = href.Value.Trim();
- }
- }
- var pars = m.Elements("param");
- foreach (var p in pars)
- {
- var n = p.Attribute("name");
- if (!n.is_null())
- {
- d.members.Add(n.Value.Trim(), p.Value.Trim());
- }
- }
- var returns = m.Element("returns");
- if (!returns.is_null())
- {
- d.returns = returns.Value.Trim();
- }
- var name = m.Attribute("name").Value.Trim();
- if (name.StartsWith("M:"))
- {
- var idx = name.IndexOf('(');
- if (idx >= 0)
- {
- name = name.Substring(2, idx - 2);
- }
-
- var ps = name.Split('.');
- _methods.Add("{0}.{1}".format(ps[ps.Length - 2], ps[ps.Length - 1]), d);
- }
- else if (name.StartsWith("T:"))
- {
- name = name.Substring(2);
-
- _classes.Add(name, d);
- }
- else if (name.StartsWith("P:"))
- {
- name = name.Substring(2);
- var ps = name.Split('.');
- _properties.Add(name, d);
- }
- }
- }
- private string prepare_specification(string assembly, string version)
- {
- var name = "";
- var spec = new JObject();
- spec.Add("swagger", "2.0");
- spec.Add("host", "host.com");
- spec.Add("schemes", new JArray("http", "https"));
- var types = AssemblyDefinition
- .ReadAssembly(assembly)
- .MainModule
- .Types;
- var info = new JObject();
- spec.Add("info", info);
- info.Add("version", version);
- foreach (var t in types)
- {
- if (!t.BaseType.is_null())
- {
- if (t.BaseType.Name.is_equals("mq_node"))
- {
- name = t.Name;
- _name = name;
- var desc = "";
- if (_classes.ContainsKey(t.FullName))
- {
- desc = _classes[t.FullName].summary;
- }
- info.Add("description", desc);
- info.Add("title", name);
- break;
- }
- }
- }
- spec.Add("basePath", "/{0}".format(name));
- var tags = new List<JObject>();
- var paths = new Dictionary<string, JObject>();
- foreach (var t in types)
- {
- // определение контейнера
- if (t.BaseType.is_null())
- continue;
- if (!t.BaseType.Name.Contains("container`"))
- continue;
- var container_name = t.Name;
- if (container_name.is_equals("index"))
- container_name = "";
- var tag = new JObject();
- tag.Add("name", container_name);
- if (_classes.ContainsKey(t.FullName))
- {
- var d = _classes[t.FullName];
- tag.Add("description", d.summary);
- if (!d.href.is_null_or_empty())
- {
- var ext_doc = new JObject();
- ext_doc.Add("description", "детальнее");
- ext_doc.Add("url", d.href);
- tag.Add("externalDocs", ext_doc);
- }
- }
- tags.Add(tag);
- // опрделение операций
- foreach (var method in t.Methods.Where((_) => { return _.IsPublic && !_.IsStatic && !_.IsConstructor; }))
- {
- if (method.Name.is_equals("ToString")
- || method.Name.is_equals("Equals")
- || method.Name.is_equals("GetHashCode")
- || method.Name.is_equals("GetType"))
- continue;
- var operation_name = method.Name.ToLower();
- var sb = new StringBuilder();
- if (!container_name.is_null_or_empty())
- sb.AppendFormat("/{0}", container_name);
- sb.AppendFormat("/{0}", operation_name);
- var path = sb.ToString();
- var operation_id = path.Replace('/', '_')
- .Substring(1);
- var summary = "";
- details md = new details();
- var key = "{0}.{1}".format(t.Name, method.Name);
- if (_methods.ContainsKey(key))
- {
- md = _methods[key];
- summary = md.summary;
- }
- var parameters = new JArray();
- //var produces = new JArray("multipart/form-data");
- //var consumes = new JArray("multipart/form-data");
- var parameter = new JObject();
- parameters.Add(parameter);
- parameter.Add("in", "body");
- parameter.Add("name", "body");
- var schema = new JObject();
- parameter.Add("schema", schema);
-
- var properties = new JObject();
- schema.Add("type", "object");
- schema.Add("properties", properties);
- var required = new JArray();
-
- // required arguments
- foreach (var p in method.Parameters.OrderBy(_ => { return _.Name; }) )
- {
- if (p.IsOptional)
- continue;
- required.Add(p.Name);
- var pd = define_equals_type(p.ParameterType);
- if (md.members.ContainsKey(p.Name))
- pd.Add("description", md.members[p.Name]);
- properties.Add(p.Name, pd);
- }
- if(required.Count > 0)
- schema.Add("required", required);
- // optional arguments
- foreach (var p in method.Parameters.OrderBy(_ => { return _.Name; }))
- {
- if (!p.IsOptional)
- continue;
- var pd = define_equals_type(p.ParameterType);
- if (md.members.ContainsKey(p.Name))
- pd.Add("description", md.members[p.Name]);
- properties.Add(p.Name, pd);
- }
- var prefix = new JObject();
- prefix.Add("name", "mq_prefix");
- prefix.Add("in", "header");
- prefix.Add("required", false);
- prefix.Add("type", "string");
- var v = new JArray() {"_dev", "common", "test.even", "test.odd", "preprod" };
- prefix.Add("enum", v);
- prefix.Add("default", "");
- prefix.Add("description", "префикс контура");
- parameters.Add(prefix);
- var mq_id = new JObject();
- mq_id.Add("name", "mq_id");
- mq_id.Add("in", "header");
- mq_id.Add("required", false);
- mq_id.Add("type", "string");
- parameters.Add(mq_id);
- var r200 = new JObject();
- var r500 = new JObject();
- var responses = new JObject();
- responses.Add("200", r200);
- responses.Add("500", r500);
- if (md.returns.is_null_or_empty())
- r200.Add("description", "success");
- else
- r200.Add("description", md.returns);
- var r_200_schema = new JObject();
- r200.Add("schema", r_200_schema);
- r_200_schema.Add("type", "object");
- var r_200_properties = new JObject();
- r_200_schema.Add("properties", r_200_properties);
- // добавить result
- var ttt = define_result_type(method.ReturnType);
-
- r_200_properties.Add("result", ttt);
-
- r500.Add("description", "internal error");
- var r_500_schema = new JObject();
- r500.Add("schema", r_500_schema);
- r_500_schema.Add("type", "object");
- var r_500_properties = new JObject();
- r_500_schema.Add("properties", r_500_properties);
- var property500 = new JObject();
- r_500_properties.Add("message", property500);
- property500.Add("type", "string");
- property500.Add("description", "сообщение об ошибке");
- var post = new JObject();
- post.Add("tags", new JArray(container_name));
- post.Add("summary", summary);
- //post.Add("description", summary);
- post.Add("operationId", operation_id);
- //post.Add("produces", produces);
- //post.Add("consumes", consumes);
- post.Add("parameters", parameters);
- post.Add("responses", responses);
- var path_content = new JObject();
- path_content.Add("post", post);
- paths.Add(path, path_content);
- }
- }
- tags = tags
- .OrderBy((t) => { return t.Value<string>("name"); })
- .ToList();
- spec.Add("tags", new JArray(tags));
-
- var ps = new JObject();
- var pks = paths.Keys.OrderBy((k) => { return k; });
- foreach (var p in pks)
- ps.Add(p, paths[p]);
- spec.Add("paths", ps);
- var definitions = new JObject();
- foreach (var i in _definitions)
- {
- definitions.Add(i.Key, i.Value);
- }
- spec.Add("definitions", definitions);
- return spec.ToString();
- }
- private JObject define_result_type(TypeReference t)
- {
- if (t.FullName.Contains("System.Threading.Tasks.Task`"))
- {
- var prop = t.GetType().GetProperty("GenericArguments");
- var d = (IList)prop.GetValue(t);
- return define_equals_type((TypeReference)d[0]);
- }
- else if (t.FullName.is_equals("System.Void"))
- {
- return new JObject();
- }
- else if (t.FullName.is_equals("System.Threading.Tasks.Task"))
- {
- return new JObject();
- }
- return define_equals_type(t);
- }
- private JObject define_equals_type(TypeReference t)
- {
- var res = new JObject();
- if (t.FullName.StartsWith("System.Collections.Generic.List`")
- || t.FullName.StartsWith("System.Collections.Generic.HashSet`"))
- {
- var prop = t.GetType().GetProperty("GenericArguments");
- var d = (IList)prop.GetValue(t);
- var arg_type = (TypeReference)d[0];
- res.Add("items", define_equals_type(arg_type));
- res.Add("type", "array");
- }
- else if (t.FullName.StartsWith("System.Collections.Generic.Dictionary`"))
- {
- res.Add("type", "object");
- }
- else if (t.FullName.is_equals("Newtonsoft.Json.Linq.JObject"))
- {
- res.Add("type", "object");
- }
- else if (t.FullName.is_equals("Newtonsoft.Json.Linq.JArray"))
- {
- res.Add("type", "array");
- var o = new JObject();
- res.Add("items", o);
- o.Add("type", "object");
- }
- else if (t.IsArray)
- {
- var arg_type = t.GetElementType();
- res.Add("items", define_equals_type(arg_type));
- res.Add("type", "array");
- }
- else if (t.FullName.is_equals("System.String"))
- {
- res.Add("type", "string");
- }
- else if (t.FullName.Contains("System.SByte")
- || t.FullName.Contains("System.Byte")
- || t.FullName.Contains("System.Char")
- || t.FullName.Contains("System.Int16")
- || t.FullName.Contains("System.UInt16")
- || t.FullName.Contains("System.Int32")
- || t.FullName.Contains("System.UInt32")
- || t.FullName.Contains("System.Int64")
- || t.FullName.Contains("System.UInt64")
- )
- {
- res.Add("type", "integer");
- }
- else if (t.FullName.Contains("System.Boolean"))
- {
- res.Add("type", "boolean");
- }
- else if (t.FullName.Contains("System.Single")
- || t.FullName.Contains("System.Double")
- || t.FullName.Contains("System.Decimal"))
- {
- res.Add("type", "number");
- }
- else // object
- {
- if (!_definitions.ContainsKey(t.Name))
- {
- var def = new JObject();
- def.Add("type", "object");
- if (_classes.ContainsKey(t.FullName))
- {
- def.Add("description", _classes[t.FullName].summary);
- }
- var props = new JObject();
- def.Add("properties", props);
- var tmp_obj = (TypeDefinition)t;
- var ts = new List<TypeDefinition>();
- ts.Add(tmp_obj);
- while (!tmp_obj.BaseType.FullName.is_equals("System.Object"))
- {
- tmp_obj = (TypeDefinition)tmp_obj.BaseType;
- ts.Add(tmp_obj);
- }
- foreach (var obj in ts)
- {
- foreach (var i in obj.Properties)
- {
- var idx = i.FullName.IndexOf(' ');
- var k = i.FullName
- .Substring(idx + 1)
- .Replace("::", ".")
- .Replace("()", "");
- var ed = define_equals_type(i.PropertyType);
- var ttt = ed.Value<string>("type");
- if (!ttt.is_null()
- && _properties.ContainsKey(k))
- {
- ed.Add("description", _properties[k].summary);
- }
- props.Add(i.Name, ed);
- }
- }
- // отсортировать свойства
- _definitions.Add(t.Name, def);
- }
- res.Add("$ref", "#/definitions/{0}".format(t.Name));
- }
- return res;
- }
- }
- }