You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

288 lines
8.9 KiB

  1. // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.
  2. var common = require('./common.js');;
  3. var classCategory = 'class';
  4. var namespaceCategory = 'ns';
  5. exports.transform = function (model) {
  6. if (!model) return
  7. handleItem(model, model._gitContribute, model._gitUrlPattern);
  8. if (model.children) {
  9. normalizeChildren(model.children).forEach(function (item) {
  10. handleItem(item, model._gitContribute, model._gitUrlPattern);
  11. });
  12. };
  13. if (model.type) {
  14. switch (model.type.toLowerCase()) {
  15. case 'namespace':
  16. model.isNamespace = true;
  17. if (model.children) groupChildren(model, namespaceCategory);
  18. break;
  19. case 'package':
  20. case 'class':
  21. case 'interface':
  22. case 'struct':
  23. case 'delegate':
  24. model.isClass = true;
  25. if (model.children) groupChildren(model, classCategory);
  26. model[getTypePropertyName(model.type)] = true;
  27. break;
  28. case 'enum':
  29. model.isEnum = true;
  30. if (model.children) groupChildren(model, classCategory);
  31. model[getTypePropertyName(model.type)] = true;
  32. break;
  33. default:
  34. break;
  35. }
  36. }
  37. return model;
  38. }
  39. exports.getBookmarks = function (model, ignoreChildren) {
  40. if (!model || !model.type || model.type.toLowerCase() === "namespace") return null;
  41. var bookmarks = {};
  42. if (typeof ignoreChildren == 'undefined' || ignoreChildren === false) {
  43. if (model.children) {
  44. normalizeChildren(model.children).forEach(function (item) {
  45. bookmarks[item.uid] = common.getHtmlId(item.uid);
  46. if (item.overload && item.overload.uid) {
  47. bookmarks[item.overload.uid] = common.getHtmlId(item.overload.uid);
  48. }
  49. });
  50. }
  51. }
  52. // Reference's first level bookmark should have no anchor
  53. bookmarks[model.uid] = "";
  54. return bookmarks;
  55. }
  56. function handleItem(vm, gitContribute, gitUrlPattern) {
  57. // get contribution information
  58. vm.docurl = common.getImproveTheDocHref(vm, gitContribute, gitUrlPattern);
  59. vm.sourceurl = common.getViewSourceHref(vm, gitContribute, gitUrlPattern);
  60. // set to null incase mustache looks up
  61. vm.summary = vm.summary || null;
  62. vm.remarks = vm.remarks || null;
  63. vm.conceptual = vm.conceptual || null;
  64. vm.syntax = vm.syntax || null;
  65. vm.implements = vm.implements || null;
  66. vm.example = vm.example || null;
  67. common.processSeeAlso(vm);
  68. // id is used as default template's bookmark
  69. vm.id = common.getHtmlId(vm.uid);
  70. if (vm.overload && vm.overload.uid) {
  71. vm.overload.id = common.getHtmlId(vm.overload.uid);
  72. }
  73. // concatenate multiple types with `|`
  74. if (vm.syntax) {
  75. var syntax = vm.syntax;
  76. if (syntax.parameters) {
  77. syntax.parameters = syntax.parameters.map(function (p) {
  78. return joinType(p);
  79. })
  80. syntax.parameters = groupParameters(syntax.parameters);
  81. }
  82. if (syntax.return) {
  83. syntax.return = joinType(syntax.return);
  84. }
  85. }
  86. }
  87. function joinType(parameter) {
  88. // change type in syntax from array to string
  89. var joinTypeProperty = function (type, key) {
  90. if (!type || !type[0] || !type[0][key]) return null;
  91. var value = type.map(function (t) {
  92. return t[key][0].value;
  93. }).join(' | ');
  94. return [{
  95. lang: type[0][key][0].lang,
  96. value: value
  97. }];
  98. };
  99. if (parameter.type) {
  100. parameter.type = {
  101. name: joinTypeProperty(parameter.type, "name"),
  102. nameWithType: joinTypeProperty(parameter.type, "nameWithType"),
  103. fullName: joinTypeProperty(parameter.type, "fullName"),
  104. specName: joinTypeProperty(parameter.type, "specName")
  105. }
  106. }
  107. return parameter;
  108. }
  109. function groupParameters(parameters) {
  110. // group parameter with properties
  111. if (!parameters || parameters.length == 0) return parameters;
  112. var groupedParameters = [];
  113. var stack = [];
  114. for (var i = 0; i < parameters.length; i++) {
  115. var parameter = parameters[i];
  116. parameter.properties = null;
  117. var prefixLength = 0;
  118. while (stack.length > 0) {
  119. var top = stack.pop();
  120. var prefix = top.id + '.';
  121. if (parameter.id.indexOf(prefix) == 0) {
  122. prefixLength = prefix.length;
  123. if (!top.parameter.properties) {
  124. top.parameter.properties = [];
  125. }
  126. top.parameter.properties.push(parameter);
  127. stack.push(top);
  128. break;
  129. }
  130. if (stack.length == 0) {
  131. groupedParameters.push(top.parameter);
  132. }
  133. }
  134. stack.push({ id: parameter.id, parameter: parameter });
  135. parameter.id = parameter.id.substring(prefixLength);
  136. }
  137. while (stack.length > 0) {
  138. top = stack.pop();
  139. }
  140. groupedParameters.push(top.parameter);
  141. return groupedParameters;
  142. }
  143. function groupChildren(model, category, typeChildrenItems) {
  144. if (!model || !model.type) {
  145. return;
  146. }
  147. if (!typeChildrenItems) {
  148. var typeChildrenItems = getDefinitions(category);
  149. }
  150. var grouped = {};
  151. normalizeChildren(model.children).forEach(function (c) {
  152. if (c.isEii) {
  153. var type = "eii";
  154. } else {
  155. var type = c.type.toLowerCase();
  156. }
  157. if (!grouped.hasOwnProperty(type)) {
  158. grouped[type] = [];
  159. }
  160. // special handle for field
  161. if (type === "field" && c.syntax) {
  162. c.syntax.fieldValue = c.syntax.return;
  163. c.syntax.return = undefined;
  164. }
  165. // special handle for property
  166. if (type === "property" && c.syntax) {
  167. c.syntax.propertyValue = c.syntax.return;
  168. c.syntax.return = undefined;
  169. }
  170. // special handle for event
  171. if (type === "event" && c.syntax) {
  172. c.syntax.eventType = c.syntax.return;
  173. c.syntax.return = undefined;
  174. }
  175. grouped[type].push(c);
  176. })
  177. var children = [];
  178. for (var key in typeChildrenItems) {
  179. if (typeChildrenItems.hasOwnProperty(key) && grouped.hasOwnProperty(key)) {
  180. var typeChildrenItem = typeChildrenItems[key];
  181. var items = grouped[key];
  182. if (items && items.length > 0) {
  183. var item = {};
  184. for (var itemKey in typeChildrenItem) {
  185. if (typeChildrenItem.hasOwnProperty(itemKey)){
  186. item[itemKey] = typeChildrenItem[itemKey];
  187. }
  188. }
  189. item.children = items;
  190. children.push(item);
  191. }
  192. }
  193. }
  194. model.children = children;
  195. }
  196. function getTypePropertyName(type) {
  197. if (!type) {
  198. return undefined;
  199. }
  200. var loweredType = type.toLowerCase();
  201. var definition = getDefinition(loweredType);
  202. if (definition) {
  203. return definition.typePropertyName;
  204. }
  205. return undefined;
  206. }
  207. function getCategory(type) {
  208. var classItems = getDefinitions(classCategory);
  209. if (classItems.hasOwnProperty(type)) {
  210. return classCategory;
  211. }
  212. var namespaceItems = getDefinitions(namespaceCategory);
  213. if (namespaceItems.hasOwnProperty(type)) {
  214. return namespaceCategory;
  215. }
  216. return undefined;
  217. }
  218. function getDefinition(type) {
  219. var classItems = getDefinitions(classCategory);
  220. if (classItems.hasOwnProperty(type)) {
  221. return classItems[type];
  222. }
  223. var namespaceItems = getDefinitions(namespaceCategory);
  224. if (namespaceItems.hasOwnProperty(type)) {
  225. return namespaceItems[type];
  226. }
  227. return undefined;
  228. }
  229. function getDefinitions(category) {
  230. var namespaceItems = {
  231. "class": { inClass: true, typePropertyName: "inClass", id: "classes" },
  232. "struct": { inStruct: true, typePropertyName: "inStruct", id: "structs" },
  233. "interface": { inInterface: true, typePropertyName: "inInterface", id: "interfaces" },
  234. "enum": { inEnum: true, typePropertyName: "inEnum", id: "enums" },
  235. "delegate": { inDelegate: true, typePropertyName: "inDelegate", id: "delegates" },
  236. "package": { inDelegate: true, typePropertyName: "inPackage", id: "packages" }
  237. };
  238. var classItems = {
  239. "constructor": { inConstructor: true, typePropertyName: "inConstructor", id: "constructors" },
  240. "field": { inField: true, typePropertyName: "inField", id: "fields" },
  241. "property": { inProperty: true, typePropertyName: "inProperty", id: "properties" },
  242. "method": { inMethod: true, typePropertyName: "inMethod", id: "methods" },
  243. "event": { inEvent: true, typePropertyName: "inEvent", id: "events" },
  244. "operator": { inOperator: true, typePropertyName: "inOperator", id: "operators" },
  245. "eii": { inEii: true, typePropertyName: "inEii", id: "eii" },
  246. "function": { inFunction: true, typePropertyName: "inFunction", id: "functions"},
  247. "member": { inMember: true, typePropertyName: "inMember", id: "members"}
  248. };
  249. if (category === 'class') {
  250. return classItems;
  251. }
  252. if (category === 'ns') {
  253. return namespaceItems;
  254. }
  255. console.err("category '" + category + "' is not valid.");
  256. return undefined;
  257. }
  258. function normalizeChildren(children) {
  259. if (children[0] && children[0].lang && children[0].value) {
  260. return children[0].value;
  261. }
  262. return children;
  263. }