generate.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. #!/usr/bin/env node
  2. var fs = require('fs');
  3. var path = require('path');
  4. // These are the node packages we are going to wrap.
  5. var packages = {
  6. assert: { skip: true },
  7. async_hooks: { optional: true, skip: true },
  8. buffer: { skip: true },
  9. child_process: {
  10. exec: { promisify: true, returnsObject: true, args: 1, cb:['stdout','stderr'] },
  11. execFile: { promisify: true, returnsObject: true, args: 1, cb:['stdout','stderr'] },
  12. fork: { promisify: false },
  13. spawn: { promisify: false },
  14. },
  15. cluster: {
  16. disconnect: { promisify: true, args: 0 },
  17. },
  18. console: { skip: true },
  19. crypto: {
  20. DEFAULT_ENCODING: { constant: false },
  21. pseudoRandomBytes: { promisify: true, syncIfNoCallback: true, args: 1 },
  22. randomBytes: { promisify: true, syncIfNoCallback: true, args: 1 },
  23. randomFill: { args: 1 },
  24. },
  25. dns: {
  26. // XXX: Resolver could be wrapped...
  27. ADNAME: { skip: true },
  28. lookup: { promisify: true, args: 1 },
  29. lookupService: { promisify: true, args: 2, cb:['hostname','service'] },
  30. resolve: { promisify: true, args: 1 },
  31. resolve4: { promisify: true, args: 1 },
  32. resolve6: { promisify: true, args: 1 },
  33. resolveAny: { promisify: true, args: 1 },
  34. resolveCname: { promisify: true, args: 1 },
  35. resolveMx: { promisify: true, args: 1 },
  36. resolveNaptr: { promisify: true, args: 1 },
  37. resolveNs: { promisify: true, args: 1 },
  38. resolvePtr: { promisify: true, args: 1 },
  39. resolveSoa: { promisify: true, args: 1 },
  40. resolveSrv: { promisify: true, args: 1 },
  41. resolveTxt: { promisify: true, args: 1 },
  42. reverse: { promisify: true, args: 1 },
  43. },
  44. domain: {
  45. // XXX Domain#bind and Domain#intercept should be promisified
  46. },
  47. events: {
  48. skip: true,
  49. },
  50. fs: {
  51. access: { args: 1 },
  52. appendFile: { args: 2 },
  53. copyFile: { args: 2 },
  54. exists: { promisify: true, noError: true },
  55. mkdir: { args: 1 },
  56. mkdtemp: { args: 1 },
  57. open: { args: 2 },
  58. read: { cb: ['read', 'buffer'] },
  59. readdir: { args: 1 },
  60. readlink: { args: 1 },
  61. readFile: { args: 1 },
  62. realpath: { args: 1 },
  63. symlink: { args: 2 },
  64. write: { cb: ['written', 'buffer'] },
  65. writeFile: { args: 2 },
  66. },
  67. http: {
  68. STATUS_CODES: { constant: true },
  69. // XXX ClientRequest#setTimeout should be promisified
  70. // XXX IncomingMessage#setTimeout should be promisified
  71. // XXX Server#listen, Server#close, and Server#setTimeout
  72. // should be promisified
  73. // XXX ServerResponse#setTimeout should be promisified
  74. request: { promisify: true, returnsObject: true, args: 1 },
  75. get: { promisify: true, returnsObject: true, args: 1 },
  76. },
  77. http2: {
  78. optional: true,
  79. },
  80. https: {
  81. // XXX Server#listen, Server#close, and Server#setTimeout
  82. // should be promisified
  83. request: { promisify: true, returnsObject: true, args: 1 },
  84. get: { promisify: true, returnsObject: true, args: 1 },
  85. },
  86. inspector: {
  87. optional: true,
  88. skip: true,
  89. },
  90. net: {
  91. // XXX Server#listen, Server#close, Server#getConnections
  92. // should be promisified
  93. // XXX Socket#write, Socket#setTimeout should be promisified
  94. },
  95. os: { skip: true },
  96. path: { skip: true },
  97. perf_hooks: { optional: true, skip: true },
  98. process: {
  99. nextTick: { promisify: true, args: 0 }
  100. },
  101. punycode: { optional: true, skip: true },
  102. querystring: { skip: true },
  103. readline: {
  104. // XXX Interface#question should be promisified
  105. },
  106. repl: { skip: true },
  107. stream: {
  108. super_: { skip: true },
  109. // XXX Writable#write and Writable#end should be promisified
  110. // XXX same for Duplex and Transform? inheritance unclear.
  111. // what about _read/_write/_transform/_flush for implementers?
  112. },
  113. string_decoder: { skip: true },
  114. timers: {
  115. setImmediate: { promisify: true, callbackIsFirstArg: true, noError: true },
  116. setTimeout: { promisify: true, callbackIsFirstArg: true, noError: true },
  117. },
  118. tls: {
  119. connect: { promisify: true, returnsObject: true, args: 1 },
  120. createServer: { promisify: true, returnsObject: true, args: 1 },
  121. },
  122. tty: {
  123. skip: true
  124. // should tty.ReadStream and tty.WriteStream be promisified?
  125. // (process.stdin / process.stdout)
  126. },
  127. dgram: {
  128. // note that createSocket takes a listener, not a callback
  129. // XXX Socket#send and Socket#bind should be promisified
  130. },
  131. url: { skip: true },
  132. util: {
  133. pump: { promisify: true, args: 2 }
  134. },
  135. v8: { optional: true, skip: true },
  136. vm: { skip: true },
  137. zlib: {
  138. codes: { constant: true },
  139. deflate: { promisify: true, args: 1 },
  140. deflateRaw: { promisify: true, args: 1 },
  141. gzip: { promisify: true, args: 1 },
  142. gunzip: { promisify: true, args: 1 },
  143. inflate: { promisify: true, args: 1 },
  144. inflateRaw: { promisify: true, args: 1 },
  145. unzip: { promisify: true, args: 1 },
  146. },
  147. };
  148. var sorted = function(arr) {
  149. var s = arr.slice(0);
  150. s.sort();
  151. return s;
  152. }
  153. sorted(Object.keys(packages)).forEach(function(pkgname) {
  154. var pkgopts = packages[pkgname] || {};
  155. var script = [];
  156. var emit = function(l) { script.push(l); };
  157. var m;
  158. if (pkgname==='process') {
  159. m = process;
  160. } else if (pkgopts.optional) {
  161. // Package is not present in older versions of node.
  162. emit('var '+pkgname+' = {};');
  163. emit('try { '+pkgname+' = require("'+pkgname+'"); } catch (e) { }');
  164. m = require(pkgname);
  165. } else {
  166. emit('var '+pkgname+' = require("'+pkgname+'");');
  167. m = require(pkgname);
  168. }
  169. if (pkgopts.skip) {
  170. emit('module.exports = '+pkgname+';');
  171. } else {
  172. emit('var promisify = require("./_promisify.js");');
  173. emit('var bind = function(c, f) { return f && f.bind(c); };');
  174. emit('Object.defineProperties(module.exports, {');
  175. sorted(Object.keys(m)).forEach(function(prop) {
  176. var opts = pkgopts[prop] || {};
  177. // skip private properties
  178. if (opts.skip !== undefined ? opts.skip : /^_/.test(prop)) {
  179. emit(' //'+prop+': // skipping');
  180. return;
  181. }
  182. var out = ' '+prop+': { enumerable: true, ';
  183. // Is this a function?
  184. var caps = /^[A-Z]/.test(prop);
  185. var isFunction = typeof(m[prop]) === 'function';
  186. var isConstant = opts.constant!==undefined ? opts.constant :
  187. isFunction ?
  188. (opts.bind !== undefined ? opts.bind===false : caps) :
  189. caps;
  190. if (isConstant) {
  191. emit(out+'value: '+pkgname+'.'+prop+' },');
  192. return;
  193. }
  194. if (!isFunction) {
  195. // add getters & setters
  196. emit(out+'get: function() { return '+pkgname+'.'+prop+'; }, '+
  197. 'set: function(v) { '+pkgname+'.'+prop+' = v; } },');
  198. return;
  199. }
  200. // Is this a async function?
  201. var isAsync = (typeof(m[prop+'Sync']) === 'function');
  202. if (opts.promisify) { isAsync = true; }
  203. if (!isAsync || opts.promisify === false) {
  204. emit(out+'value: bind('+pkgname+', '+pkgname+'.'+prop+') },');
  205. return;
  206. }
  207. // OK, this is very likely an async function!
  208. // number of mandatory options (may be additional optional args)
  209. var nargs = opts.args!==undefined ? opts.args :
  210. (typeof(m[prop+'Sync']) === 'function') ?
  211. m[prop+'Sync'].length : m[prop].length;
  212. var options = {}, emitOptions = false;
  213. if (opts.cb) {
  214. options.pattern = opts.cb;
  215. emitOptions = true;
  216. }
  217. if (opts.noError) {
  218. options.noError = true;
  219. emitOptions = true;
  220. }
  221. if (opts.returnsObject) {
  222. options.returnsObject = true;
  223. emitOptions = true;
  224. }
  225. if (opts.callbackIsFirstArg) {
  226. options.callbackIsFirstArg = true;
  227. nargs = 0;
  228. emitOptions = true;
  229. }
  230. var optString = emitOptions ? ', '+JSON.stringify(options) : '';
  231. emit(out+'value: promisify('+pkgname+', '+pkgname+'.'+prop+', '+nargs+optString+') },');
  232. if (opts.syncIfNoCallback) {
  233. emit(out.replace(/:/,"Sync:")+'value: '+pkgname+'.'+prop+'.bind('+pkgname+') },');
  234. }
  235. });
  236. emit('});');
  237. }
  238. // Write out this wrapped package!
  239. fs.writeFileSync(path.join(__dirname,'..',pkgname+'.js'),
  240. script.join('\n'), 'utf-8');
  241. });