index.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. const fs = require('fs');
  2. const path = require('path');
  3. const glob = require('glob');
  4. class TempWorkDir {
  5. /**
  6. * Switches the working directory to be the one on which this file lives.
  7. */
  8. constructor(dir) {
  9. this.original = null;
  10. this.dir = dir || path.join(__filename, '..');
  11. }
  12. open() {
  13. this.original = __dirname;
  14. fs.mkdirSync(this.dir, { recursive: true });
  15. process.chdir(this.dir);
  16. return this;
  17. }
  18. close() {
  19. process.chdir(this.original);
  20. }
  21. }
  22. const GENERATOR_DIR = './gramjs_generator';
  23. const LIBRARY_DIR = './gramjs';
  24. const ERRORS_IN = `${GENERATOR_DIR}/data/errors.csv`;
  25. const ERRORS_OUT = `${LIBRARY_DIR}/errors/rpcerrorlist.js`;
  26. const METHODS_IN = `${GENERATOR_DIR}/data/methods.csv`;
  27. // Which raw API methods are covered by *friendly* methods in the client?
  28. const FRIENDLY_IN = `${GENERATOR_DIR}/data/friendly.csv`;
  29. const TLOBJECT_IN_TLS = glob.sync(`${GENERATOR_DIR}/data/*.tl`);
  30. const TLOBJECT_OUT = `${LIBRARY_DIR}/tl`;
  31. const IMPORT_DEPTH = 2;
  32. const DOCS_IN_RES = `../${GENERATOR_DIR}/data/html`;
  33. const DOCS_OUT = `./docs`;
  34. const generate = (which, action = 'gen') => {
  35. const {
  36. parseErrors,
  37. parseMethods,
  38. parseTl,
  39. findLayer,
  40. } = require('./gramjs_generator/parsers');
  41. const {
  42. generateErrors,
  43. generateTLObjects,
  44. generateDocs,
  45. cleanTLObjects,
  46. } = require('./gramjs_generator/generators');
  47. const [layer] = TLOBJECT_IN_TLS.map(findLayer).filter(Boolean);
  48. const errors = [...parseErrors(ERRORS_IN)];
  49. const methods = [
  50. ...parseMethods(
  51. METHODS_IN,
  52. FRIENDLY_IN,
  53. errors.reduce((errors, error) => {
  54. errors[error.stringCode] = error;
  55. return errors;
  56. }, {})
  57. ),
  58. ];
  59. const tlobjects = TLOBJECT_IN_TLS.reduce(
  60. (files, file) => [...files, ...parseTl(file, layer, methods)],
  61. []
  62. );
  63. if (!which || which.length === 0) {
  64. which.push('tl', 'errors');
  65. }
  66. const clean = action === 'clean';
  67. action = clean ? 'Cleaning' : 'Generating';
  68. if (which.includes('all')) {
  69. which.splice(which.indexOf('all'), 1);
  70. for (const x of ['tl', 'errors', 'docs']) {
  71. if (!which.includes(x)) {
  72. which.push(x);
  73. }
  74. }
  75. }
  76. if (which.includes('tl')) {
  77. which.splice(which.indexOf('tl'), 1);
  78. console.log(action, 'TLObjects...');
  79. if (clean) {
  80. cleanTLObjects(TLOBJECT_OUT);
  81. } else {
  82. generateTLObjects(tlobjects, layer, IMPORT_DEPTH, TLOBJECT_OUT);
  83. }
  84. }
  85. if (which.includes('errors')) {
  86. which.splice(which.indexOf('errors'), 1);
  87. console.log(action, 'RPCErrors...');
  88. if (clean) {
  89. if (fs.statSync(ERRORS_OUT).isFile()) {
  90. fs.unlinkSync(ERRORS_OUT);
  91. }
  92. } else {
  93. const file = fs.createWriteStream(ERRORS_OUT);
  94. generateErrors(errors, file);
  95. }
  96. }
  97. if (which.includes('docs')) {
  98. which.splice(which.indexOf('docs'), 1);
  99. console.log(action, 'documentation...');
  100. if (clean) {
  101. if (fs.statSync(DOCS_OUT)) {
  102. fs.rmdirSync(DOCS_OUT);
  103. }
  104. } else {
  105. const tmp = new TempWorkDir(DOCS_OUT).open();
  106. generateDocs(tlobjects, methods, layer, DOCS_IN_RES);
  107. tmp.close();
  108. }
  109. }
  110. if (which.includes('json')) {
  111. which.splice(which.indexOf('json'), 1);
  112. console.log(action, 'JSON schema...');
  113. const jsonFiles = TLOBJECT_IN_TLS.map(
  114. x => x.slice(0, x.lastIndexOf('.')) + '.json'
  115. );
  116. if (clean) {
  117. for (const file of jsonFiles) {
  118. if (fs.statSync(file).isFile()) {
  119. fs.unlinkSync(file);
  120. }
  121. }
  122. } else {
  123. const genJson = (fin, fout) => {
  124. const meths = [];
  125. const constructors = [];
  126. for (const tl of parseTl(fin, layer)) {
  127. if (tl.isFunction) {
  128. meths.push(tl.toJson());
  129. } else {
  130. constructors.push(tl.toJson());
  131. }
  132. }
  133. const what = { constructors, methods };
  134. fs.writeFileSync(fout, JSON.stringify(what, null, 2));
  135. };
  136. for (let i = 0; i < TLOBJECT_IN_TLS.length; i++) {
  137. const fin = TLOBJECT_IN_TLS[i];
  138. const fout = jsonFiles[i];
  139. genJson(fin, fout);
  140. }
  141. }
  142. }
  143. if (which.length) {
  144. console.log('The following items were not understood:', which);
  145. console.log(' Consider using only "tl", "errors" and/or "docs".');
  146. console.log(
  147. ' Using only "clean" will clean them. "all" to act on all.'
  148. );
  149. console.log(' For instance "gen tl errors".');
  150. }
  151. };
  152. const { argv } = process;
  153. if (argv.length > 2 && argv[2] === 'gen') {
  154. generate(argv.slice(3));
  155. }