Comparing version 0.2.1 to 0.2.2
@@ -12,6 +12,5 @@ /* | ||
capitalize = utile.inflect.capitalize, | ||
colors = require('colors'), | ||
winston = require('winston'), | ||
read = require('read'), | ||
validate = require('revalidator').validate, | ||
tty = require('tty'); | ||
winston = require('winston'); | ||
@@ -34,2 +33,3 @@ // | ||
prompt.delimiter = ': '; | ||
prompt.colors = true; | ||
@@ -64,4 +64,2 @@ // | ||
stdin.resume && stdin.resume(); | ||
// | ||
@@ -75,2 +73,3 @@ // By default: Remember the last `10` prompt property / | ||
prompt.delimiter = options.delimiter || prompt.delimiter; | ||
prompt.colors = options.colors || prompt.colors; | ||
@@ -141,6 +140,6 @@ if (process.platform !== 'win32') { | ||
return history.filter(function (name) { | ||
return history.filter(function (pair) { | ||
return typeof pair.property === 'string' | ||
? pair.property === name | ||
: pair.property.name === name; | ||
? pair.property === search | ||
: pair.property.name === search; | ||
})[0]; | ||
@@ -150,39 +149,2 @@ }; | ||
// | ||
// ### function convert (schema) | ||
// #### @schema {Object} Schema for a property | ||
// Converts the schema into new format if it is in old format | ||
// | ||
var convert = function (schema) { | ||
var newSchema = false, | ||
newProps = Object.keys(validate.messages); | ||
newProps = newProps.concat(['description','dependencies']); | ||
for (var key in schema) { | ||
if (newProps.indexOf(key) > 0) { | ||
newSchema = true; | ||
break; | ||
} | ||
} | ||
if (!newSchema || schema.validator || | ||
schema.warning || schema.empty != null | ||
) { | ||
schema.description = schema.message; | ||
schema.message = schema.warning; | ||
schema.pattern = schema.validator; | ||
if (schema.empty != null) { | ||
schema.required = !(schema.empty); | ||
} | ||
delete schema.warning; | ||
delete schema.validator; | ||
delete schema.empty; | ||
} | ||
return schema; | ||
}; | ||
// | ||
// ### function get (msg, callback) | ||
@@ -194,40 +156,82 @@ // #### @msg {Array|Object|string} Set of variables to get input for. | ||
prompt.get = function (schema, callback) { | ||
// | ||
// Transforms a full JSON-schema into an array describing path and sub-schemas. | ||
// Used for iteration purposes. | ||
// | ||
function untangle(schema, path) { | ||
var results = []; | ||
path = path || []; | ||
iterate(schema, function get(target, next) { | ||
var path = target.path, | ||
schema = target.schema; | ||
if (schema.properties) { | ||
// | ||
// Iterate over the properties in the schema and use recursion | ||
// to process sub-properties. | ||
// | ||
Object.keys(schema.properties).forEach(function (key) { | ||
var obj = {}; | ||
obj[key] = schema.properties[key]; | ||
prompt.getInput(target, function (err, line) { | ||
if (err) { | ||
return next(err); | ||
} | ||
next(null, line); | ||
}); | ||
}, callback); | ||
// | ||
// Concat a sub-untangling to the results. | ||
// | ||
results = results.concat(untangle(obj[key], path.concat(key))); | ||
}); | ||
return prompt; | ||
// Return the results. | ||
return results; | ||
} | ||
// iterate over the values in the schema, | ||
// represented as legit single-property object sub-schemas. | ||
function iterate(schema, get, cb) { | ||
var iterator = []; | ||
// | ||
// This is a schema "leaf". | ||
// | ||
return { | ||
path: path, | ||
schema: schema | ||
}; | ||
} | ||
// We can iterate over a single string, ... | ||
if (typeof schema == 'string') { | ||
// | ||
// Iterate over the values in the schema, represented as | ||
// a legit single-property object subschemas. Accepts `schema` | ||
// of the forms: | ||
// | ||
// 'prop-name' | ||
// | ||
// ['string-name', { path: ['or-well-formed-subschema'], properties: ... }] | ||
// | ||
// { path: ['or-well-formed-subschema'], properties: ... ] } | ||
// | ||
// { properties: { 'schema-with-no-path' } } | ||
// | ||
// And transforms them all into | ||
// | ||
// { path: ['path', 'to', 'property'], properties: { path: { to: ...} } } | ||
// | ||
function iterate(schema, get, done) { | ||
var iterator = [], | ||
result = {}; | ||
if (typeof schema === 'string') { | ||
// | ||
// We can iterate over a single string. | ||
// | ||
iterator.push({ | ||
path: [ schema ], | ||
schema: {} | ||
path: [schema], | ||
schema: prompt.properties[schema.toLowerCase()] || {} | ||
}); | ||
} // ..an array of strings and/or single-prop schema and/or no-prop schema... | ||
} | ||
else if (Array.isArray(schema)) { | ||
// | ||
// An array of strings and/or single-prop schema and/or no-prop schema. | ||
// | ||
iterator = schema.map(function (element) { | ||
if (typeof element == 'string') { | ||
if (typeof element === 'string') { | ||
return { | ||
path: [ element ], | ||
path: [element], | ||
schema: prompt.properties[element.toLowerCase()] || {} | ||
} | ||
}; | ||
} | ||
else if (element.properties) { | ||
return { | ||
path: [ Object.keys(element.properties)[0] ], | ||
path: [Object.keys(element.properties)[0]], | ||
schema: element.properties[Object.keys(element.properties)[0]] | ||
@@ -241,3 +245,3 @@ }; | ||
return { | ||
path: [ element.name || 'question' ], | ||
path: [element.name || 'question'], | ||
schema: element | ||
@@ -247,18 +251,23 @@ }; | ||
}); | ||
} //..or a complete schema... | ||
} | ||
else if (schema.properties) { | ||
// `untangle` is defined later. | ||
// | ||
// Or a complete schema `untangle` it for use. | ||
// | ||
iterator = untangle(schema); | ||
} //...or a partial schema and path. TODO: Evaluate need for this option. | ||
} | ||
else { | ||
// | ||
// Or a partial schema and path. | ||
// TODO: Evaluate need for this option. | ||
// | ||
iterator = [{ | ||
schema: schema.schema ? schema.schema : schema, | ||
path: schema.path || [ schema.name || 'question' ] | ||
path: schema.path || [schema.name || 'question'] | ||
}]; | ||
} | ||
var result = {}; | ||
// | ||
// Now, iterate and assemble the result. | ||
// | ||
async.forEachSeries(iterator, function (branch, next) { | ||
@@ -270,15 +279,10 @@ get(branch, function assembler(err, line) { | ||
result = attach(result, build(branch.path, line)); | ||
next(); | ||
function build(path, line) { | ||
var o = {}; | ||
var obj = {}; | ||
if (path.length) { | ||
o[path[0]] = build(path.slice(1), line); | ||
return o; | ||
obj[path[0]] = build(path.slice(1), line); | ||
return obj; | ||
} | ||
else { | ||
return line; | ||
} | ||
return line; | ||
} | ||
@@ -288,51 +292,32 @@ | ||
var keys; | ||
if (attr instanceof Object) { | ||
keys = Object.keys(attr); | ||
if (keys.length) { | ||
if (!obj[keys[0]]) { | ||
obj[keys[0]] = {}; | ||
} | ||
obj[keys[0]] = attach(obj[keys[0]], attr[keys[0]]); | ||
if (typeof attr !== 'object') { | ||
return attr; | ||
} | ||
keys = Object.keys(attr); | ||
if (keys.length) { | ||
if (!obj[keys[0]]) { | ||
obj[keys[0]] = {}; | ||
} | ||
return obj; | ||
obj[keys[0]] = attach(obj[keys[0]], attr[keys[0]]); | ||
} | ||
return attr; | ||
return obj; | ||
} | ||
result = attach(result, build(branch.path, line)); | ||
next(); | ||
}); | ||
}, function (err) { | ||
return err ? cb(err) : cb(null, result); | ||
return err ? done(err) : done(null, result); | ||
}); | ||
} | ||
iterate(schema, function get(target, next) { | ||
prompt.getInput(target, function (err, line) { | ||
return err ? next(err) : next(null, line); | ||
}); | ||
}, callback); | ||
// Transforms a full JSON-schema into an array describing path and sub-schemas. | ||
// Used for iteration purposes. | ||
function untangle(schema, path) { | ||
var results = []; | ||
path = path || []; | ||
if (schema.properties) { | ||
// Iterate over the properties in the schema and use recursion | ||
// to process sub-properties. | ||
Object.keys(schema.properties).forEach(function (k) { | ||
var o = {}; | ||
o[k] = schema.properties[k]; | ||
// Concat a sub-untangling to the results. | ||
results = results.concat(untangle(o[k], path.concat(k))); | ||
}); | ||
// Return the results. | ||
return results; | ||
} | ||
else { | ||
// This is a schema "leaf." | ||
return { | ||
path: path, | ||
schema: schema | ||
}; | ||
} | ||
} | ||
} | ||
return prompt; | ||
}; | ||
@@ -349,9 +334,10 @@ | ||
// An object may have the following properties: | ||
// { | ||
// description: 'yes/no' // message to prompt user | ||
// pattern: /^[yntf]{1}/i // optional - regex defining acceptable responses | ||
// yes: /^[yt]{1}/i // optional - regex defining `affirmative` responses | ||
// message: 'yes/no' // optional - message to display for invalid responses | ||
// } | ||
// | ||
// { | ||
// description: 'yes/no' // message to prompt user | ||
// pattern: /^[yntf]{1}/i // optional - regex defining acceptable responses | ||
// yes: /^[yt]{1}/i // optional - regex defining `affirmative` responses | ||
// message: 'yes/no' // optional - message to display for invalid responses | ||
// } | ||
// | ||
prompt.confirm = function (msg, callback) { | ||
@@ -375,6 +361,6 @@ var vars = !Array.isArray(msg) ? [msg] : msg, | ||
} | ||
async.rejectSeries(vars, confirm, function(result) { | ||
callback(null, result.length===0); | ||
}); | ||
}; | ||
@@ -391,19 +377,44 @@ | ||
storedSchema = prompt.properties[propName.toLowerCase()], | ||
delim = prompt.delimiter, raw, | ||
name, read, defaultLine, length, msg, valid, against; | ||
delim = prompt.delimiter, | ||
defaultLine, | ||
against, | ||
hidden, | ||
length, | ||
valid, | ||
name, | ||
raw, | ||
msg; | ||
if ( | ||
schema instanceof Object && !Object.keys(schema).length && | ||
typeof storedSchema !== 'undefined' | ||
) { | ||
// | ||
// Handle overrides here. | ||
// TODO: Make overrides nestable | ||
// | ||
if (prompt.override && prompt.override[propName]) { | ||
return callback(null, prompt.override[propName]); | ||
} | ||
// | ||
// If there is a stored schema for `propName` in `propmpt.properties` | ||
// then use it. | ||
// | ||
if (schema instanceof Object && !Object.keys(schema).length && | ||
typeof storedSchema !== 'undefined') { | ||
schema = storedSchema; | ||
} | ||
// | ||
// Build a proper validation schema if we just have a string | ||
// and no `storedSchema`. | ||
// | ||
if (typeof prop === 'string' && !storedSchema) { | ||
schema = {}; | ||
} | ||
schema = convert(schema); | ||
defaultLine = schema.default; | ||
name = prop.description || schema.description || propName; | ||
read = (schema.hidden ? prompt.readLineHidden : prompt.readLine); | ||
raw = [prompt.message, delim + name.grey, delim.grey]; | ||
raw = prompt.colors | ||
? [prompt.message, delim + name.grey, delim.grey] | ||
: [prompt.message, delim + name, delim]; | ||
defaultLine = schema.default; | ||
prop = { | ||
@@ -414,32 +425,18 @@ schema: schema, | ||
// Handle overrides here. | ||
// TODO: Make overrides nestable | ||
if (prompt.override && prompt.override[propName]) { | ||
return callback (null, prompt.override[propName]) | ||
} | ||
// Build a proper validation schema if we just have a string | ||
if (typeof prop == 'string') { | ||
schema = {}; | ||
} | ||
// TODO: Isn't this broken? Maybe? | ||
// | ||
// If the schema has no `properties` value then set | ||
// it to an object containing the current schema | ||
// for `propName`. | ||
// | ||
if (!schema.properties) { | ||
schema = (function () { | ||
var o = { | ||
properties: {} | ||
}; | ||
o.properties[propName] = schema; | ||
return o; | ||
var obj = { properties: {} }; | ||
obj.properties[propName] = schema; | ||
return obj; | ||
})(); | ||
} | ||
// Show the default in the prompt (this is correct) | ||
if (defaultLine) { | ||
raw.splice(2, -1, ' (' + defaultLine + ')'); | ||
} | ||
// | ||
// Calculate the raw length and colorize the prompt | ||
// | ||
length = raw.join('').length; | ||
@@ -455,9 +452,17 @@ raw[0] = raw[0]; | ||
// Write the message, emit a "prompting" event | ||
// TODO: Find prompt.on's | ||
stdout.write(msg); | ||
prompt.emit('prompt', schema); | ||
// | ||
// Emit a "prompting" event | ||
// | ||
prompt.emit('prompt', prop); | ||
// | ||
// Make the actual read | ||
read.call(null, function (err, line) { | ||
// | ||
read({ | ||
prompt: msg, | ||
silent: prop.schema && prop.schema.hidden, | ||
default: defaultLine || null, | ||
stdin: stdin, | ||
stdout: stdout | ||
}, function (err, line) { | ||
if (err) { | ||
@@ -467,11 +472,10 @@ return callback(err); | ||
var valid, | ||
against = {}; | ||
var against = {}, | ||
valid; | ||
// Apply defaults. This is cool. | ||
if (!line || line === '') { | ||
line = defaultLine || line; | ||
if (typeof line !== 'string') { | ||
line = ''; | ||
} | ||
if (line && !(line === '')) { | ||
if (line && line !== '') { | ||
against[propName] = line; | ||
@@ -481,11 +485,13 @@ } | ||
// Validate. | ||
try { | ||
valid = validate(against, schema); | ||
} | ||
catch (err) { | ||
return callback(err); | ||
} | ||
try { valid = validate(against, schema) } | ||
catch (err) { return callback(err) } | ||
if (!valid.valid) { | ||
logger.error('Invalid input for ' + name.grey); | ||
if (prompt.colors) { | ||
logger.error('Invalid input for ' + name.grey); | ||
} | ||
else { | ||
logger.error('Invalid input for ' + name); | ||
} | ||
if (prop.schema.message) { | ||
@@ -561,88 +567,2 @@ logger.error(prop.schema.message); | ||
// | ||
// ### function readLine (callback) | ||
// #### @callback {function} Continuation to respond to when complete | ||
// Gets 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')); | ||
value = 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 complete | ||
// Gets a single line of hidden input (i.e. `rawMode = true`) from the user. | ||
// | ||
prompt.readLineHidden = function (callback) { | ||
var value = ''; | ||
function raw(mode) { | ||
var setRawMode = stdin.setRawMode || tty.setRawMode; | ||
setRawMode.call(stdin, mode); | ||
} | ||
// | ||
// Ignore errors from `.setRawMode()` so that `prompt` can | ||
// be scripted in child processes. | ||
// | ||
try { raw(true) } | ||
catch (ex) { } | ||
prompt.resume(); | ||
stdin.on('error', callback); | ||
stdin.on('data', function data (line) { | ||
line = line + ''; | ||
for(var i = 0; i < line.length; i++) { | ||
var c = line[i]; | ||
switch (c) { | ||
case '\n': case '\r': case '\r\n': case '\u0004': | ||
try { raw(false) } | ||
catch (ex) { } | ||
stdin.removeListener('data', data); | ||
stdin.removeListener('error', callback); | ||
value = value.trim(); | ||
stdout.write('\n'); | ||
stdout.flush && stdout.flush(); | ||
prompt.pause(); | ||
return callback(null, value); | ||
case '\x7f': case'\x08': | ||
value = value.slice(0,-1); | ||
break; | ||
case '\u0003': case '\0': | ||
stdout.write('\n'); | ||
process.exit(1); | ||
break; | ||
default: | ||
value = value + c; | ||
break; | ||
} | ||
} | ||
}); | ||
return prompt; | ||
}; | ||
// | ||
// ### @private function _remember (property, value) | ||
@@ -669,1 +589,37 @@ // #### @property {Object|string} Property that the value is in response to. | ||
}; | ||
// | ||
// ### @private function convert (schema) | ||
// #### @schema {Object} Schema for a property | ||
// Converts the schema into new format if it is in old format | ||
// | ||
function convert(schema) { | ||
var newProps = Object.keys(validate.messages), | ||
newSchema = false, | ||
key; | ||
newProps = newProps.concat(['description', 'dependencies']); | ||
for (key in schema) { | ||
if (newProps.indexOf(key) > 0) { | ||
newSchema = true; | ||
break; | ||
} | ||
} | ||
if (!newSchema || schema.validator || schema.warning || typeof schema.empty !== 'undefined') { | ||
schema.description = schema.message; | ||
schema.message = schema.warning; | ||
schema.pattern = schema.validator; | ||
if (typeof schema.empty !== 'undefined') { | ||
schema.required = !(schema.empty); | ||
} | ||
delete schema.warning; | ||
delete schema.validator; | ||
delete schema.empty; | ||
} | ||
return schema; | ||
} |
{ | ||
"name": "prompt", | ||
"description": "A beautiful command-line prompt for node.js", | ||
"version": "0.2.1", | ||
"version": "0.2.2", | ||
"author": "Nodejitsu Inc. <info@nodejitsu.com>", | ||
@@ -15,7 +15,7 @@ "maintainers": [ | ||
"dependencies": { | ||
"pkginfo": "0.x.x", | ||
"read": "https://github.com/indexzero/read/tarball/refactor-optional-streams", | ||
"revalidator": "0.1.x", | ||
"utile": "0.1.x", | ||
"colors": "0.x.x", | ||
"pkginfo": "0.x.x", | ||
"winston": "0.6.x", | ||
"revalidator": "0.1.x" | ||
"winston": "0.6.x" | ||
}, | ||
@@ -31,5 +31,5 @@ "devDependencies": { | ||
"engines": { | ||
"node": ">= 0.4.0" | ||
"node": ">= 0.6.6" | ||
} | ||
} | ||
315
README.md
@@ -11,14 +11,2 @@ # prompt [![Build Status](https://secure.travis-ci.org/flatiron/prompt.png)](http://travis-ci.org/flatiron/prompt) | ||
## Installation | ||
### Installing npm (node package manager) | ||
``` | ||
curl http://npmjs.org/install.sh | sh | ||
``` | ||
### Installing prompt | ||
``` | ||
[sudo] npm install prompt | ||
``` | ||
## Usage | ||
@@ -31,20 +19,20 @@ Using prompt is relatively straight forward. There are two core methods you should be aware of: `prompt.get()` and `prompt.addProperties()`. There methods take strings representing property names in addition to objects for complex property validation (and more). There are a number of [examples][0] that you should examine for detailed usage. | ||
``` js | ||
var prompt = require('prompt'); | ||
var prompt = require('prompt'); | ||
// | ||
// Start the prompt | ||
// | ||
prompt.start(); | ||
// | ||
// Start the prompt | ||
// | ||
prompt.start(); | ||
// | ||
// Get two properties from the user: username and email | ||
// | ||
prompt.get(['username', 'email'], function (err, result) { | ||
// | ||
// Log the results. | ||
// Get two properties from the user: username and email | ||
// | ||
console.log('Command-line input received:'); | ||
console.log(' username: ' + result.username); | ||
console.log(' email: ' + result.email); | ||
}) | ||
prompt.get(['username', 'email'], function (err, result) { | ||
// | ||
// Log the results. | ||
// | ||
console.log('Command-line input received:'); | ||
console.log(' username: ' + result.username); | ||
console.log(' email: ' + result.email); | ||
}); | ||
``` | ||
@@ -55,8 +43,8 @@ | ||
``` | ||
$ node examples/simple-prompt.js | ||
prompt: username: some-user | ||
prompt: email: some-user@some-place.org | ||
Command-line input received: | ||
username: some-user | ||
email: some-user@some-place.org | ||
$ node examples/simple-prompt.js | ||
prompt: username: some-user | ||
prompt: email: some-user@some-place.org | ||
Command-line input received: | ||
username: some-user | ||
email: some-user@some-place.org | ||
``` | ||
@@ -68,31 +56,31 @@ | ||
``` js | ||
var schema = { | ||
properties: { | ||
name: { | ||
pattern: /^[a-zA-Z\s\-]+$/, | ||
message: 'Name must be only letters, spaces, or dashes', | ||
required: true | ||
}, | ||
password: { | ||
hidden: true | ||
var schema = { | ||
properties: { | ||
name: { | ||
pattern: /^[a-zA-Z\s\-]+$/, | ||
message: 'Name must be only letters, spaces, or dashes', | ||
required: true | ||
}, | ||
password: { | ||
hidden: true | ||
} | ||
} | ||
} | ||
}; | ||
}; | ||
// | ||
// Start the prompt | ||
// | ||
prompt.start(); | ||
// | ||
// Start the prompt | ||
// | ||
prompt.start(); | ||
// | ||
// Get two properties from the user: email, password | ||
// | ||
prompt.get(schema, function (err, result) { | ||
// | ||
// Log the results. | ||
// Get two properties from the user: email, password | ||
// | ||
console.log('Command-line input received:'); | ||
console.log(' name: ' + result.name); | ||
console.log(' password: ' + result.password); | ||
}); | ||
prompt.get(schema, function (err, result) { | ||
// | ||
// Log the results. | ||
// | ||
console.log('Command-line input received:'); | ||
console.log(' name: ' + result.name); | ||
console.log(' password: ' + result.password); | ||
}); | ||
``` | ||
@@ -103,11 +91,11 @@ | ||
``` | ||
$ node examples/property-prompt.js | ||
prompt: name: nodejitsu000 | ||
error: Invalid input for name | ||
error: Name must be only letters, spaces, or dashes | ||
prompt: name: Nodejitsu Inc | ||
prompt: password: | ||
Command-line input received: | ||
name: Nodejitsu Inc | ||
password: some-password | ||
$ node examples/property-prompt.js | ||
prompt: name: nodejitsu000 | ||
error: Invalid input for name | ||
error: Name must be only letters, spaces, or dashes | ||
prompt: name: Nodejitsu Inc | ||
prompt: password: | ||
Command-line input received: | ||
name: Nodejitsu Inc | ||
password: some-password | ||
``` | ||
@@ -121,10 +109,10 @@ | ||
``` js | ||
{ | ||
description: 'Enter your password', // Prompt displayed to the user. If not supplied name will be used. | ||
pattern: /^\w+$/, // Regular expression that input must be valid against. | ||
message: 'Password must be letters', // Warning message to display if validation fails. | ||
hidden: true, // If true, characters entered will not be output to console. | ||
default: 'lamepassword', // Default value to use if no value is entered. | ||
required: true // If true, value entered must be non-empty. | ||
} | ||
{ | ||
description: 'Enter your password', // Prompt displayed to the user. If not supplied name will be used. | ||
pattern: /^\w+$/, // Regular expression that input must be valid against. | ||
message: 'Password must be letters', // Warning message to display if validation fails. | ||
hidden: true, // If true, characters entered will not be output to console. | ||
default: 'lamepassword', // Default value to use if no value is entered. | ||
required: true // If true, value entered must be non-empty. | ||
} | ||
``` | ||
@@ -139,29 +127,29 @@ | ||
```js | ||
var prompt = require('../lib/prompt'); | ||
var prompt = require('../lib/prompt'); | ||
// | ||
// Start the prompt | ||
// | ||
prompt.start(); | ||
// | ||
// Start the prompt | ||
// | ||
prompt.start(); | ||
// | ||
// Get two properties from the user: username and password | ||
// | ||
prompt.get([{ | ||
name: 'username', | ||
required: true | ||
}, { | ||
name: 'password', | ||
hidden: true, | ||
conform: function (value) { | ||
return true; | ||
} | ||
}], function (err, result) { | ||
// | ||
// Log the results. | ||
// Get two properties from the user: username and password | ||
// | ||
console.log('Command-line input received:'); | ||
console.log(' username: ' + result.username); | ||
console.log(' password: ' + result.password); | ||
}); | ||
prompt.get([{ | ||
name: 'username', | ||
required: true | ||
}, { | ||
name: 'password', | ||
hidden: true, | ||
conform: function (value) { | ||
return true; | ||
} | ||
}], function (err, result) { | ||
// | ||
// Log the results. | ||
// | ||
console.log('Command-line input received:'); | ||
console.log(' username: ' + result.username); | ||
console.log(' password: ' + result.password); | ||
}); | ||
``` | ||
@@ -180,31 +168,30 @@ | ||
``` js | ||
//prompt-override.js | ||
//prompt-override.js | ||
var prompt = require('prompt'), | ||
optimist = require('optimist') | ||
var prompt = require('prompt'), | ||
optimist = require('optimist') | ||
// | ||
// set the overrides | ||
// | ||
prompt.override = optimist.argv | ||
// | ||
// set the overrides | ||
// | ||
prompt.override = optimist.argv | ||
// | ||
// Start the prompt | ||
// | ||
prompt.start(); | ||
// | ||
// Start the prompt | ||
// | ||
prompt.start(); | ||
// | ||
// Get two properties from the user: username and email | ||
// | ||
prompt.get(['username', 'email'], function (err, result) { | ||
// | ||
// Log the results. | ||
// Get two properties from the user: username and email | ||
// | ||
console.log('Command-line input received:'); | ||
console.log(' username: ' + result.username); | ||
console.log(' email: ' + result.email); | ||
}) | ||
prompt.get(['username', 'email'], function (err, result) { | ||
// | ||
// Log the results. | ||
// | ||
console.log('Command-line input received:'); | ||
console.log(' username: ' + result.username); | ||
console.log(' email: ' + result.email); | ||
}) | ||
//: node prompt-override.js --username USER --email EMAIL | ||
//: node prompt-override.js --username USER --email EMAIL | ||
``` | ||
@@ -217,23 +204,23 @@ | ||
``` js | ||
var obj = { | ||
password: 'lamepassword', | ||
mindset: 'NY' | ||
} | ||
var obj = { | ||
password: 'lamepassword', | ||
mindset: 'NY' | ||
} | ||
// | ||
// Log the initial object. | ||
// | ||
console.log('Initial object to be extended:'); | ||
console.dir(obj); | ||
// | ||
// Log the initial object. | ||
// | ||
console.log('Initial object to be extended:'); | ||
console.dir(obj); | ||
// | ||
// Add two properties to the empty object: username and email | ||
// | ||
prompt.addProperties(obj, ['username', 'email'], function (err) { | ||
// | ||
// Log the results. | ||
// Add two properties to the empty object: username and email | ||
// | ||
console.log('Updated object received:'); | ||
console.dir(obj); | ||
}); | ||
prompt.addProperties(obj, ['username', 'email'], function (err) { | ||
// | ||
// Log the results. | ||
// | ||
console.log('Updated object received:'); | ||
console.dir(obj); | ||
}); | ||
``` | ||
@@ -259,35 +246,47 @@ | ||
``` js | ||
var prompt = require("prompt"); | ||
// | ||
// The colors module adds color properties to String.prototype | ||
// | ||
require("colors"); | ||
var prompt = require("prompt"); | ||
// | ||
// Setting these properties customizes the prompt. | ||
// | ||
prompt.message = "Question!".rainbow; | ||
prompt.delimiter = "><".green; | ||
// | ||
// Setting these properties customizes the prompt. | ||
// | ||
prompt.message = "Question!".rainbow; | ||
prompt.delimiter = "><".green; | ||
prompt.start(); | ||
prompt.start(); | ||
prompt.get({ | ||
properties: { | ||
name: { | ||
description: "What is your name?".magenta | ||
prompt.get({ | ||
properties: { | ||
name: { | ||
description: "What is your name?".magenta | ||
} | ||
} | ||
} | ||
}, function (err, result) { | ||
console.log("You said your name is: ".cyan + result.name.cyan); | ||
}); | ||
}, function (err, result) { | ||
console.log("You said your name is: ".cyan + result.name.cyan); | ||
}); | ||
``` | ||
## Running tests | ||
If you don't want colors, you can set | ||
```js | ||
var prompt = require('prompt'); | ||
prompt.colors = false; | ||
``` | ||
vows test/*-test.js --spec | ||
## Installation | ||
``` bash | ||
$ [sudo] npm install prompt | ||
``` | ||
#### Author: [Charlie Robbins][1] | ||
## Running tests | ||
``` bash | ||
$ npm test | ||
``` | ||
#### License: MIT | ||
#### Author: [Charlie Robbins](http://github.com/indexzero) | ||
#### Contributors: [Josh Holbrook](http://github.com/jesusabdullah), [Pavan Kumar Sunkara](http://github.com/pksunkara) | ||
[0]: https://github.com/flatiron/prompt/tree/master/examples | ||
[1]: http://nodejitsu.com |
@@ -29,4 +29,12 @@ /* | ||
this.emit('data', msg); | ||
return true; | ||
}; | ||
MockReadWriteStream.prototype.writeNextTick = function (msg) { | ||
var self = this | ||
process.nextTick(function () { | ||
self.write(msg); | ||
}); | ||
}; | ||
// | ||
@@ -41,2 +49,20 @@ // Create some mock streams for asserting against | ||
// | ||
// Because `read` uses a `process.nextTick` for reading from | ||
// stdin, it is necessary to write sequences of input with extra | ||
// `process.nextTick` calls | ||
// | ||
helpers.stdin.writeSequence = function (lines) { | ||
if (!lines || !lines.length) { | ||
return; | ||
} | ||
helpers.stdin.writeNextTick(lines.shift()); | ||
prompt.once('prompt', function () { | ||
process.nextTick(function () { | ||
helpers.stdin.writeSequence(lines); | ||
}); | ||
}); | ||
} | ||
// | ||
// Monkey punch `util.error` to silence console output | ||
@@ -75,2 +101,3 @@ // and redirect to helpers.stderr for testing. | ||
password: { | ||
default: 'Enter 12345 [backspace] [backspace]!', | ||
hidden: true, | ||
@@ -77,0 +104,0 @@ required: true |
@@ -30,3 +30,3 @@ /* | ||
winston.info('When prompted, enter: 12345 [backspace] [backspace] [enter]'); | ||
prompt.getInput({ path: ['password'], schema: helpers.schema.properties.password}, this.callback); | ||
prompt.getInput({ path: ['password'], schema: helpers.schema.properties.password }, this.callback); | ||
}, | ||
@@ -33,0 +33,0 @@ "should respond with `123`": function (err, result) { |
@@ -17,8 +17,6 @@ /* | ||
var names = [].slice.call(arguments), | ||
complete = { | ||
schema: {} | ||
}; | ||
complete = { schema: {} }; | ||
names.forEach(function (name) { | ||
complete.path = [ name ], | ||
complete.path = [name], | ||
complete.schema = schema.properties[name]; | ||
@@ -43,34 +41,2 @@ }); | ||
}, | ||
"the readLine() method": { | ||
topic: function () { | ||
prompt.readLine(this.callback); | ||
helpers.stdin.write('testing\n'); | ||
}, | ||
"should respond with data from the stdin stream": function (err, input) { | ||
assert.isNull(err); | ||
assert.equal(input, 'testing'); | ||
} | ||
}, | ||
"the readLineHidden() method": { | ||
"when given backspaces": { | ||
topic: function () { | ||
prompt.readLineHidden(this.callback); | ||
helpers.stdin.write('no-\x08backspace.\x7f'); | ||
helpers.stdin.write('\n'); | ||
}, | ||
"should remove the proper characters": function (err,input) { | ||
assert.isNull(err); | ||
assert.equal(input, 'nobackspace'); | ||
} | ||
}, | ||
topic: function () { | ||
prompt.readLineHidden(this.callback); | ||
helpers.stdin.write('testing'); | ||
helpers.stdin.write('\r\n'); | ||
}, | ||
"should respond with data from the stdin stream": function (err, input) { | ||
assert.isNull(err); | ||
assert.equal(input, 'testing'); | ||
} | ||
}, | ||
"the getInput() method": { | ||
@@ -85,3 +51,3 @@ "with a simple string prompt": { | ||
prompt.getInput('test input', this.callback); | ||
helpers.stdin.write('test value\n'); | ||
helpers.stdin.writeNextTick('test value\n'); | ||
}, | ||
@@ -108,6 +74,5 @@ "should prompt to stdout and respond with data": function (err, input) { | ||
prompt.once('invalid', this.callback.bind(null, null)) | ||
helpers.stdin.write('\n'); | ||
helpers.stdin.writeNextTick('\n'); | ||
}, | ||
"should prompt with an error": function (ign, prop, input) { | ||
"should prompt with an error": function (_, prop, input) { | ||
assert.isObject(prop); | ||
@@ -129,3 +94,3 @@ assert.equal(input, ''); | ||
prompt.getInput('password', this.callback); | ||
helpers.stdin.write('trustno1\n'); | ||
helpers.stdin.writeNextTick('trustno1\n'); | ||
}, | ||
@@ -152,3 +117,3 @@ | ||
prompt.once('invalid', this.callback.bind(null, null)) | ||
helpers.stdin.write('\n'); | ||
helpers.stdin.writeNextTick('\n'); | ||
}, | ||
@@ -172,3 +137,3 @@ "should prompt with an error": function (ign, prop, input) { | ||
prompt.getInput(grab('username'), this.callback); | ||
helpers.stdin.write('some-user\n'); | ||
helpers.stdin.writeNextTick('some-user\n'); | ||
}, | ||
@@ -197,3 +162,3 @@ "should prompt to stdout and respond with data": function (err, input) { | ||
process.nextTick(function () { | ||
helpers.stdin.write('some-user\n'); | ||
helpers.stdin.writeNextTick('some-user\n'); | ||
}) | ||
@@ -203,3 +168,3 @@ }) | ||
helpers.stdin.write('some -user\n'); | ||
helpers.stdin.writeNextTick('some -user\n'); | ||
}, | ||
@@ -222,2 +187,17 @@ "should prompt with an error before completing the operation": function (err, input) { | ||
} | ||
} | ||
} | ||
}).addBatch({ | ||
"When using prompt": { | ||
topic: function () { | ||
// | ||
// Reset the prompt for mock testing | ||
// | ||
prompt.started = false; | ||
prompt.start({ | ||
stdin: helpers.stdin, | ||
stdout: helpers.stdout | ||
}); | ||
return null; | ||
}, | ||
@@ -234,3 +214,3 @@ "the get() method": { | ||
prompt.get('test input', this.callback); | ||
helpers.stdin.write('test value\n'); | ||
helpers.stdin.writeNextTick('test value\n'); | ||
}, | ||
@@ -255,3 +235,3 @@ "should prompt to stdout and respond with the value": function (err, result) { | ||
prompt.get('riffwabbles', this.callback); | ||
helpers.stdin.write('\n'); | ||
helpers.stdin.writeNextTick('\n'); | ||
}, | ||
@@ -275,3 +255,3 @@ "should prompt to stdout and respond with the default value": function (err, result) { | ||
prompt.get(grab('fnvalidator'), this.callback); | ||
helpers.stdin.write('fn123\n'); | ||
helpers.stdin.writeNextTick('fn123\n'); | ||
}, | ||
@@ -282,19 +262,22 @@ "should accept a value that is checked": function (err, result) { | ||
} | ||
}/*, // Does not work with revalidator | ||
"with a callback validator": { | ||
topic: function () { | ||
var that = this; | ||
helpers.stdout.once('data', function (msg) { | ||
that.msg = msg; | ||
}); | ||
prompt.get(grab('cbvalidator'), this.callback); | ||
helpers.stdin.write('cb123\n'); | ||
}, | ||
"should not accept a value that is correct": function (err, result) { | ||
assert.isNull(err); | ||
assert.equal(result['cbvalidator'],'cb123'); | ||
} | ||
}*/ | ||
} | ||
// | ||
// Remark Does not work with revalidator | ||
// | ||
// "with a callback validator": { | ||
// topic: function () { | ||
// var that = this; | ||
// | ||
// helpers.stdout.once('data', function (msg) { | ||
// that.msg = msg; | ||
// }); | ||
// | ||
// prompt.get(grab('cbvalidator'), this.callback); | ||
// helpers.stdin.writeNextTick('cb123\n'); | ||
// }, | ||
// "should not accept a value that is correct": function (err, result) { | ||
// assert.isNull(err); | ||
// assert.equal(result['cbvalidator'],'cb123'); | ||
// } | ||
// } | ||
} | ||
@@ -311,2 +294,17 @@ }, | ||
} | ||
} | ||
} | ||
}).addBatch({ | ||
"When using prompt": { | ||
topic: function () { | ||
// | ||
// Reset the prompt for mock testing | ||
// | ||
prompt.started = false; | ||
prompt.start({ | ||
stdin: helpers.stdin, | ||
stdout: helpers.stdout | ||
}); | ||
return null; | ||
}, | ||
@@ -316,4 +314,3 @@ "the addProperties() method": { | ||
prompt.addProperties({}, ['foo', 'bar'], this.callback); | ||
helpers.stdin.write('foo\n'); | ||
helpers.stdin.write('bar\n'); | ||
helpers.stdin.writeSequence(['foo\n', 'bar\n']); | ||
}, | ||
@@ -353,5 +350,4 @@ "should add the properties to the object": function (err, obj) { | ||
prompt.get('username', this.callback); | ||
helpers.stdin.write('\n'); | ||
helpers.stdin.write('hell$\n'); | ||
helpers.stdin.write('hello\n'); | ||
helpers.stdin.writeSequence(['\n', 'hell$\n', 'hello\n']); | ||
}, | ||
@@ -385,5 +381,4 @@ "should prompt to stdout and respond with the default value": function (err, result) { | ||
topic: function () { | ||
prompt.get([ grab('animal'), grab('sound')], this.callback); | ||
helpers.stdin.write('dog\n'); | ||
helpers.stdin.write('woof\n'); | ||
prompt.get([grab('animal'), grab('sound')], this.callback); | ||
helpers.stdin.writeSequence(['dog\n', 'woof\n']); | ||
}, | ||
@@ -398,6 +393,5 @@ "should respond with the values entered": function (err, result) { | ||
topic: function () { | ||
prompt.get([ grab('animal'), grab('sound') ], function () {}); | ||
prompt.get([grab('animal'), grab('sound')], function () {}); | ||
prompt.once('invalid', this.callback.bind(null, null)); | ||
helpers.stdin.write('dog\n'); | ||
helpers.stdin.write('meow\n'); | ||
helpers.stdin.writeSequence(['dog\n', 'meow\n']); | ||
}, | ||
@@ -494,3 +488,3 @@ "should prompt for the error": function (ign, property, line) { | ||
prompt.confirm('test', this.callback); | ||
helpers.stdin.write('Y\n'); | ||
helpers.stdin.writeNextTick('Y\n'); | ||
}, | ||
@@ -505,3 +499,3 @@ "should respond with true" : function(err, result) { | ||
prompt.confirm('test', this.callback); | ||
helpers.stdin.write('N\n'); | ||
helpers.stdin.writeNextTick('N\n'); | ||
}, | ||
@@ -516,3 +510,3 @@ "should respond with false" : function(err, result) { | ||
prompt.confirm('test', this.callback); | ||
helpers.stdin.write('YES\n'); | ||
helpers.stdin.writeNextTick('YES\n'); | ||
}, | ||
@@ -527,3 +521,3 @@ "should respond with true" : function(err, result) { | ||
prompt.confirm('test', this.callback); | ||
helpers.stdin.write('NO\n'); | ||
helpers.stdin.writeNextTick('NO\n'); | ||
}, | ||
@@ -538,3 +532,3 @@ "should respond with false" : function(err, result) { | ||
prompt.confirm('test', this.callback); | ||
helpers.stdin.write('T\n'); | ||
helpers.stdin.writeNextTick('T\n'); | ||
}, | ||
@@ -549,3 +543,3 @@ "should respond with true" : function(err, result) { | ||
prompt.confirm('test', this.callback); | ||
helpers.stdin.write('F\n'); | ||
helpers.stdin.writeNextTick('F\n'); | ||
}, | ||
@@ -560,3 +554,3 @@ "should respond with false" : function(err, result) { | ||
prompt.confirm('test', this.callback); | ||
helpers.stdin.write('TRUE\n'); | ||
helpers.stdin.writeNextTick('TRUE\n'); | ||
}, | ||
@@ -571,3 +565,3 @@ "should respond with true" : function(err, result) { | ||
prompt.confirm('test', this.callback); | ||
helpers.stdin.write('FALSE\n'); | ||
helpers.stdin.writeNextTick('FALSE\n'); | ||
}, | ||
@@ -584,3 +578,3 @@ "should respond with false" : function(err, result) { | ||
prompt.confirm({description:'a custom message'}, this.callback); | ||
helpers.stdin.write('Y\n'); | ||
helpers.stdin.writeNextTick('Y\n'); | ||
}, | ||
@@ -595,3 +589,3 @@ "should respond with true" : function(err, result) { | ||
prompt.confirm({}, this.callback); | ||
helpers.stdin.write('Y\n'); | ||
helpers.stdin.writeNextTick('Y\n'); | ||
}, | ||
@@ -605,3 +599,3 @@ "should respond with true" : function(err, result) { | ||
"responding node" : { | ||
topic : function() { | ||
topic: function() { | ||
prompt.confirm({ | ||
@@ -612,3 +606,3 @@ description: 'node or jitsu?', | ||
}, this.callback); | ||
helpers.stdin.write('node\n'); | ||
helpers.stdin.writeNextTick('node\n'); | ||
}, | ||
@@ -621,3 +615,3 @@ "should respond with true" : function(err, result) { | ||
"responding jitsu" : { | ||
topic : function() { | ||
topic: function() { | ||
prompt.confirm({ | ||
@@ -628,3 +622,3 @@ description: 'node or jitsu?', | ||
}, this.callback); | ||
helpers.stdin.write('jitsu\n'); | ||
helpers.stdin.writeNextTick('jitsu\n'); | ||
}, | ||
@@ -641,7 +635,5 @@ "should respond with false" : function(err, result) { | ||
"responding with yesses" : { | ||
topic : function() { | ||
topic: function() { | ||
prompt.confirm(["test", "test2", "test3"], this.callback); | ||
helpers.stdin.write('Y\n'); | ||
helpers.stdin.write('y\n'); | ||
helpers.stdin.write('YES\n'); | ||
helpers.stdin.writeSequence(['Y\n', 'y\n', 'YES\n']); | ||
}, | ||
@@ -654,7 +646,5 @@ "should respond with true" : function(err, result) { | ||
"responding with one no" : { | ||
topic : function() { | ||
topic: function() { | ||
prompt.confirm(["test", "test2", "test3"], this.callback); | ||
helpers.stdin.write('Y\n'); | ||
helpers.stdin.write('N\n'); | ||
helpers.stdin.write('YES\n'); | ||
helpers.stdin.writeSequence(['Y\n', 'N\n', 'YES\n']); | ||
}, | ||
@@ -667,7 +657,5 @@ "should respond with false" : function(err, result) { | ||
"responding with all noes" : { | ||
topic : function() { | ||
topic: function() { | ||
prompt.confirm(["test", "test2", "test3"], this.callback); | ||
helpers.stdin.write('n\n'); | ||
helpers.stdin.write('NO\n'); | ||
helpers.stdin.write('N\n'); | ||
helpers.stdin.writeSequence(['n\n', 'NO\n', 'N\n']); | ||
}, | ||
@@ -682,12 +670,8 @@ "should respond with false" : function(err, result) { | ||
"responding with yesses" : { | ||
topic : function() { | ||
prompt.confirm( | ||
[ | ||
{message:"test"}, | ||
{message:"test2"} | ||
], | ||
this.callback | ||
); | ||
helpers.stdin.write('y\n'); | ||
helpers.stdin.write('y\n'); | ||
topic: function() { | ||
prompt.confirm([ | ||
{ message: "test" }, | ||
{ message: "test2" } | ||
], this.callback); | ||
helpers.stdin.writeSequence(['y\n', 'y\n']); | ||
}, | ||
@@ -700,12 +684,8 @@ "should respond with true" : function(err, result) { | ||
"responding with noes" : { | ||
topic : function() { | ||
prompt.confirm( | ||
[ | ||
{message:"test"}, | ||
{message:"test2"} | ||
], | ||
this.callback | ||
); | ||
helpers.stdin.write('n\n'); | ||
helpers.stdin.write('n\n'); | ||
topic: function() { | ||
prompt.confirm([ | ||
{ message: "test" }, | ||
{ message: "test2" } | ||
], this.callback); | ||
helpers.stdin.writeSequence(['n\n', 'n\n']); | ||
}, | ||
@@ -718,12 +698,8 @@ "should respond with false" : function(err, result) { | ||
"responding with yes and no" : { | ||
topic : function() { | ||
prompt.confirm( | ||
[ | ||
{message:"test"}, | ||
{message:"test2"} | ||
], | ||
this.callback | ||
); | ||
helpers.stdin.write('n\n'); | ||
helpers.stdin.write('y\n'); | ||
topic: function() { | ||
prompt.confirm([ | ||
{ message: "test" }, | ||
{ message: "test2" } | ||
], this.callback); | ||
helpers.stdin.writeSequence(['n\n', 'y\n']); | ||
}, | ||
@@ -730,0 +706,0 @@ "should respond with false" : function(err, result) { |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
HTTP dependency
Supply chain riskContains a dependency which resolves to a remote HTTP URL which could be used to inject untrusted code and reduce overall package reliability.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
22
109676
1833
283
1