Repositorio del curso CCOM4030 el semestre B91 del proyecto Artesanías con el Instituto de Cultura

promzard.js 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. module.exports = promzard
  2. promzard.PromZard = PromZard
  3. var fs = require('fs')
  4. var vm = require('vm')
  5. var util = require('util')
  6. var files = {}
  7. var crypto = require('crypto')
  8. var EventEmitter = require('events').EventEmitter
  9. var read = require('read')
  10. var Module = require('module').Module
  11. var path = require('path')
  12. function promzard (file, ctx, cb) {
  13. if (typeof ctx === 'function') cb = ctx, ctx = null;
  14. if (!ctx) ctx = {};
  15. var pz = new PromZard(file, ctx)
  16. pz.on('error', cb)
  17. pz.on('data', function (data) {
  18. cb(null, data)
  19. })
  20. }
  21. promzard.fromBuffer = function (buf, ctx, cb) {
  22. var filename = 0
  23. do {
  24. filename = '\0' + Math.random();
  25. } while (files[filename])
  26. files[filename] = buf
  27. var ret = promzard(filename, ctx, cb)
  28. delete files[filename]
  29. return ret
  30. }
  31. function PromZard (file, ctx) {
  32. if (!(this instanceof PromZard))
  33. return new PromZard(file, ctx)
  34. EventEmitter.call(this)
  35. this.file = file
  36. this.ctx = ctx
  37. this.unique = crypto.randomBytes(8).toString('hex')
  38. this.load()
  39. }
  40. PromZard.prototype = Object.create(
  41. EventEmitter.prototype,
  42. { constructor: {
  43. value: PromZard,
  44. readable: true,
  45. configurable: true,
  46. writable: true,
  47. enumerable: false } } )
  48. PromZard.prototype.load = function () {
  49. if (files[this.file])
  50. return this.loaded()
  51. fs.readFile(this.file, 'utf8', function (er, d) {
  52. if (er && this.backupFile) {
  53. this.file = this.backupFile
  54. delete this.backupFile
  55. return this.load()
  56. }
  57. if (er)
  58. return this.emit('error', this.error = er)
  59. files[this.file] = d
  60. this.loaded()
  61. }.bind(this))
  62. }
  63. PromZard.prototype.loaded = function () {
  64. this.ctx.prompt = this.makePrompt()
  65. this.ctx.__filename = this.file
  66. this.ctx.__dirname = path.dirname(this.file)
  67. this.ctx.__basename = path.basename(this.file)
  68. var mod = this.ctx.module = this.makeModule()
  69. this.ctx.require = function (path) {
  70. return mod.require(path)
  71. }
  72. this.ctx.require.resolve = function(path) {
  73. return Module._resolveFilename(path, mod);
  74. }
  75. this.ctx.exports = mod.exports
  76. this.script = this.wrap(files[this.file])
  77. var fn = vm.runInThisContext(this.script, this.file)
  78. var args = Object.keys(this.ctx).map(function (k) {
  79. return this.ctx[k]
  80. }.bind(this))
  81. try { var res = fn.apply(this.ctx, args) }
  82. catch (er) { this.emit('error', er) }
  83. if (res &&
  84. typeof res === 'object' &&
  85. exports === mod.exports &&
  86. Object.keys(exports).length === 1) {
  87. this.result = res
  88. } else {
  89. this.result = mod.exports
  90. }
  91. this.walk()
  92. }
  93. PromZard.prototype.makeModule = function () {
  94. var mod = new Module(this.file, module)
  95. mod.loaded = true
  96. mod.filename = this.file
  97. mod.id = this.file
  98. mod.paths = Module._nodeModulePaths(path.dirname(this.file))
  99. return mod
  100. }
  101. PromZard.prototype.wrap = function (body) {
  102. var s = '(function( %s ) { %s\n })'
  103. var args = Object.keys(this.ctx).join(', ')
  104. return util.format(s, args, body)
  105. }
  106. PromZard.prototype.makePrompt = function () {
  107. this.prompts = []
  108. return prompt.bind(this)
  109. function prompt () {
  110. var p, d, t
  111. for (var i = 0; i < arguments.length; i++) {
  112. var a = arguments[i]
  113. if (typeof a === 'string' && p)
  114. d = a
  115. else if (typeof a === 'string')
  116. p = a
  117. else if (typeof a === 'function')
  118. t = a
  119. else if (a && typeof a === 'object') {
  120. p = a.prompt || p
  121. d = a.default || d
  122. t = a.transform || t
  123. }
  124. }
  125. try { return this.unique + '-' + this.prompts.length }
  126. finally { this.prompts.push([p, d, t]) }
  127. }
  128. }
  129. PromZard.prototype.walk = function (o, cb) {
  130. o = o || this.result
  131. cb = cb || function (er, res) {
  132. if (er)
  133. return this.emit('error', this.error = er)
  134. this.result = res
  135. return this.emit('data', res)
  136. }
  137. cb = cb.bind(this)
  138. var keys = Object.keys(o)
  139. var i = 0
  140. var len = keys.length
  141. L.call(this)
  142. function L () {
  143. if (this.error)
  144. return
  145. while (i < len) {
  146. var k = keys[i]
  147. var v = o[k]
  148. i++
  149. if (v && typeof v === 'object') {
  150. return this.walk(v, function (er, res) {
  151. if (er) return cb(er)
  152. o[k] = res
  153. L.call(this)
  154. }.bind(this))
  155. } else if (v &&
  156. typeof v === 'string' &&
  157. v.indexOf(this.unique) === 0) {
  158. var n = +v.substr(this.unique.length + 1)
  159. var prompt = this.prompts[n]
  160. if (isNaN(n) || !prompt)
  161. continue
  162. // default to the key
  163. if (undefined === prompt[0])
  164. prompt[0] = k
  165. // default to the ctx value, if there is one
  166. if (undefined === prompt[1])
  167. prompt[1] = this.ctx[k]
  168. return this.prompt(prompt, function (er, res) {
  169. if (er) {
  170. if (!er.notValid) {
  171. return this.emit('error', this.error = er);
  172. }
  173. console.log(er.message)
  174. i --
  175. return L.call(this)
  176. }
  177. o[k] = res
  178. L.call(this)
  179. }.bind(this))
  180. } else if (typeof v === 'function') {
  181. try { return v.call(this.ctx, function (er, res) {
  182. if (er)
  183. return this.emit('error', this.error = er)
  184. o[k] = res
  185. // back up so that we process this one again.
  186. // this is because it might return a prompt() call in the cb.
  187. i --
  188. L.call(this)
  189. }.bind(this)) }
  190. catch (er) { this.emit('error', er) }
  191. }
  192. }
  193. // made it to the end of the loop, maybe
  194. if (i >= len)
  195. return cb(null, o)
  196. }
  197. }
  198. PromZard.prototype.prompt = function (pdt, cb) {
  199. var prompt = pdt[0]
  200. var def = pdt[1]
  201. var tx = pdt[2]
  202. if (tx) {
  203. cb = function (cb) { return function (er, data) {
  204. try {
  205. var res = tx(data)
  206. if (!er && res instanceof Error && !!res.notValid) {
  207. return cb(res, null)
  208. }
  209. return cb(er, res)
  210. }
  211. catch (er) { this.emit('error', er) }
  212. }}(cb).bind(this)
  213. }
  214. read({ prompt: prompt + ':' , default: def }, cb)
  215. }