Permalink
Browse files

the code

  • Loading branch information...
1 parent e53d3d8 commit 87e4ff0de8fe4bcc5036a0f55f8247617169ab09 @isaacs isaacs committed Jun 13, 2012
Showing with 243 additions and 0 deletions.
  1. +12 −0 example/index.js
  2. +58 −0 example/substack.json
  3. +173 −0 promzard.js
View
12 example/index.js
@@ -0,0 +1,12 @@
+var pz = require('../promzard')
+
+var path = require('path')
+var file = path.resolve(__dirname, 'substack.json')
+var ctx = { basename: path.basename(path.dirname(file)) }
+
+pz(file, ctx, function (er, res) {
+ console.error('in cb', er, res)
+ if (er)
+ throw er
+ console.log(JSON.stringify(res, null, 2))
+})
View
58 example/substack.json
@@ -0,0 +1,58 @@
+{
+ "name" : basename.replace(/^node-/, ''),
+ "version" : "0.0.0",
+ "description" : (function (cb) {
+ var fs = require('fs');
+ var value;
+ try {
+ var src = fs.readFileSync('README.markdown', 'utf8');
+ value = src.split('\n').filter(function (line) {
+ return /\s+/.test(line)
+ && line.trim() !== basename.replace(/^node-/, '')
+ ;
+ })[0]
+ .trim()
+ .replace(/^./, function (c) { return c.toLowerCase() })
+ .replace(/\.$/, '')
+ ;
+ }
+ catch (e) {}
+
+ return prompt('description', value);
+ })(),
+ "main" : prompt('entry point', 'index.js'),
+ "bin" : function (cb) {
+ var path = require('path');
+ var fs = require('fs');
+ var exists = fs.exists || path.exists;
+ exists('bin/cmd.js', function (ex) {
+ var bin = {};
+ if (ex) bin[basename.replace(/^node-/, '')] = 'bin/cmd.js';
+ cb(null, bin);
+ });
+ },
+ "directories" : {
+ "example" : "example",
+ "test" : "test"
+ },
+ "dependencies" : {},
+ "devDependencies" : {
+ "tap" : "~0.2.5"
+ },
+ "scripts" : {
+ "test" : "tap test/*.js"
+ },
+ "repository" : {
+ "type" : "git",
+ "url" : "git://github.com/substack/" + basename + ".git"
+ },
+ "homepage" : "https://github.com/substack/" + basename,
+ "keywords" : prompt(function (s) { return s.split(/\s+/) }),
+ "author" : {
+ "name" : "James Halliday",
+ "email" : "mail@substack.net",
+ "url" : "http://substack.net"
+ },
+ "license" : "MIT",
+ "engine" : { "node" : ">=0.6" }
+}
View
173 promzard.js
@@ -0,0 +1,173 @@
+module.exports = promzard
+
+var fs = require('fs')
+var vm = require('vm')
+var util = require('util')
+var files = {}
+var crypto = require('crypto')
+var EventEmitter = require('events').EventEmitter
+var read = require('read')
+
+var Module = require('module').Module
+var path = require('path')
+
+function promzard (file, ctx, cb) {
+ if (typeof ctx === 'function') cb = ctx, ctx = null;
+ if (!ctx) ctx = {};
+ var pz = new PromZard(file, ctx)
+ pz.on('error', cb)
+ pz.on('data', function (data) {
+ cb(null, data)
+ })
+}
+
+function PromZard (file, ctx) {
+ if (!(this instanceof PromZard))
+ return new PromZard(file, ctx)
+ EventEmitter.call(this)
+ this.file = file
+ this.ctx = ctx
+ this.unique = crypto.randomBytes(8).toString('hex')
+ this.load()
+}
+
+PromZard.prototype = Object.create(
+ EventEmitter.prototype,
+ { constructor: {
+ value: PromZard,
+ readable: true,
+ configurable: true,
+ writable: true,
+ enumerable: false } } )
+
+PromZard.prototype.load = function () {
+ if (files[this.file])
+ return this.loaded()
+
+ fs.readFile(this.file, 'utf8', function (er, d) {
+ if (er)
+ return this.emit('error', er)
+ files[this.file] = d
+ this.loaded()
+ }.bind(this))
+}
+
+PromZard.prototype.loaded = function () {
+ this.ctx.prompt = this.makePrompt()
+ this.ctx.__filename = this.file
+ this.ctx.__dirname = path.dirname(this.file)
+ this.ctx.__basename = path.basename(this.file)
+ var mod = this.ctx.module = this.makeModule()
+ this.ctx.require = function (path) {
+ return mod.require(path)
+ }
+ this.ctx.require.resolve = function(path) {
+ return Module._resolveFilename(path, mod);
+ }
+ this.ctx.exports = mod.exports
+
+ this.script = this.wrap(files[this.file])
+ var fn = vm.runInThisContext(this.script, this.file)
+ var args = Object.keys(this.ctx).map(function (k) {
+ return this.ctx[k]
+ }.bind(this))
+ this.result = fn.apply(this.ctx, args)
+ this.walk()
+}
+
+PromZard.prototype.makeModule = function (path) {
+ var mod = new Module(path, module)
+ mod.loaded = true
+ mod.filename = this.file
+ return mod
+}
+
+PromZard.prototype.wrap = function (body) {
+ var s = '(function( %s ) { return %s\n })'
+ var args = Object.keys(this.ctx).join(',')
+ return util.format(s, args, body)
+}
+
+PromZard.prototype.makePrompt = function () {
+ this.prompts = []
+ return prompt.bind(this)
+ function prompt () {
+ var p, d, t
+ for (var i = 0; i < arguments.length; i++) {
+ var a = arguments[i]
+ if (typeof a === 'string' && p)
+ d = a
+ else if (typeof a === 'string')
+ p = a
+ else if (typeof a === 'function')
+ t = a
+ }
+
+ try { return this.unique + '-' + this.prompts.length }
+ finally { this.prompts.push([p, d, t]) }
+ }
+}
+
+PromZard.prototype.walk = function (o, cb) {
+ o = o || this.result
+ cb = cb || function (er, res) {
+ if (er)
+ return this.emit('error', er)
+ this.result = res
+ return this.emit('data', res)
+ }
+ cb = cb.bind(this)
+ var keys = Object.keys(o)
+ var i = 0
+ var len = keys.length
+
+ L.call(this)
+ function L () {
+ while (i < len) {
+ var k = keys[i]
+ var v = o[k]
+ i++
+
+ if (v && typeof v === 'object') {
+ return this.walk(v, function (er, res) {
+ if (er) return cb(er)
+ o[k] = res
+ L.call(this)
+ }.bind(this))
+ } else if (v &&
+ typeof v === 'string' &&
+ v.indexOf(this.unique) === 0) {
+ var n = +v.substr(this.unique.length + 1)
+ var prompt = this.prompts[n]
+ if (isNaN(n) || !prompt)
+ continue
+
+ // default to the key
+ if (undefined === prompt[0])
+ prompt[0] = k
+
+ return this.prompt(prompt, function (er, res) {
+ o[k] = res
+ L.call(this)
+ }.bind(this))
+ }
+ }
+ // made it to the end of the loop, maybe
+ if (i >= len)
+ return cb(null, o)
+ }
+}
+
+PromZard.prototype.prompt = function (pdt, cb) {
+ var prompt = pdt[0]
+ var def = pdt[1]
+ var tx = pdt[2]
+
+ if (tx)
+ cb = function (cb) { return function (er, data) {
+ return cb(er, data ? tx(data) : null)
+ }}(cb)
+
+ read({ prompt: prompt, default: def }, cb)
+}
+

0 comments on commit 87e4ff0

Please sign in to comment.