| prompt.js | |
|---|---|
| /*
 * prompt.js: Simple prompt for prompting information from the command line 
 *
 * (C) 2010, Nodejitsu Inc.
 *
 */
var events = require('events'),
    async = require('async'),
    colors = require('colors'),
    winston = require('winston'),
    stdio = process.binding('stdio'); | |
| @private function capitalize (str)str {string} String to capitalizeCapitalizes the string supplied. | function capitalize(str) {
  return str.charAt(0).toUpperCase() + str.slice(1);
}
var prompt = module.exports = Object.create(events.EventEmitter.prototype);
var logger = prompt.logger = new winston.Logger({
  transports: [
    new (winston.transports.Console)()
  ]
});
    
prompt.started    = false;
prompt.paused     = false;
prompt.allowEmpty = false; 
var stdin, stdout; | 
| Create an empty object for the properties 
known to  | prompt.properties = {}; | 
| Setup the default winston logger to use 
the  | logger.cli(); | 
| function start (options)@options {Object} Optional Options to consume by promptStarts the prompt by listening to the appropriate events on  | prompt.start = function (options) {
  if (prompt.started) {
    return;
  }
  
  options = options        || {};
  stdin   = options.stdin  || process.openStdin();
  stdout  = options.stdout || process.stdout;
  
  prompt.allowEmpty = options.allowEmpty || false;
  
  process.on('SIGINT', function () {
    stdout.write('\n');
    process.exit(1);
  })
  
  prompt.emit('start');
  prompt.started = true;
  return prompt;
}; | 
| function pause ()Pauses input coming in from stdin | prompt.pause = function () {
  if (!prompt.started || prompt.paused) {
    return;
  }
  
  stdin.pause();
  prompt.emit('pause');
  prompt.paused = true;
  return prompt;
}; | 
| function resume ()Resumes input coming in from stdin | prompt.resume = function () {
  if (!prompt.started || !prompt.paused) {
    return;
  }
  
  stdin.resume();
  prompt.emit('resume');
  prompt.paused = false;
  return prompt;
}; | 
| function get (msg, [validator,] callback)@msg {Array|Object|string} Set of variables to get input for.@callback {function} Continuation to pass control to when complete.Gets input from the user via stdin for the specified message(s)  | prompt.get = function (msg, callback) {
  var vars = !Array.isArray(msg) ? [msg] : msg,
      result = {};
  
  vars = vars.map(function (v) {
    if (typeof v === 'string') {
      v = v.toLowerCase();
    }
    
    return prompt.properties[v] || v;
  });
  
  function get(target, next) {
    prompt.getInput(target, function (err, line) {
      if (err) {
        return next(err);
      }
      
      var name = target.name || target;
      result[name] = line;
      next();
    });
  }
  
  async.forEachSeries(vars, get, function (err) {
    return err ? callback(err) : callback(null, result);
  });
  
  return prompt;
}; | 
| function getInput (msg, validator, callback)@msg {Object|string} Variable to get input for.@callback {function} Continuation to pass control to when complete.Gets input from the user via stdin for the specified message  | prompt.getInput = function (prop, callback) {
  var name   = prop.message || prop.name || prop,
      raw    = ['prompt', ': ' + name.grey, ': '.grey],
      read   = prop.hidden ? prompt.readLineHidden : prompt.readLine,
      length, msg;
  
  if (prop.default) {
    raw.splice(2, -1, ' (' + prop.default + ')');
  }
   | 
| Calculate the raw length and colorize the prompt |   length = raw.join('').length;
  raw[0] = raw[0];
  msg = raw.join('');
  
  if (prop.help) {
    prop.help.forEach(function (line) {
      logger.help(line);
    });
  }
  
  stdout.write(msg); 
  prompt.emit('prompt', prop);
  
  read.call(null, function (err, line) {
    if (err) {
      return callback(err);
    }
  
    if (!line || line === '') {
      line = prop.default || line;
    }
    
    if (prop.validator || prop.empty === false) {
      var valid;
      
      if (prop.validator) {
        valid = prop.validator.test 
         ? prop.validator.test(line)
         : prop.validator(line);
      }
      
      if (prop.empty === false && valid) {
        valid = line.length > 0;
        prop.warning = prop.warning || 'You must supply a value.';
      }
      
      if (!valid) {
        logger.error('Invalid input for ' + name.grey);
        if (prop.warning) {
          logger.error(prop.warning);
        }
        
        prompt.emit('invalid', prop, line);
        return prompt.getInput(prop, callback);
      }
    }
        
    logger.input(line.yellow);
    callback(null, line);
  });
  return prompt;
}; | 
| function addProperties (obj, properties, callback)@obj {Object} Object to add properties to@properties {Array} List of properties to get values for@callback {function} Continuation to pass control to when complete.Prompts the user for values each of the  | prompt.addProperties = function (obj, properties, callback) {
  properties = properties.filter(function (prop) {
    return typeof obj[prop] === 'undefined';
  });
  
  if (properties.length === 0) {
    return callback(obj);
  }
  
  prompt.get(properties, function (err, results) {
    if (err) {
      return callback(err);
    }
    else if (!results) {
      return callback(null, obj);
    }
    
    function putNested (obj, path, value) {
      var last = obj, key; 
      
      while (path.length > 1) {
        key = path.shift();
        if (!last[key]) {
          last[key] = {};
        }
        
        last = last[key];
      }
      
      last[path.shift()] = value;
    }
    
    Object.keys(results).forEach(function (key) {
      putNested(obj, key.split('.'), results[key]);
    });
    
    callback(null, obj);
  });
  
  return prompt;
}; | 
| function readLine (callback)@callback {function} Continuation to respond to when completeGets a single line of input from the user. | prompt.readLine = function (callback) {
  var value = '', buffer = '';
  prompt.resume();
  stdin.setEncoding('utf8');
  stdin.on('error', callback);
  stdin.on('data', function data (chunk) {
    value += buffer + chunk;
    buffer = '';
    value = value.replace(/\r/g, '');
    if (value.indexOf('\n') !== -1) {
      if (value !== '\n') {
        value = value.replace(/^\n+/, '');
      }
      
      buffer = value.substr(value.indexOf('\n'));
      val = value.substr(0, value.indexOf('\n'));
      prompt.pause();
      stdin.removeListener('data', data);
      stdin.removeListener('error', callback);
      value = value.trim();
      callback(null, value);
    }
  });
  
  return prompt;
}; | 
| function readLineHidden (callback)@callback {function} Continuation to respond to when completeGets a single line of hidden input (i.e.  | prompt.readLineHidden = function (callback) {
  var value = '', buffer = '';
  stdio.setRawMode(true);
  prompt.resume();
  stdin.on('error', callback);
  stdin.on('data', function data (c) {
    c = '' + c;
    switch (c) {
      case '\n': case '\r': case '\r\n': case '\u0004':
        stdio.setRawMode(false);
        stdin.removeListener('data', data);
        stdin.removeListener('error', callback);
        value = value.trim();
        stdout.write('\n');
        stdout.flush();
        prompt.pause();
        return callback(null, value)
      case '\u0003': case '\0':
        stdout.write('\n');
        process.exit(1);
        break;
      default:
        value += buffer + c
        buffer = '';
        break;
    }
  });
  
  return prompt;
};
 |