defs.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. const dedent = require('dedent');
  2. const doctrine = require('doctrine');
  3. class Out {
  4. constructor () {
  5. this.str = '';
  6. const fn = this.out.bind(this);
  7. fn.h = this.h.bind(this);
  8. fn.lf = this.lf.bind(this);
  9. fn.text = () => this.str;
  10. return fn;
  11. }
  12. h (n, text) {
  13. this.str += '#'.repeat(n) + ' ' + text + '\n\n';
  14. }
  15. lf () { this.str += '\n'; }
  16. out (str) {
  17. this.str += str;
  18. }
  19. }
  20. class Doc {
  21. constructor () {
  22. this._construct();
  23. }
  24. provide_comment (comment) {
  25. const parsed_comment = doctrine.parse(comment.value, { unwrap: true });
  26. this.comment = parsed_comment.description;
  27. }
  28. }
  29. class ModuleDoc extends Doc {
  30. _construct () {
  31. this.services = [];
  32. this.requires = [];
  33. this.libs = [];
  34. }
  35. add_service () {
  36. const service = new ServiceDoc();
  37. this.services.push(service);
  38. return service;
  39. }
  40. add_lib () {
  41. const lib = new LibDoc();
  42. this.libs.push(lib);
  43. return lib;
  44. }
  45. ready () {
  46. this.notes = [];
  47. const rel_requires = this.requires.filter(r => r.startsWith('../'));
  48. if ( rel_requires.length > 0 ) {
  49. this.notes.push({
  50. title: 'Outside Imports',
  51. desc: dedent(`
  52. This module has external relative imports. When these are
  53. removed it may become possible to move this module to an
  54. extension.
  55. **Imports:**
  56. ${rel_requires.map(r => {
  57. let maybe_aside = '';
  58. if ( r.endsWith('BaseService') ) {
  59. maybe_aside = ' (use.BaseService)';
  60. }
  61. return `- \`${r}\`` + maybe_aside;
  62. }).join('\n')}
  63. `)
  64. });
  65. }
  66. }
  67. toMarkdown ({ hl, out } = { hl: 1 }) {
  68. this.ready();
  69. out = out ?? new Out();
  70. out.h(hl, this.name);
  71. out(this.comment + '\n\n');
  72. if ( this.services.length > 0 ) {
  73. out.h(hl + 1, 'Services');
  74. for ( const service of this.services ) {
  75. service.toMarkdown({ out, hl: hl + 2 });
  76. }
  77. }
  78. if ( this.libs.length > 0 ) {
  79. out.h(hl + 1, 'Libraries');
  80. for ( const lib of this.libs ) {
  81. lib.toMarkdown({ out, hl: hl + 2 });
  82. }
  83. }
  84. if ( this.notes.length > 0 ) {
  85. out.h(hl + 1, 'Notes');
  86. for ( const note of this.notes ) {
  87. out.h(hl + 2, note.title);
  88. out(note.desc);
  89. out.lf();
  90. }
  91. }
  92. return out.text();
  93. }
  94. }
  95. class ServiceDoc extends Doc {
  96. _construct () {
  97. this.listeners = [];
  98. this.methods = [];
  99. }
  100. provide_comment (comment) {
  101. const parsed_comment = doctrine.parse(comment.value, { unwrap: true });
  102. this.comment = parsed_comment.description;
  103. }
  104. provide_listener (listener) {
  105. const parsed_comment = doctrine.parse(listener.comment, { unwrap: true });
  106. const params = [];
  107. for ( const tag of parsed_comment.tags ) {
  108. if ( tag.title !== 'evtparam' ) continue;
  109. const name = tag.description.slice(0, tag.description.indexOf(' '));
  110. const desc = tag.description.slice(tag.description.indexOf(' '));
  111. params.push({ name, desc })
  112. }
  113. this.listeners.push({
  114. ...listener,
  115. comment: parsed_comment.description,
  116. params,
  117. });
  118. }
  119. provide_method (method) {
  120. const parsed_comment = doctrine.parse(method.comment, { unwrap: true });
  121. const params = [];
  122. for ( const tag of parsed_comment.tags ) {
  123. if ( tag.title !== 'param' ) continue;
  124. const name = tag.name;
  125. const desc = tag.description;
  126. params.push({ name, desc })
  127. }
  128. this.methods.push({
  129. ...method,
  130. comment: parsed_comment.description,
  131. params,
  132. });
  133. }
  134. toMarkdown ({ hl, out } = { hl: 1 }) {
  135. out = out ?? new Out();
  136. out.h(hl, this.name);
  137. out(this.comment + '\n\n');
  138. if ( this.listeners.length > 0 ) {
  139. out.h(hl + 1, 'Listeners');
  140. for ( const listener of this.listeners ) {
  141. out.h(hl + 2, '`' + listener.key + '`');
  142. out (listener.comment + '\n\n');
  143. if ( listener.params.length > 0 ) {
  144. out.h(hl + 3, 'Parameters');
  145. for ( const param of listener.params ) {
  146. out(`- **${param.name}:** ${param.desc}\n`);
  147. }
  148. out.lf();
  149. }
  150. }
  151. }
  152. if ( this.methods.length > 0 ) {
  153. out.h(hl + 1, 'Methods');
  154. for ( const method of this.methods ) {
  155. out.h(hl + 2, '`' + method.key + '`');
  156. out (method.comment + '\n\n');
  157. if ( method.params.length > 0 ) {
  158. out.h(hl + 3, 'Parameters');
  159. for ( const param of method.params ) {
  160. out(`- **${param.name}:** ${param.desc}\n`);
  161. }
  162. out.lf();
  163. }
  164. }
  165. }
  166. return out.text();
  167. }
  168. }
  169. class LibDoc extends Doc {
  170. _construct () {
  171. this.functions = [];
  172. }
  173. provide_function ({ key, comment, params }) {
  174. const parsed_comment = doctrine.parse(comment, { unwrap: true });
  175. const parsed_params = [];
  176. for ( const tag of parsed_comment.tags ) {
  177. if ( tag.title !== 'param' ) continue;
  178. const name = tag.name;
  179. const desc = tag.description;
  180. parsed_params.push({ name, desc });
  181. }
  182. this.functions.push({
  183. key,
  184. comment: parsed_comment.description,
  185. params: parsed_params,
  186. });
  187. }
  188. toMarkdown ({ hl, out } = { hl: 1 }) {
  189. out = out ?? new Out();
  190. out.h(hl, this.name);
  191. console.log('functions?', this.functions);
  192. if ( this.functions.length > 0 ) {
  193. out.h(hl + 1, 'Functions');
  194. for ( const func of this.functions ) {
  195. out.h(hl + 2, '`' + func.key + '`');
  196. out(func.comment + '\n\n');
  197. if ( func.params.length > 0 ) {
  198. out.h(hl + 3, 'Parameters');
  199. for ( const param of func.params ) {
  200. out(`- **${param.name}:** ${param.desc}\n`);
  201. }
  202. out.lf();
  203. }
  204. }
  205. }
  206. return out.text();
  207. }
  208. }
  209. module.exports = {
  210. ModuleDoc,
  211. ServiceDoc,
  212. };