main.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. const fs = require("fs");
  2. const path_ = require("path");
  3. const rootdir = path_.resolve(process.argv[2] ?? '.');
  4. const parser = require('@babel/parser');
  5. const traverse = require('@babel/traverse').default;
  6. const doctrine = require('doctrine');
  7. const def_module = {
  8. services: [],
  9. };
  10. const to_module_add_service = (def_module, values) => {
  11. def_module.services.push({
  12. ...values,
  13. });
  14. }
  15. const to_service_add_listener = (def_service, values) => {
  16. const parsed_comment = doctrine.parse(values.comment, { unwrap: true });
  17. const params = [];
  18. for ( const tag of parsed_comment.tags ) {
  19. if ( tag.title !== 'evtparam' ) continue;
  20. const name = tag.description.slice(0, tag.description.indexOf(' '));
  21. const desc = tag.description.slice(tag.description.indexOf(' '));
  22. params.push({ name, desc })
  23. }
  24. def_service.listeners.push({
  25. ...values,
  26. comment: parsed_comment.description,
  27. params,
  28. });
  29. };
  30. const to_service_add_comment = (def_service, comment) => {
  31. console.log('comment', comment);
  32. const parsed_comment = doctrine.parse(comment.value, { unwrap: true });
  33. def_service.comment = parsed_comment.description;
  34. };
  35. const to_module_add_comment = (def_module, comment) => {
  36. console.log('comment', comment);
  37. const parsed_comment = doctrine.parse(comment.value, { unwrap: true });
  38. def_module.comment = parsed_comment.description;
  39. };
  40. const create_service = () => ({
  41. listeners: []
  42. });
  43. // List files in this directory
  44. const files = fs.readdirSync(rootdir);
  45. for ( const file of files ) {
  46. const stat = fs.statSync(path_.join(rootdir, file));
  47. if ( stat.isDirectory() ) {
  48. continue;
  49. }
  50. if ( ! file.endsWith('.js') ) continue;
  51. const type =
  52. file.endsWith('Service.js') ? 'service' :
  53. file.endsWith('Module.js') ? 'module' :
  54. null;
  55. if ( type === null ) continue;
  56. const def_service = create_service();
  57. console.log('file', file);
  58. const code = fs.readFileSync(path_.join(rootdir, file), 'utf8');
  59. const ast = parser.parse(code);
  60. traverse(ast, {
  61. ClassDeclaration (path) {
  62. const node = path.node;
  63. const name = node.id.name;
  64. def_service.name = name;
  65. // Skip utility classes (for now)
  66. if ( name !== file.slice(0, -3) ) {
  67. return;
  68. }
  69. const comment = (node.leadingComments && (
  70. node.leadingComments.length < 1 ? '' :
  71. node.leadingComments[node.leadingComments.length - 1]
  72. )) ?? '';
  73. if ( type === 'module' ) {
  74. def_module.name = name;
  75. if ( comment !== '' ) {
  76. to_module_add_comment(def_module, comment);
  77. }
  78. return;
  79. }
  80. if ( comment !== '' ) {
  81. to_service_add_comment(def_service, comment);
  82. }
  83. console.log('class', name);
  84. path.node.body.body.forEach(member => {
  85. const key = member.key.name ?? member.key.value;
  86. const comment = member.leadingComments?.[0]?.value ?? '';
  87. if ( key.startsWith('__on_') ) {
  88. // 2nd argument is always an object destructuring;
  89. // we want the list of keys in the object:
  90. const params = member.params?.[1]?.properties ?? [];
  91. to_service_add_listener(def_service, {
  92. key: key.slice(5),
  93. comment,
  94. params,
  95. });
  96. }
  97. console.log(member.type, key, member.leadingComments);
  98. });
  99. // module_info.services.push({
  100. // name,
  101. // file,
  102. // });
  103. }
  104. })
  105. to_module_add_service(def_module, def_service);
  106. // console.log('parsed?', parsed);
  107. }
  108. console.log('module', JSON.stringify(def_module, undefined, ' '));
  109. const outfile = path_.join(rootdir, 'README.md');
  110. let out = '';
  111. out += `# ${def_module.name}\n\n`;
  112. if ( def_module.comment ) {
  113. out += `${def_module.comment}\n\n`;
  114. }
  115. out += '## Services\n\n';
  116. for ( const service of def_module.services ) {
  117. out += `### ${service.name}\n\n`;
  118. out += `${service.comment}\n\n`;
  119. out += '#### Listeners\n\n';
  120. for ( const listener of service.listeners ) {
  121. out += `##### \`${listener.key}\`\n\n`;
  122. out += `${listener.comment}\n\n`;
  123. if ( listener.params.length > 0 ) {
  124. out += '###### Parameters\n\n';
  125. for ( const param of listener.params ) {
  126. out += `- \`${param.name}\`: ${param.desc}\n`;
  127. }
  128. out += '\n';
  129. }
  130. }
  131. }
  132. fs.writeFileSync(outfile, out);