index.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. // 声明所有全局内容
  2. var sa_mcontent = {
  3. // 例如:定义res, 你可以在md文档中使用 import(res),来导入这一段话
  4. res: '``` js\n\t{\n\t\t"code": 200, // 成功时=200, 失败时=500 msg=失败原因\n\t\t"msg": "ok",\n\t\t"data": {}\n\t} \n```'
  5. };
  6. // 声明插件
  7. var sa_plugins = function(hook) {
  8. // 解析之前执行
  9. hook.beforeEach(function(content) {
  10. content = refMd_p2table(content); // 参数转表格
  11. content = refMd_import2content(content); // 加载import
  12. content = refMd_api2trim(content); // api去除空格
  13. content = refMd_var(content); // 更换变量
  14. return content;
  15. });
  16. // 解析之后执行
  17. hook.afterEach(function(html) {
  18. // 添加页脚
  19. var footer = [
  20. '<br/><br/><br/><br/><br/><br/><br/><hr/>',
  21. '<footer>',
  22. '&emsp;<span>本接口文档使用 <a href="https://github.com/click33/sa-doc" target="_blank">sa-doc</a> 编写</span>',
  23. // '<span>Proudly published with <a href="https://github.com/docsifyjs/docsify" target="_blank">docsify</a>.</span>',
  24. '</footer>'
  25. ].join('');
  26. return html + footer;
  27. });
  28. function f5_test_btn() {
  29. // console.log(123);
  30. $('.anchor').each(function(index, el) {
  31. try{
  32. // 获取父元素
  33. var parTag = $(this).parent('h3');
  34. if(parTag == null) {
  35. return;
  36. }
  37. var tagName = parTag.prop("tagName");
  38. if(tagName != 'H3') {
  39. return;
  40. }
  41. // 地址、参数等信息
  42. var cc_id = sa.randomString(16); // id号码
  43. window.apiInfoMap = window.apiInfoMap || {}; // 存储当前页面所有api信息
  44. window.apiInfoMap[cc_id] = { // 此项的所有信息
  45. // api_title: parTag.find('a span').text(), // 接口标题
  46. ajaxUrl: '', // 接口地址
  47. ajaxType: 'GET', // 接口请求方式
  48. headerList: [], // 请求头参数
  49. bodyList: [], // 请求体参数
  50. };
  51. var apiInfo = window.apiInfoMap[cc_id];
  52. var nextTagArr = $(parTag).nextAll();
  53. for (var i = 0; i < nextTagArr.length; i++) {
  54. var tag = $(nextTagArr.get(i));
  55. // 如果已经到了H3了,则可以结束了
  56. if(tag.prop("tagName") == 'H3') {
  57. break;
  58. }
  59. // 如果是参数
  60. if(tag.prop("tagName") == 'TABLE') {
  61. var trArr = $(tag).find('tbody tr');
  62. for (var j = 0; j < trArr.length; j++) {
  63. var tdArr = $(trArr.get(j)).find('td');
  64. apiInfo.bodyList.push({name: tdArr.get(0).innerHTML, value: '', tips: tdArr.get(3).innerHTML}); // , value: tdArr.get(3)
  65. }
  66. }
  67. // 如果是参数
  68. // if(tag.prop("tagName") == 'DIV' && tag.prop('class') == 'body-p-list') {
  69. // var text = tag.text();
  70. // var trArr = JSON.parse(text);
  71. // console.log(trArr.length);
  72. // for (var j = 0; j < trArr.length; j++) {
  73. // var tdArr = trArr[j];
  74. // apiInfo.bodyList.push({name: tdArr[0], value: '', tips: tdArr[3]}); // , value: tdArr[2]
  75. // }
  76. // }
  77. // 如果是地址
  78. if(tag.prop("tagName") == 'UL') {
  79. // 如果能搜索到 data-lang="api"
  80. var tg = $(tag).find('[class=lang-api]');
  81. if(tg.length > 0) {
  82. var url_i = tg.get(0).innerHTML;
  83. if(url_i.indexOf('http') != 0) {
  84. url_i = sa_doc_cfg.server_url + url_i;;
  85. }
  86. apiInfo.ajaxUrl = url_i;
  87. }
  88. }
  89. }
  90. // console.log(nextAll.length);
  91. // console.log(tagName);
  92. // 后面添加一个按钮
  93. // parTag.after('<button>测试接口</button>');
  94. // console.log(parTag.find('a span').text());
  95. var button = '<button class="test-api-btn" type="button" '+
  96. ' cc-id="' + cc_id + '" ' +
  97. ' api-title="' + parTag.find('a span').text() + '" ' +
  98. ' onclick="test_api(this)">接口测试</button>';
  99. parTag.append(button);
  100. }catch(e){
  101. console.err(e);
  102. }
  103. })
  104. }
  105. // 渲染完全完成之后
  106. hook.doneEach(function() {
  107. f5_test_btn();
  108. // 给代码盒子,添加行数样式
  109. $('pre code').each(function(){
  110. var lines = $(this).text().split('\n').length;
  111. var $numbering = $('<ul/>').addClass('code-line-box');
  112. $(this)
  113. .addClass('has-numbering')
  114. .parent()
  115. .append($numbering);
  116. for(i=1;i<=lines;i++){
  117. $numbering.append($('<li/>').text(i));
  118. }
  119. });
  120. });
  121. };
  122. // 点击测试接口的按钮
  123. function test_api(event) {
  124. // console.log(event.classList);
  125. // 获取参数
  126. // 获取title
  127. var j_index = document.title.indexOf('-');
  128. var title = document.title;
  129. if(j_index > -1) {
  130. title = title.substr(0, j_index);
  131. title = event.getAttribute('api-title') + ' &emsp;&emsp;----by&emsp; ' + title;
  132. }
  133. // 获取地址、参数等信息
  134. var id = event.getAttribute('cc-id');
  135. var cc = window.apiInfoMap[id];
  136. console.log(cc);
  137. // var cc = {
  138. // ajaxType: 'GET',
  139. // ajaxUrl: 'dsada',
  140. // headerList: [],
  141. // bodyList: []
  142. // }
  143. sessionStorage.setItem('sa-doc-cc-' + id, JSON.stringify(cc));
  144. sa.showIframe3(title, './sa-lib/api-test/index.html?id=' + id, '1000px', '90%');
  145. }
  146. // 移除数组中所有空白字符串
  147. function arrayTrimSpace(array) {
  148. for (var i = 0; i < array.length; i++) {
  149. if (array[i] == "" || array[i] == " " || array[i] == null || typeof(array[i]) == "undefined") {
  150. array.splice(i, 1);
  151. i = i - 1;
  152. }
  153. }
  154. return array;
  155. }
  156. // 获取一行表格
  157. // 参数名字,类型,默认值,说明
  158. function getTrMd(name, type, default_value, remrak) {
  159. var str = '\n|' + name + '|' + type + '|' + default_value + '|' + remrak + '|';
  160. return str;
  161. }
  162. // 加工md,将其中的```p 转换为table格式
  163. function refMd_p2table(content) {
  164. // 1、取出全文中所有的 ```d
  165. var reg = /```\s*p[\s\S]*?```/igm; // [\s\S]*=任意字符n次,?=非贪婪模式
  166. var pArr = content.match(reg)|| [];; // 返回所有匹配项数组
  167. // 遍历并转换
  168. pArr.forEach(function(p) {
  169. // 声明表头
  170. var table = '\n' +
  171. '| 参数名称| 类型| 默认值|说明|\n' +
  172. '| :--------| :--------| :--------|:--------|';
  173. // 将这个p内容按换行符切割
  174. var canStr = p.replace(/```\s*p/, '').replace('```', '').trim(); // 去除首行尾行
  175. var canArr = canStr.split('\n') || []; // 按行切割
  176. // var bodyPList = []; // 二维数组记录一下参数集合
  177. // 开始逐行转换为tr
  178. canArr.forEach(function(canStr) {
  179. // 去除空格
  180. canStr = canStr.trim();
  181. // 声明四大变量的值
  182. let name = ''; // 参数名子
  183. let type = ''; // 数据类型
  184. let default_value = ''; // 默认值
  185. let remrak = ''; // 参数说明
  186. // 如果带有数据类型
  187. if(canStr.indexOf('{') > -1 && canStr.indexOf('}') > -1) {
  188. canStr = canStr.replace('{', ''); // 去除掉前{
  189. let sjArr = canStr.split('}'); // 按照}分割
  190. type = sjArr[0].trim();
  191. canStr = sjArr[1].trim();
  192. }
  193. // 切割成数组
  194. var canArray = canStr.split(/[\s\t\n]/) || [];
  195. // canArray = arrayTrimSpace(canArray); // 去除空格元素
  196. // 如果开发者写的不规范,使其超过2个元素,则强制改为2个元素
  197. if(canArray.length == 0) {
  198. return;
  199. }
  200. if(canArray.length == 1) {
  201. canArray.push('');
  202. }
  203. // =========== 开始判断 5种情况 ==================
  204. let one = canArray[0];
  205. let two = canArray[1];
  206. // 情况1 id=1 xxxx
  207. if(one.indexOf('=') > -1 && one.indexOf('=') < one.length - 1) {
  208. name = one.split('=')[0];
  209. default_value = one.split('=')[1];
  210. canArray.splice(0, 1);
  211. }
  212. // 情况2 id= 1 xxxx
  213. else if(one.indexOf('=') == one.length - 1) {
  214. name = one.split('=')[0];
  215. default_value = two;
  216. canArray.splice(0, 2);
  217. }
  218. // 情况3 id =1 xxxx
  219. else if(one.indexOf('=') == -1 && two.indexOf('=') == 0 && two.length > 1) {
  220. name = one;
  221. default_value = two.split('=')[1];
  222. canArray.splice(0, 2);
  223. }
  224. // 情况4 id = 1 xxxx
  225. else if(one.indexOf('=') == -1 && two == '=') {
  226. name = one;
  227. default_value = canArray[2] || '';
  228. canArray.splice(0, 3);
  229. }
  230. // 情况5 id 1 xxxx 或其它
  231. // else if(one.indexOf('=') == -1 && two.indexOf('=') != 0) {
  232. else {
  233. name = one;
  234. canArray.splice(0, 1);
  235. }
  236. // 剩下的元素,都拼接remrak
  237. remrak = canArray.join('');
  238. // 添加到表格
  239. table += getTrMd(name, type, default_value, remrak);
  240. // bodyPList.push([name, type, default_value, remrak]);
  241. })
  242. // console.log(p);
  243. // 将原始p内容替换成为table内容
  244. table += '\n';
  245. // table += '\n<div class="body-p-list" style="display: none;">' + JSON.stringify(bodyPList) + '</div>\n'; // 增加上参数信息
  246. content = content.replace(p, table);
  247. });
  248. return content;
  249. }
  250. // 加工md,将其中的@import 转换为真实内容
  251. function refMd_import2content(content) {
  252. // 1、取出全文中所有的 ```d
  253. var reg = /@import\([\s\S]*?\)/igm; // [\s\S]*=任意字符n次,?=非贪婪模式
  254. var importArr = content.match(reg)|| []; // 返回所有匹配项数组
  255. // 遍历并转换
  256. importArr.forEach(function(import_item) {
  257. // 过滤空格
  258. // console.log(import_item);
  259. var item = import_item.replace(' ', '').replace('@import(', '').replace(')', '');
  260. // 开始替换
  261. content = content.replace(import_item, sa_mcontent[item] || '');
  262. });
  263. return content;
  264. }
  265. // 加工md,将其中的```api 去除空格
  266. function refMd_api2trim(content) {
  267. // 1、取出全文中所有的 ```d
  268. var reg = /```\s*api[\s\S]*?```/igm; // [\s\S]*=任意字符n次,?=非贪婪模式
  269. var pArr = content.match(reg)|| [];; // 返回所有匹配项数组
  270. // 遍历并转换
  271. pArr.forEach(function(p) {
  272. // 将这个p内容按换行符切割
  273. var canStr = p.replace(/```\s*api/, '').replace('```', '').trim(); // 去除首行尾行
  274. var canArr = canStr.split('\n') || []; // 按行切割
  275. var str = '';
  276. // 遍历并转换
  277. canArr.forEach(function(p) {
  278. str += p;
  279. });
  280. str = '``` api\n' + str + '```\n';
  281. // console.log(str);
  282. // 加上按钮
  283. // str = '<button>测试接口</button>\n' + str;
  284. // 将原始p内容替换成为后来内容
  285. content = content.replace(p, str);
  286. })
  287. return content;
  288. }
  289. // 加工md,将其中的变量
  290. function refMd_var(content) {
  291. content = content.replace('${sa_doc_cfg.server_url}', window.sa_doc_cfg.server_url);
  292. return content;
  293. }
  294. // 打印信息
  295. console.log('欢迎使用sa-doc(一个基于markdown的接口文档编写工具),当前版本:v1.3.0,更新于:2020-07-2,GitHub地址:https://github.com/click33/sa-doc');
  296. console.log('如在使用中发现任何bug或者疑问,请加入QQ群交流:782974737,点击加入:https://jq.qq.com/?_wv=1027&k=5DHN5Ib');