question-cache
Advanced tools
Comparing version 0.3.5 to 0.4.0
662
index.js
@@ -1,22 +0,25 @@ | ||
/*! | ||
* question-cache <https://github.com/jonschlinkert/question-cache> | ||
* | ||
* Copyright (c) 2015, Jon Schlinkert. | ||
* Licensed under the MIT License. | ||
*/ | ||
'use strict'; | ||
var use = require('use'); | ||
var util = require('util'); | ||
var debug = require('debug')('questions'); | ||
var Options = require('option-cache'); | ||
var Question = require('./lib/question'); | ||
var utils = require('./lib/utils'); | ||
/** | ||
* Create an instance of `Questions` with the | ||
* given `options`. | ||
* Answer cache, for caching answers during a session, | ||
* and potentially across instances | ||
*/ | ||
var sessionAnswers = {}; | ||
var forced = {}; | ||
/** | ||
* Create an instance of `Questions` with the given `options`. | ||
* | ||
* ```js | ||
* var inquirer = require('inquirer') | ||
* var questions = new Questions({inquirer: inquirer}); | ||
* var Questions = new Questions(options); | ||
* ``` | ||
* | ||
* @param {Object} `options` Pass your instance of [inquirer] on the `inquirer` option. | ||
* @param {Object} `options` question cache options | ||
* @api public | ||
@@ -29,60 +32,135 @@ */ | ||
} | ||
if (isObject(options) && 'prompt' in options) { | ||
options = {inquirer: options}; | ||
} | ||
this.options = options || {}; | ||
var inquirer = this.options.inquirer; | ||
if (typeof inquirer === 'undefined') { | ||
inquirer = utils.inquirer(); | ||
} | ||
Options.call(this, options); | ||
use(this); | ||
this.options = utils.omitEmpty(options || {}); | ||
this.initQuestions(this.options); | ||
} | ||
define(this, 'inquirer', inquirer); | ||
delete this.options.inquirer; | ||
/** | ||
* Inherit `options-cache` | ||
*/ | ||
util.inherits(Questions, Options); | ||
/** | ||
* Intialize question-cache | ||
*/ | ||
Questions.prototype.initQuestions = function(opts) { | ||
debug('initializing question-cache'); | ||
this.answers = sessionAnswers; | ||
this.inquirer = opts.inquirer || utils.inquirer(); | ||
this.project = opts.project || utils.project(process.cwd()); | ||
this.data = opts.data || {}; | ||
this.cache = {}; | ||
this.queue = []; | ||
} | ||
}; | ||
/** | ||
* Store a question object by `key`. | ||
* Calls [addQuestion](#addQuestion), with the only difference being that `.set` | ||
* returns the `questions` instance and `.addQuestion` returns the question object. | ||
* So use `.set` if you want to chain questions, or `.addQuestion` if you need | ||
* the created question object. | ||
* | ||
* ```js | ||
* questions.set('name', { | ||
* questions | ||
* .set('drink', 'What is your favorite beverage?') | ||
* .set('color', 'What is your favorite color?') | ||
* .set('season', 'What is your favorite season?'); | ||
* | ||
* // or | ||
* questions.set('drink', { | ||
* type: 'input', | ||
* message: 'Project name?', | ||
* default: 'undefined' | ||
* message: 'What is your favorite beverage?' | ||
* }); | ||
* | ||
* // or | ||
* questions.set({ | ||
* name: 'drink' | ||
* type: 'input', | ||
* message: 'What is your favorite beverage?' | ||
* }); | ||
* ``` | ||
* @param {Object|String} `name` Question name, message (string), or question/options object. | ||
* @param {Object|String} `value` Question message (string), or question/options object. | ||
* @param {Object|String} `options` Question/options object. | ||
* @api public | ||
*/ | ||
Questions.prototype.set = function(name, val, options) { | ||
this.addQuestion.apply(this, arguments); | ||
return this; | ||
}; | ||
/** | ||
* Add a question to be asked at a later point. Creates an instance of | ||
* [Question](#question), so any `Question` options or settings may be used. | ||
* Also, the default `type` is `input` if not defined by the user. | ||
* | ||
* @param {String} `key` Unique question id. | ||
* @param {Object} `value` Question object that follows [inquirer] conventions. | ||
* ```js | ||
* questions.addQuestion('drink', 'What is your favorite beverage?'); | ||
* | ||
* // or | ||
* questions.addQuestion('drink', { | ||
* type: 'input', | ||
* message: 'What is your favorite beverage?' | ||
* }); | ||
* | ||
* // or | ||
* questions.addQuestion({ | ||
* name: 'drink' | ||
* type: 'input', | ||
* message: 'What is your favorite beverage?' | ||
* }); | ||
* ``` | ||
* @param {Object|String} `name` Question name, message (string), or question/options object. | ||
* @param {Object|String} `value` Question message (string), or question/options object. | ||
* @param {Object|String} `options` Question/options object. | ||
* @api public | ||
*/ | ||
Questions.prototype.set = function(key, value) { | ||
if (typeof key === 'undefined') { | ||
throw new TypeError('expected set to be a string or object.'); | ||
Questions.prototype.addQuestion = function(name, val, options) { | ||
if (utils.isObject(name) && !utils.isQuestion(name)) { | ||
return this.visit('set', name); | ||
} | ||
if (typeof key === 'object') { | ||
value = key; | ||
key = value.name; | ||
} | ||
var question = new Question(name, val, options); | ||
debug('questions#set "%s"', name); | ||
if (typeof value === 'string') { | ||
value = {message: value}; | ||
} else if (typeof key === 'string' && !value) { | ||
value = {message: addQmark(key)}; | ||
} | ||
this.emit('set', question.name, question); | ||
this.cache[question.name] = question; | ||
value = value || {}; | ||
if (isObject(key)) { | ||
value = utils.merge({}, value, key); | ||
} | ||
utils.union(this.queue, [question.name]); | ||
this.run(question); | ||
return question; | ||
}; | ||
value.type = value.type || 'input'; | ||
value.name = value.name || value.key || key; | ||
/** | ||
* Create a "choices" question from an array of values. | ||
* | ||
* ```js | ||
* questions.choices('foo', ['a', 'b', 'c']); | ||
* | ||
* // or | ||
* questions.choices('foo', { | ||
* message: 'Favorite letter?', | ||
* choices: ['a', 'b', 'c'] | ||
* }); | ||
* ``` | ||
* @param {String} `key` Question key | ||
* @param {String} `msg` Question message | ||
* @param {Array} `items` Choice items | ||
* @param {Object|Function} `options` Question options or callback function | ||
* @param {Function} `callback` callback function | ||
* @api public | ||
*/ | ||
utils.set(this.cache, key, value); | ||
this.queue.push(value); | ||
Questions.prototype.choices = function(key, msg, items, options) { | ||
var choices = utils.toChoices(); | ||
var question = choices.apply(null, arguments); | ||
if (!question.hasOwnProperty('save')) { | ||
question.save = false; | ||
} | ||
this.set(question.name, question); | ||
return this; | ||
@@ -92,270 +170,390 @@ }; | ||
/** | ||
* Get a question by `key`. | ||
* Create a "list" question from an array of values. | ||
* | ||
* ```js | ||
* questions.get('name'); | ||
* //=> {type: 'input', message: 'What is your name?', default: ''} | ||
* questions.list('foo', ['a', 'b', 'c']); | ||
* | ||
* // or | ||
* questions.list('foo', { | ||
* message: 'Favorite letter?', | ||
* choices: ['a', 'b', 'c'] | ||
* }); | ||
* ``` | ||
* | ||
* @param {String} `key` Unique question id. | ||
* @param {Object} `value` Question object that follows [inquirer] conventions. | ||
* @param {String} `key` Question key | ||
* @param {String} `msg` Question message | ||
* @param {Array} `list` List items | ||
* @param {String|Array} `queue` Name or array of question names. | ||
* @param {Object|Function} `options` Question options or callback function | ||
* @param {Function} `callback` callback function | ||
* @api public | ||
*/ | ||
Questions.prototype.get = function(key) { | ||
return utils.get(this.cache, key); | ||
Questions.prototype.list = function(key, msg, list, options) { | ||
var choices = utils.toChoices({type: 'list'}); | ||
var question = choices.apply(null, arguments); | ||
if (options) { | ||
question.options = options; | ||
} | ||
this.set(question.name, question); | ||
return this; | ||
}; | ||
/** | ||
* Return true if the given question name is stored on | ||
* question-cache. | ||
* Create a "rawlist" question from an array of values. | ||
* | ||
* ```js | ||
* var exists = questions.has('name'); | ||
* //=> true or false | ||
* questions.rawlist('foo', ['a', 'b', 'c']); | ||
* | ||
* // or | ||
* questions.rawlist('foo', { | ||
* message: 'Favorite letter?', | ||
* choices: ['a', 'b', 'c'] | ||
* }); | ||
* ``` | ||
* | ||
* @param {String} `key` Unique question id. | ||
* @param {Object} `value` Question object that follows [inquirer] conventions. | ||
* @param {String} `key` Question key | ||
* @param {String} `msg` Question message | ||
* @param {Array} `list` List items | ||
* @param {String|Array} `queue` Name or array of question names. | ||
* @param {Object|Function} `options` Question options or callback function | ||
* @param {Function} `callback` callback function | ||
* @api public | ||
*/ | ||
Questions.prototype.has = function(key) { | ||
return utils.has(this.cache, key); | ||
Questions.prototype.rawlist = function(key, msg, list, options) { | ||
var choices = utils.toChoices({type: 'rawlist'}); | ||
var question = choices.apply(null, arguments); | ||
if (options) { | ||
question.options = options; | ||
} | ||
this.set(question.name, question); | ||
return this; | ||
}; | ||
/** | ||
* Returns an array of question objects from an array of keys. Keys | ||
* may use dot notation. | ||
* Create an "expand" question from an array of values. | ||
* | ||
* @param {Array} `keys` Question names or object paths. | ||
* @return {Array} Array of question objects. | ||
* ```js | ||
* questions.expand('foo', ['a', 'b', 'c']); | ||
* | ||
* // or | ||
* questions.expand('foo', { | ||
* message: 'Favorite letter?', | ||
* choices: ['a', 'b', 'c'] | ||
* }); | ||
* ``` | ||
* @param {String} `key` Question key | ||
* @param {String} `msg` Question message | ||
* @param {Array} `list` List items | ||
* @param {String|Array} `queue` Name or array of question names. | ||
* @param {Object|Function} `options` Question options or callback function | ||
* @param {Function} `callback` callback function | ||
* @api public | ||
*/ | ||
Questions.prototype.resolve = function(keys) { | ||
keys = arrayify(keys); | ||
var len = keys.length, i = -1; | ||
var questions = []; | ||
Questions.prototype.expand = function(name, msg, list, options) { | ||
var choices = utils.toChoices({type: 'expand'}); | ||
var question = choices.apply(null, arguments); | ||
if (options) { | ||
question.options = options; | ||
} | ||
this.set(question.name, question); | ||
return this; | ||
}; | ||
while (++i < len) { | ||
var question = {}; | ||
var key = keys[i]; | ||
/** | ||
* Create a "choices" question from an array of values. | ||
* | ||
* ```js | ||
* questions.choices('foo', ['a', 'b', 'c']); | ||
* // or | ||
* questions.choices('foo', { | ||
* message: 'Favorite letter?', | ||
* choices: ['a', 'b', 'c'] | ||
* }); | ||
* ``` | ||
* @param {String|Array} `queue` Name or array of question names. | ||
* @param {Object|Function} `options` Question options or callback function | ||
* @param {Function} `callback` callback function | ||
* @api public | ||
*/ | ||
if (typeof key === 'string') { | ||
question = this.get(key); | ||
} else if (isObject(key)) { | ||
question = this.normalizeObject(key); | ||
} | ||
Questions.prototype.confirm = function() { | ||
var question = this.addQuestion.apply(this, arguments); | ||
question.type = 'confirm'; | ||
return this; | ||
}; | ||
if (!question) { | ||
question = this.toQuestion(key); | ||
} | ||
/** | ||
* Get question `name`, or group `name` if question is not found. | ||
* You can also do a direct lookup using `quesions.cache['foo']`. | ||
* | ||
* ```js | ||
* var name = questions.get('name'); | ||
* //=> question object | ||
* ``` | ||
* @param {String} `name` | ||
* @return {Object} Returns the question object. | ||
* @api public | ||
*/ | ||
if (question.hasOwnProperty('type')) { | ||
questions.push(question); | ||
continue; | ||
} | ||
Questions.prototype.get = function(key) { | ||
return !utils.isQuestion(key) ? this.cache[key] : key; | ||
}; | ||
for (var prop in question) { | ||
this.set(prop, question[prop]); | ||
var val = this.get(prop); | ||
/** | ||
* Returns true if `questions.cache` or `questions.groups` has | ||
* question `name`. | ||
* | ||
* ```js | ||
* var name = questions.has('name'); | ||
* //=> true | ||
* ``` | ||
* @return {String} The name of the question to check | ||
* @api public | ||
*/ | ||
if (question.hasOwnProperty(prop)) { | ||
questions.push(val); | ||
} | ||
} | ||
Questions.prototype.has = function(key) { | ||
for (var prop in this.cache) { | ||
if (prop.indexOf(key) === 0) return true; | ||
} | ||
return questions; | ||
return false; | ||
}; | ||
/** | ||
* Normalize questions into a consistent object format | ||
* following [inquirer][] conventions. | ||
* Delete the given question or any questions that have the given | ||
* namespace using dot-notation. | ||
* | ||
* @param {Object} `questions` | ||
* @param {Object} `options` | ||
* @return {Object} | ||
* ```js | ||
* questions.del('name'); | ||
* questions.get('name'); | ||
* //=> undefined | ||
* | ||
* // using dot-notation | ||
* questions.del('author'); | ||
* questions.get('author.name'); | ||
* //=> undefined | ||
* ``` | ||
* @return {String} The name of the question to delete | ||
* @api public | ||
*/ | ||
Questions.prototype.normalizeObject = function(questions) { | ||
var res = []; | ||
for (var key in questions) { | ||
if (questions.hasOwnProperty(key)) { | ||
var val = questions[key]; | ||
var question; | ||
if (typeof val === 'string') { | ||
question = this.toQuestion(key, val); | ||
} else if (typeof val === 'object') { | ||
question = this.toQuestion(key, val); | ||
} | ||
if (question) res = res.concat(question); | ||
Questions.prototype.del = function(key) { | ||
for (var prop in this.cache) { | ||
if (prop.indexOf(key) === 0) { | ||
delete this.cache[prop]; | ||
} | ||
} | ||
return res; | ||
}; | ||
/** | ||
* Create a question object from a string. Uses the `input` question type, | ||
* and does the following basic normalization: | ||
* Clear all cached answers. | ||
* | ||
* - when `foo` is passed, a `?` is added to the question. e.g. `foo?` | ||
* - when `foo?` is passed, `?` is removed on the question key, so the answer to `foo?` is | ||
* `{foo: 'bar'}` | ||
* ```js | ||
* questions.clearAnswers(); | ||
* ``` | ||
* | ||
* @param {String} `key` | ||
* @return {Object} Returns a question object. | ||
* @api public | ||
*/ | ||
Questions.prototype.toQuestion = function(key, value) { | ||
var obj = {}; | ||
if (isReserved(key) && typeof value === 'string') { | ||
obj[key] = value; | ||
} else if (typeof key === 'string') { | ||
obj.name = key; | ||
} else if (typeof value === 'string') { | ||
obj.message = value; | ||
} | ||
if (isObject(value)) { | ||
obj = utils.merge({}, obj, value); | ||
} | ||
obj.name = stripQmark(obj.name || key); | ||
if (!obj.message) { | ||
obj.message = addQmark(obj.name); | ||
} | ||
obj.type = obj.type || 'input'; | ||
return obj; | ||
Questions.prototype.clearAnswers = function() { | ||
this.answers = sessionAnswers = {}; | ||
this.data = {}; | ||
}; | ||
/** | ||
* Ask a question or array of questions. | ||
* Clear all questions from the cache. | ||
* | ||
* ```js | ||
* questions.ask(['name', 'homepage']); | ||
* //=> { name: 'foo', homepage: 'https://github/foo' } | ||
* questions.clearQuestions(); | ||
* ``` | ||
* | ||
* @param {String} `key` Unique question id. | ||
* @param {Object} `value` Question object that follows [inquirer] conventions. | ||
* @api public | ||
*/ | ||
Questions.prototype.ask = function(keys, cb) { | ||
if (isObject(keys)) keys = [keys]; | ||
var questions = []; | ||
if (typeof keys === 'function') { | ||
cb = keys; | ||
questions = this.queue; | ||
} else { | ||
questions = this.resolve(keys); | ||
} | ||
if (questions.length === 0) { | ||
return cb(new Error('no questions found.')); | ||
} | ||
try { | ||
this.prompt(questions, function(answers) { | ||
cb(null, setEach({}, answers)); | ||
}); | ||
} catch(err) { | ||
cb(err); | ||
} | ||
Questions.prototype.clearQuestions = function() { | ||
this.cache = {}; | ||
this.queue = []; | ||
}; | ||
/** | ||
* Exposes the `prompt` method on [inquirer] as a convenience. | ||
* Clear all cached questions and answers. | ||
* | ||
* ```js | ||
* questions.prompt({ | ||
* type: 'list', | ||
* name: 'chocolate', | ||
* message: 'What\'s your favorite chocolate?', | ||
* choices: ['Mars', 'Oh Henry', 'Hershey'] | ||
* }, function(answers) { | ||
* //=> {chocolate: 'Hershey'} | ||
* }); | ||
* questions.clear(); | ||
* ``` | ||
* | ||
* @param {Object|Array} `question` Question object or array of question objects. | ||
* @param {Object} `callback` Callback function. | ||
* @api public | ||
*/ | ||
Questions.prototype.prompt = function() { | ||
return this.inquirer.prompt.apply(this.inquirer, arguments); | ||
Questions.prototype.clear = function() { | ||
this.clearQuestions(); | ||
this.clearAnswers(); | ||
}; | ||
/** | ||
* Utility for setting values on properties defined using | ||
* dot notation (object paths). | ||
* Ask one or more questions, with the given `options` and callback. | ||
* | ||
* @param {object} `obj` Object to store values on. | ||
* @param {object} `answers` Answers object. | ||
* ```js | ||
* questions.ask(['name', 'description'], function(err, answers) { | ||
* console.log(answers); | ||
* }); | ||
* ``` | ||
* @param {String|Array} `queue` Name or array of question names. | ||
* @param {Object|Function} `options` Question options or callback function | ||
* @param {Function} `callback` callback function | ||
* @api public | ||
*/ | ||
function setEach(obj, answers) { | ||
for (var key in answers) { | ||
if (answers.hasOwnProperty(key)) { | ||
utils.set(obj, key, answers[key]); | ||
} | ||
Questions.prototype.ask = function(queue, config, cb) { | ||
if (typeof queue === 'function') { | ||
return this.ask.call(this, this.queue, {}, queue); | ||
} | ||
return obj; | ||
} | ||
function addQmark(str) { | ||
if (str && str.slice(-1) !== '?') { | ||
return str + '?'; | ||
if (typeof config === 'function') { | ||
return this.ask.call(this, queue, {}, config); | ||
} | ||
return str; | ||
} | ||
function stripQmark(str) { | ||
if (str && str.slice(-1) === '?') { | ||
return str.slice(0, -1); | ||
} | ||
return str; | ||
} | ||
var questions = this.buildQueue(queue); | ||
var self = this; | ||
function isReserved(key) { | ||
return ['name', 'input', 'message'].indexOf(key) > -1; | ||
} | ||
utils.async.reduce(questions, this.answers, function(answers, key, next) { | ||
debug('asking question "%s"', key); | ||
/** | ||
* Utility for casting a value to an array. | ||
*/ | ||
try { | ||
var opts = utils.merge({}, self.options, config); | ||
var data = utils.merge({}, self.data, opts); | ||
function arrayify(val) { | ||
return val ? (Array.isArray(val) ? val : [val]) : []; | ||
} | ||
var question = self.get(key); | ||
var options = question._options = question.opts(opts); | ||
var val = question.answer(answers, data, self); | ||
debug('using answer %j', val); | ||
// emit question before building options | ||
self.emit('ask', val, key, question, answers); | ||
// get val again after emitting `ask` | ||
val = question.answer(answers, data, self); | ||
// re-build options object after emitting ask, to allow | ||
// user to update question options from a listener | ||
options = question._options = question.opts(opts, question.options); | ||
debug('using options %j', options); | ||
if (options.enabled('skip')) { | ||
debug('skipping question "%s", using answer "%j"', key, val); | ||
question.next(val, self, answers, next); | ||
return; | ||
} | ||
var force = options.get('force'); | ||
var isForced = force === true || utils.matchesKey(force, key); | ||
if (!forced.hasOwnProperty(key)) { | ||
forced[key] = true; | ||
} else { | ||
isForced = false; | ||
} | ||
if (!isForced && utils.isAnswer(val)) { | ||
debug('question "%s", using answer "%j"', key, val); | ||
utils.set(answers, key, val); | ||
self.emit('answer', val, key, question, answers); | ||
question.next(val, self, answers, next); | ||
return; | ||
} | ||
self.inquirer.prompt([question], function(answer) { | ||
debug('answered "%s" with "%j"', key, answer); | ||
try { | ||
var val = answer[key]; | ||
if (question.type === 'checkbox') { | ||
val = utils.flatten(val); | ||
} | ||
if (!utils.isAnswer(val)) { | ||
next(null, answers); | ||
return; | ||
} | ||
// set answer on 'answers' cache | ||
utils.set(answers, key, val); | ||
// emit answer | ||
self.emit('answer', val, key, question, answers); | ||
// next question | ||
question.next(val, self, answers, next); | ||
} catch (err) { | ||
self.emit('error', err); | ||
next(err); | ||
} | ||
}); | ||
} catch (err) { | ||
self.emit('error', err); | ||
next(err); | ||
} | ||
}, function(err, answers) { | ||
if (err) return cb(err); | ||
self.emit('answers', answers); | ||
cb(null, answers); | ||
}); | ||
}; | ||
/** | ||
* Utility for casting a value to an array. | ||
* Build an array of names of questions to ask. | ||
* | ||
* @param {Array|String} keys | ||
* @return {Object} | ||
*/ | ||
function isObject(val) { | ||
return utils.typeOf(val) === 'object'; | ||
} | ||
Questions.prototype.buildQueue = function(questions) { | ||
questions = utils.arrayify(questions); | ||
var len = questions.length; | ||
var queue = []; | ||
var idx = -1; | ||
if (len === 0) { | ||
queue = this.queue; | ||
} | ||
while (++idx < len) { | ||
utils.union(queue, this.normalize(questions[idx])); | ||
} | ||
return queue; | ||
}; | ||
/** | ||
* Utility for definining a non-enumerable property. | ||
* Normalize the given value to return an array of question keys. | ||
* | ||
* @param {[type]} key | ||
* @return {[type]} | ||
* @api public | ||
*/ | ||
function define(obj, prop, val) { | ||
Object.defineProperty(obj, prop, { | ||
configurable: true, | ||
enumerable: false, | ||
writable: true, | ||
value: val | ||
}); | ||
} | ||
Questions.prototype.normalize = function(name) { | ||
debug('normalizing %j', name); | ||
// get `name` from question object | ||
if (utils.isQuestion(name)) { | ||
return [name.name]; | ||
} | ||
if (this.cache.hasOwnProperty(name)) { | ||
return [name]; | ||
} | ||
// filter keys with dot-notation | ||
var matched = 0; | ||
var keys = []; | ||
for (var prop in this.cache) { | ||
if (this.cache.hasOwnProperty(prop)) { | ||
if (prop.indexOf(name) === 0) { | ||
keys.push(prop); | ||
matched++; | ||
} | ||
} | ||
} | ||
return keys; | ||
}; | ||
/** | ||
@@ -362,0 +560,0 @@ * Expose `Questions` |
105
lib/utils.js
'use strict'; | ||
/** | ||
* Module dependencies | ||
*/ | ||
var utils = require('lazy-cache')(require); | ||
var fn = require; | ||
require = utils; | ||
/** | ||
* Module dependencies | ||
* Lazily required module dependencies | ||
*/ | ||
require = utils; | ||
require('arr-flatten', 'flatten'); | ||
require('arr-union', 'union'); | ||
require('async'); | ||
require('define-property', 'define'); | ||
require('get-value', 'get'); | ||
require('has-value', 'has'); | ||
require('inquirer2', 'inquirer'); | ||
require('kind-of', 'typeOf'); | ||
require('is-answer'); | ||
require('isobject', 'isObject'); | ||
require('mixin-deep', 'merge'); | ||
require('get-value', 'get'); | ||
require('has-value', 'has'); | ||
require('omit-empty'); | ||
require('project-name', 'project'); | ||
require('set-value', 'set'); | ||
require('to-choices'); | ||
require = fn; | ||
utils.decorate = function(opts) { | ||
utils.define(opts, 'set', function(prop, val) { | ||
utils.set(this, prop, val); | ||
return this; | ||
}.bind(opts)); | ||
utils.define(opts, 'get', function(prop) { | ||
return utils.get(this, prop); | ||
}.bind(opts)); | ||
utils.define(opts, 'enabled', function(prop) { | ||
return this.get(prop) === true; | ||
}.bind(opts)); | ||
utils.define(opts, 'disabled', function(prop) { | ||
return this.get(prop) === false; | ||
}.bind(opts)); | ||
}; | ||
utils.isEmpty = function(answer) { | ||
return !utils.isAnswer(answer); | ||
}; | ||
utils.matchesKey = function(prop, key) { | ||
if (typeof key !== 'string' || typeof prop !== 'string') { | ||
return false; | ||
} | ||
if (prop === key) { | ||
return true; | ||
} | ||
var len = prop.length; | ||
var ch = key.charAt(len); | ||
return key.indexOf(prop) === 0 && ch === '.'; | ||
}; | ||
/** | ||
* Restore `require` | ||
* Cast val to an array | ||
*/ | ||
require = fn; | ||
utils.arrayify = function(val) { | ||
if (!val) return []; | ||
return Array.isArray(val) ? val : [val]; | ||
}; | ||
/** | ||
* Expose `utils` modules | ||
* Returns true if a value is an object and appears to be a | ||
* question object. | ||
*/ | ||
utils.isQuestion = function(val) { | ||
return utils.isObject(val) && (val.isQuestion || !utils.isOptions(val)); | ||
}; | ||
/** | ||
* Returns true if a value is an object and appears to be an | ||
* options object. | ||
*/ | ||
utils.isOptions = function(val) { | ||
if (!utils.isObject(val)) { | ||
return false; | ||
} | ||
if (val.hasOwnProperty('locale')) { | ||
return true; | ||
} | ||
if (val.hasOwnProperty('force')) { | ||
return true; | ||
} | ||
if (val.hasOwnProperty('type')) { | ||
return false; | ||
} | ||
if (val.hasOwnProperty('message')) { | ||
return false; | ||
} | ||
if (val.hasOwnProperty('choices')) { | ||
return false; | ||
} | ||
if (val.hasOwnProperty('name')) { | ||
return false; | ||
} | ||
}; | ||
/** | ||
* Expose `utils` | ||
*/ | ||
module.exports = utils; |
{ | ||
"name": "question-cache", | ||
"description": "A wrapper around inquirer that makes it easy to create and selectively reuse questions.", | ||
"version": "0.3.5", | ||
"version": "0.4.0", | ||
"homepage": "https://github.com/jonschlinkert/question-cache", | ||
@@ -14,3 +14,3 @@ "author": "Jon Schlinkert (https://github.com/jonschlinkert)", | ||
"index.js", | ||
"lib/" | ||
"lib" | ||
], | ||
@@ -22,9 +22,21 @@ "main": "index.js", | ||
"dependencies": { | ||
"get-value": "^2.0.2", | ||
"has-value": "^0.3.0", | ||
"inquirer2": "github:jonschlinkert/inquirer2", | ||
"kind-of": "^3.0.2", | ||
"arr-flatten": "^1.0.1", | ||
"arr-union": "^3.1.0", | ||
"async": "1.5.2", | ||
"debug": "^2.2.0", | ||
"define-property": "^0.2.5", | ||
"get-value": "^2.0.5", | ||
"has-value": "^0.3.1", | ||
"inquirer2": "^0.1.1", | ||
"is-answer": "^0.1.0", | ||
"isobject": "^2.0.0", | ||
"lazy-cache": "^1.0.3", | ||
"mixin-deep": "^1.1.3", | ||
"set-value": "^0.3.2" | ||
"omit-empty": "^0.3.6", | ||
"option-cache": "^3.3.5", | ||
"os-homedir": "^1.0.1", | ||
"project-name": "^0.2.4", | ||
"set-value": "^0.3.3", | ||
"to-choices": "^0.2.0", | ||
"use": "^1.1.2" | ||
}, | ||
@@ -36,6 +48,8 @@ "devDependencies": { | ||
"gulp-eslint": "^1.0.0", | ||
"gulp-format-md": "^0.1.7", | ||
"gulp-istanbul": "^0.10.2", | ||
"gulp-mocha": "^2.1.3", | ||
"mocha": "*", | ||
"should": "*" | ||
"gulp-unused": "^0.1.2", | ||
"helper-example": "^0.1.0", | ||
"mocha": "^2.4.5" | ||
}, | ||
@@ -56,2 +70,11 @@ "keywords": [ | ||
"verb": { | ||
"run": true, | ||
"toc": false, | ||
"layout": "default", | ||
"tasks": [ | ||
"readme" | ||
], | ||
"plugins": [ | ||
"gulp-format-md" | ||
], | ||
"related": { | ||
@@ -71,7 +94,9 @@ "list": [ | ||
], | ||
"layout": "default", | ||
"plugins": [ | ||
"gulp-format-md" | ||
"lint": { | ||
"reflinks": true | ||
}, | ||
"helpers": [ | ||
"helper-example" | ||
] | ||
} | ||
} |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
GitHub dependency
Supply chain riskContains a dependency which resolves to a GitHub URL. Dependencies fetched from GitHub specifiers are not immutable can be used to inject untrusted code or reduce the likelihood of a reproducible install.
Found 1 instance in 1 package
37312
6
780
547
0
19
10
1
+ Addedarr-flatten@^1.0.1
+ Addedarr-union@^3.1.0
+ Addedasync@1.5.2
+ Addeddebug@^2.2.0
+ Addeddefine-property@^0.2.5
+ Addedis-answer@^0.1.0
+ Addedisobject@^2.0.0
+ Addedomit-empty@^0.3.6
+ Addedoption-cache@^3.3.5
+ Addedos-homedir@^1.0.1
+ Addedproject-name@^0.2.4
+ Addedto-choices@^0.2.0
+ Addeduse@^1.1.2
+ Addedansi-escapes@1.4.0(transitive)
+ Addedansi-gray@0.1.1(transitive)
+ Addedansi-regex@2.1.1(transitive)
+ Addedansi-styles@2.2.1(transitive)
+ Addedansi-wrap@0.1.0(transitive)
+ Addedarr-map@2.0.2(transitive)
+ Addedarr-pluck@0.1.0(transitive)
+ Addedarr-union@3.1.0(transitive)
+ Addedarray-unique@0.2.1(transitive)
+ Addedasync@1.5.2(transitive)
+ Addedchalk@1.1.3(transitive)
+ Addedcli-cursor@1.0.2(transitive)
+ Addedcli-width@1.1.1(transitive)
+ Addedcode-point-at@1.1.0(transitive)
+ Addedcollection-visit@1.0.0(transitive)
+ Addedcomponent-emitter@1.3.1(transitive)
+ Addedcore-util-is@1.0.3(transitive)
+ Addedcwd@0.9.1(transitive)
+ Addeddebug@2.6.9(transitive)
+ Addeddefine-property@0.2.5(transitive)
+ Addedescape-string-regexp@1.0.5(transitive)
+ Addedexit-hook@1.1.1(transitive)
+ Addedexpand-tilde@1.2.2(transitive)
+ Addedfigures@1.7.0(transitive)
+ Addedfile-name@0.1.0(transitive)
+ Addedfind-file-up@0.1.3(transitive)
+ Addedfind-pkg@0.1.2(transitive)
+ Addedfor-own@0.1.5(transitive)
+ Addedfs-exists-sync@0.1.0(transitive)
+ Addedgit-config-path@1.0.1(transitive)
+ Addedgit-repo-name@0.6.0(transitive)
+ Addedglobal-modules@0.2.3(transitive)
+ Addedglobal-prefix@0.1.5(transitive)
+ Addedhas-ansi@2.0.0(transitive)
+ Addedhomedir-polyfill@1.0.3(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedini@1.3.8(transitive)
+ Addedinquirer2@0.1.1(transitive)
+ Addedis-accessor-descriptor@1.0.1(transitive)
+ Addedis-answer@0.1.1(transitive)
+ Addedis-data-descriptor@1.0.1(transitive)
+ Addedis-date-object@1.0.5(transitive)
+ Addedis-descriptor@0.1.7(transitive)
+ Addedis-fullwidth-code-point@1.0.0(transitive)
+ Addedis-number@2.1.0(transitive)
+ Addedis-primitive@2.0.0(transitive)
+ Addedis-windows@0.2.0(transitive)
+ Addedisexe@2.0.0(transitive)
+ Addedkind-of@6.0.3(transitive)
+ Addedlazy-cache@2.0.2(transitive)
+ Addedlodash._arrayfilter@3.0.0(transitive)
+ Addedlodash._basecallback@3.3.1(transitive)
+ Addedlodash._baseeach@3.0.4(transitive)
+ Addedlodash._basefilter@3.0.0(transitive)
+ Addedlodash._baseisequal@3.0.7(transitive)
+ Addedlodash._baseismatch@3.1.3(transitive)
+ Addedlodash._basematches@3.2.0(transitive)
+ Addedlodash._bindcallback@3.0.1(transitive)
+ Addedlodash._getnative@3.9.1(transitive)
+ Addedlodash.isarguments@3.1.0(transitive)
+ Addedlodash.isarray@3.0.4(transitive)
+ Addedlodash.istypedarray@3.0.6(transitive)
+ Addedlodash.keys@3.1.2(transitive)
+ Addedlodash.pairs@3.0.1(transitive)
+ Addedlodash.where@3.1.0(transitive)
+ Addedmake-iterator@1.0.1(transitive)
+ Addedmap-visit@1.0.0(transitive)
+ Addedminimist@1.2.8(transitive)
+ Addedms@2.0.0(transitive)
+ Addedmute-stream@0.0.5(transitive)
+ Addednumber-is-nan@1.0.1(transitive)
+ Addedobject-assign@4.1.1(transitive)
+ Addedobject-visit@1.0.1(transitive)
+ Addedomit-empty@0.3.60.4.1(transitive)
+ Addedonce@1.4.0(transitive)
+ Addedonetime@1.1.0(transitive)
+ Addedoption-cache@3.5.0(transitive)
+ Addedos-homedir@1.0.2(transitive)
+ Addedparse-git-config@1.1.1(transitive)
+ Addedparse-passwd@1.0.0(transitive)
+ Addedprocess-nextick-args@2.0.1(transitive)
+ Addedproject-name@0.2.6(transitive)
+ Addedreadable-stream@2.3.8(transitive)
+ Addedreadline2@1.0.1(transitive)
+ Addedreduce-object@0.1.3(transitive)
+ Addedremote-origin-url@0.5.3(transitive)
+ Addedresolve-dir@0.1.1(transitive)
+ Addedrestore-cursor@1.0.1(transitive)
+ Addedrun-async@0.1.0(transitive)
+ Addedrx-lite@4.0.8(transitive)
+ Addedsafe-buffer@5.1.2(transitive)
+ Addedset-getter@0.1.1(transitive)
+ Addedset-value@0.4.3(transitive)
+ Addedstring_decoder@1.1.1(transitive)
+ Addedstrip-ansi@3.0.1(transitive)
+ Addedstrip-color@0.1.0(transitive)
+ Addedsupports-color@2.0.0(transitive)
+ Addedthrough2@2.0.5(transitive)
+ Addedto-choices@0.2.0(transitive)
+ Addedto-object-path@0.3.0(transitive)
+ Addeduse@1.1.2(transitive)
+ Addedutil-deprecate@1.0.2(transitive)
+ Addedwhich@1.3.1(transitive)
+ Addedwrappy@1.0.2(transitive)
+ Addedxtend@4.0.2(transitive)
- Removedkind-of@^3.0.2
Updatedget-value@^2.0.5
Updatedhas-value@^0.3.1
Updatedinquirer2@^0.1.1
Updatedset-value@^0.3.3