index.js 5.0 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. }