PageRenderTime 64ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/specificator/performer.cs

https://bitbucket.org/jeyjen/specificator
C# | 472 lines | 412 code | 49 blank | 11 comment | 74 complexity | d7ac6363ba526f2140fa7f74fb6b5f98 MD5 | raw file
  1. using jeyjen.extension;
  2. using Mono.Cecil;
  3. using Newtonsoft.Json.Linq;
  4. using System;
  5. using System.Collections;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Xml.Linq;
  11. namespace specificator
  12. {
  13. public class performer
  14. {
  15. Dictionary<string, details> _methods;
  16. Dictionary<string, details> _classes;
  17. Dictionary<string, details> _properties;
  18. Dictionary<string, JObject> _definitions;
  19. private string _name;
  20. public performer()
  21. {
  22. _methods = new Dictionary<string, details>();
  23. _classes = new Dictionary<string, details>();
  24. _properties = new Dictionary<string, details>();
  25. _definitions = new Dictionary<string, JObject>();
  26. }
  27. public string name
  28. {
  29. get
  30. {
  31. return _name;
  32. }
  33. }
  34. public string swagger(string path, string version)
  35. {
  36. if (!File.Exists(path))
  37. throw new Exception("assembly does not found");
  38. var file = Path.GetFileNameWithoutExtension(path);
  39. var xml = Path.Combine(Path.GetDirectoryName(path), "{0}.xml".format(file));
  40. if (File.Exists(xml))
  41. parse_xml_doc(xml);
  42. return prepare_specification(path, version);
  43. }
  44. private void parse_xml_doc(string path)
  45. {
  46. var doc = XDocument.Parse(File.ReadAllText(path));
  47. var ms = doc.Element("doc")
  48. .Element("members")
  49. .Elements("member");
  50. foreach (var m in ms)
  51. {
  52. var d = new details();
  53. var summary = m.Element("summary");
  54. if (!summary.is_null())
  55. d.summary = summary.Value.Trim();
  56. var see = m.Element("see");
  57. if (!see.is_null())
  58. {
  59. var href = see.Attribute("href");
  60. if (!href.is_null())
  61. {
  62. d.href = href.Value.Trim();
  63. }
  64. }
  65. var pars = m.Elements("param");
  66. foreach (var p in pars)
  67. {
  68. var n = p.Attribute("name");
  69. if (!n.is_null())
  70. {
  71. d.members.Add(n.Value.Trim(), p.Value.Trim());
  72. }
  73. }
  74. var returns = m.Element("returns");
  75. if (!returns.is_null())
  76. {
  77. d.returns = returns.Value.Trim();
  78. }
  79. var name = m.Attribute("name").Value.Trim();
  80. if (name.StartsWith("M:"))
  81. {
  82. var idx = name.IndexOf('(');
  83. if (idx >= 0)
  84. {
  85. name = name.Substring(2, idx - 2);
  86. }
  87. var ps = name.Split('.');
  88. _methods.Add("{0}.{1}".format(ps[ps.Length - 2], ps[ps.Length - 1]), d);
  89. }
  90. else if (name.StartsWith("T:"))
  91. {
  92. name = name.Substring(2);
  93. _classes.Add(name, d);
  94. }
  95. else if (name.StartsWith("P:"))
  96. {
  97. name = name.Substring(2);
  98. var ps = name.Split('.');
  99. _properties.Add(name, d);
  100. }
  101. }
  102. }
  103. private string prepare_specification(string assembly, string version)
  104. {
  105. var name = "";
  106. var spec = new JObject();
  107. spec.Add("swagger", "2.0");
  108. spec.Add("host", "host.com");
  109. spec.Add("schemes", new JArray("http", "https"));
  110. var types = AssemblyDefinition
  111. .ReadAssembly(assembly)
  112. .MainModule
  113. .Types;
  114. var info = new JObject();
  115. spec.Add("info", info);
  116. info.Add("version", version);
  117. foreach (var t in types)
  118. {
  119. if (!t.BaseType.is_null())
  120. {
  121. if (t.BaseType.Name.is_equals("mq_node"))
  122. {
  123. name = t.Name;
  124. _name = name;
  125. var desc = "";
  126. if (_classes.ContainsKey(t.FullName))
  127. {
  128. desc = _classes[t.FullName].summary;
  129. }
  130. info.Add("description", desc);
  131. info.Add("title", name);
  132. break;
  133. }
  134. }
  135. }
  136. spec.Add("basePath", "/{0}".format(name));
  137. var tags = new List<JObject>();
  138. var paths = new Dictionary<string, JObject>();
  139. foreach (var t in types)
  140. {
  141. // определение контейнера
  142. if (t.BaseType.is_null())
  143. continue;
  144. if (!t.BaseType.Name.Contains("container`"))
  145. continue;
  146. var container_name = t.Name;
  147. if (container_name.is_equals("index"))
  148. container_name = "";
  149. var tag = new JObject();
  150. tag.Add("name", container_name);
  151. if (_classes.ContainsKey(t.FullName))
  152. {
  153. var d = _classes[t.FullName];
  154. tag.Add("description", d.summary);
  155. if (!d.href.is_null_or_empty())
  156. {
  157. var ext_doc = new JObject();
  158. ext_doc.Add("description", "детальнее");
  159. ext_doc.Add("url", d.href);
  160. tag.Add("externalDocs", ext_doc);
  161. }
  162. }
  163. tags.Add(tag);
  164. // опрделение операций
  165. foreach (var method in t.Methods.Where((_) => { return _.IsPublic && !_.IsStatic && !_.IsConstructor; }))
  166. {
  167. if (method.Name.is_equals("ToString")
  168. || method.Name.is_equals("Equals")
  169. || method.Name.is_equals("GetHashCode")
  170. || method.Name.is_equals("GetType"))
  171. continue;
  172. var operation_name = method.Name.ToLower();
  173. var sb = new StringBuilder();
  174. if (!container_name.is_null_or_empty())
  175. sb.AppendFormat("/{0}", container_name);
  176. sb.AppendFormat("/{0}", operation_name);
  177. var path = sb.ToString();
  178. var operation_id = path.Replace('/', '_')
  179. .Substring(1);
  180. var summary = "";
  181. details md = new details();
  182. var key = "{0}.{1}".format(t.Name, method.Name);
  183. if (_methods.ContainsKey(key))
  184. {
  185. md = _methods[key];
  186. summary = md.summary;
  187. }
  188. var parameters = new JArray();
  189. //var produces = new JArray("multipart/form-data");
  190. //var consumes = new JArray("multipart/form-data");
  191. var parameter = new JObject();
  192. parameters.Add(parameter);
  193. parameter.Add("in", "body");
  194. parameter.Add("name", "body");
  195. var schema = new JObject();
  196. parameter.Add("schema", schema);
  197. var properties = new JObject();
  198. schema.Add("type", "object");
  199. schema.Add("properties", properties);
  200. var required = new JArray();
  201. // required arguments
  202. foreach (var p in method.Parameters.OrderBy(_ => { return _.Name; }) )
  203. {
  204. if (p.IsOptional)
  205. continue;
  206. required.Add(p.Name);
  207. var pd = define_equals_type(p.ParameterType);
  208. if (md.members.ContainsKey(p.Name))
  209. pd.Add("description", md.members[p.Name]);
  210. properties.Add(p.Name, pd);
  211. }
  212. if(required.Count > 0)
  213. schema.Add("required", required);
  214. // optional arguments
  215. foreach (var p in method.Parameters.OrderBy(_ => { return _.Name; }))
  216. {
  217. if (!p.IsOptional)
  218. continue;
  219. var pd = define_equals_type(p.ParameterType);
  220. if (md.members.ContainsKey(p.Name))
  221. pd.Add("description", md.members[p.Name]);
  222. properties.Add(p.Name, pd);
  223. }
  224. var prefix = new JObject();
  225. prefix.Add("name", "mq_prefix");
  226. prefix.Add("in", "header");
  227. prefix.Add("required", false);
  228. prefix.Add("type", "string");
  229. var v = new JArray() {"_dev", "common", "test.even", "test.odd", "preprod" };
  230. prefix.Add("enum", v);
  231. prefix.Add("default", "");
  232. prefix.Add("description", "префикс контура");
  233. parameters.Add(prefix);
  234. var mq_id = new JObject();
  235. mq_id.Add("name", "mq_id");
  236. mq_id.Add("in", "header");
  237. mq_id.Add("required", false);
  238. mq_id.Add("type", "string");
  239. parameters.Add(mq_id);
  240. var r200 = new JObject();
  241. var r500 = new JObject();
  242. var responses = new JObject();
  243. responses.Add("200", r200);
  244. responses.Add("500", r500);
  245. if (md.returns.is_null_or_empty())
  246. r200.Add("description", "success");
  247. else
  248. r200.Add("description", md.returns);
  249. var r_200_schema = new JObject();
  250. r200.Add("schema", r_200_schema);
  251. r_200_schema.Add("type", "object");
  252. var r_200_properties = new JObject();
  253. r_200_schema.Add("properties", r_200_properties);
  254. // добавить result
  255. var ttt = define_result_type(method.ReturnType);
  256. r_200_properties.Add("result", ttt);
  257. r500.Add("description", "internal error");
  258. var r_500_schema = new JObject();
  259. r500.Add("schema", r_500_schema);
  260. r_500_schema.Add("type", "object");
  261. var r_500_properties = new JObject();
  262. r_500_schema.Add("properties", r_500_properties);
  263. var property500 = new JObject();
  264. r_500_properties.Add("message", property500);
  265. property500.Add("type", "string");
  266. property500.Add("description", "сообщение об ошибке");
  267. var post = new JObject();
  268. post.Add("tags", new JArray(container_name));
  269. post.Add("summary", summary);
  270. //post.Add("description", summary);
  271. post.Add("operationId", operation_id);
  272. //post.Add("produces", produces);
  273. //post.Add("consumes", consumes);
  274. post.Add("parameters", parameters);
  275. post.Add("responses", responses);
  276. var path_content = new JObject();
  277. path_content.Add("post", post);
  278. paths.Add(path, path_content);
  279. }
  280. }
  281. tags = tags
  282. .OrderBy((t) => { return t.Value<string>("name"); })
  283. .ToList();
  284. spec.Add("tags", new JArray(tags));
  285. var ps = new JObject();
  286. var pks = paths.Keys.OrderBy((k) => { return k; });
  287. foreach (var p in pks)
  288. ps.Add(p, paths[p]);
  289. spec.Add("paths", ps);
  290. var definitions = new JObject();
  291. foreach (var i in _definitions)
  292. {
  293. definitions.Add(i.Key, i.Value);
  294. }
  295. spec.Add("definitions", definitions);
  296. return spec.ToString();
  297. }
  298. private JObject define_result_type(TypeReference t)
  299. {
  300. if (t.FullName.Contains("System.Threading.Tasks.Task`"))
  301. {
  302. var prop = t.GetType().GetProperty("GenericArguments");
  303. var d = (IList)prop.GetValue(t);
  304. return define_equals_type((TypeReference)d[0]);
  305. }
  306. else if (t.FullName.is_equals("System.Void"))
  307. {
  308. return new JObject();
  309. }
  310. else if (t.FullName.is_equals("System.Threading.Tasks.Task"))
  311. {
  312. return new JObject();
  313. }
  314. return define_equals_type(t);
  315. }
  316. private JObject define_equals_type(TypeReference t)
  317. {
  318. var res = new JObject();
  319. if (t.FullName.StartsWith("System.Collections.Generic.List`")
  320. || t.FullName.StartsWith("System.Collections.Generic.HashSet`"))
  321. {
  322. var prop = t.GetType().GetProperty("GenericArguments");
  323. var d = (IList)prop.GetValue(t);
  324. var arg_type = (TypeReference)d[0];
  325. res.Add("items", define_equals_type(arg_type));
  326. res.Add("type", "array");
  327. }
  328. else if (t.FullName.StartsWith("System.Collections.Generic.Dictionary`"))
  329. {
  330. res.Add("type", "object");
  331. }
  332. else if (t.FullName.is_equals("Newtonsoft.Json.Linq.JObject"))
  333. {
  334. res.Add("type", "object");
  335. }
  336. else if (t.FullName.is_equals("Newtonsoft.Json.Linq.JArray"))
  337. {
  338. res.Add("type", "array");
  339. var o = new JObject();
  340. res.Add("items", o);
  341. o.Add("type", "object");
  342. }
  343. else if (t.IsArray)
  344. {
  345. var arg_type = t.GetElementType();
  346. res.Add("items", define_equals_type(arg_type));
  347. res.Add("type", "array");
  348. }
  349. else if (t.FullName.is_equals("System.String"))
  350. {
  351. res.Add("type", "string");
  352. }
  353. else if (t.FullName.Contains("System.SByte")
  354. || t.FullName.Contains("System.Byte")
  355. || t.FullName.Contains("System.Char")
  356. || t.FullName.Contains("System.Int16")
  357. || t.FullName.Contains("System.UInt16")
  358. || t.FullName.Contains("System.Int32")
  359. || t.FullName.Contains("System.UInt32")
  360. || t.FullName.Contains("System.Int64")
  361. || t.FullName.Contains("System.UInt64")
  362. )
  363. {
  364. res.Add("type", "integer");
  365. }
  366. else if (t.FullName.Contains("System.Boolean"))
  367. {
  368. res.Add("type", "boolean");
  369. }
  370. else if (t.FullName.Contains("System.Single")
  371. || t.FullName.Contains("System.Double")
  372. || t.FullName.Contains("System.Decimal"))
  373. {
  374. res.Add("type", "number");
  375. }
  376. else // object
  377. {
  378. if (!_definitions.ContainsKey(t.Name))
  379. {
  380. var def = new JObject();
  381. def.Add("type", "object");
  382. if (_classes.ContainsKey(t.FullName))
  383. {
  384. def.Add("description", _classes[t.FullName].summary);
  385. }
  386. var props = new JObject();
  387. def.Add("properties", props);
  388. var tmp_obj = (TypeDefinition)t;
  389. var ts = new List<TypeDefinition>();
  390. ts.Add(tmp_obj);
  391. while (!tmp_obj.BaseType.FullName.is_equals("System.Object"))
  392. {
  393. tmp_obj = (TypeDefinition)tmp_obj.BaseType;
  394. ts.Add(tmp_obj);
  395. }
  396. foreach (var obj in ts)
  397. {
  398. foreach (var i in obj.Properties)
  399. {
  400. var idx = i.FullName.IndexOf(' ');
  401. var k = i.FullName
  402. .Substring(idx + 1)
  403. .Replace("::", ".")
  404. .Replace("()", "");
  405. var ed = define_equals_type(i.PropertyType);
  406. var ttt = ed.Value<string>("type");
  407. if (!ttt.is_null()
  408. && _properties.ContainsKey(k))
  409. {
  410. ed.Add("description", _properties[k].summary);
  411. }
  412. props.Add(i.Name, ed);
  413. }
  414. }
  415. // отсортировать свойства
  416. _definitions.Add(t.Name, def);
  417. }
  418. res.Add("$ref", "#/definitions/{0}".format(t.Name));
  419. }
  420. return res;
  421. }
  422. }
  423. }