🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
Book a DemoInstallSign in
Socket

wizard

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

wizard - npm Package Compare versions

Comparing version

to
2.0.0

10

example/src/index.js

@@ -5,8 +5,6 @@ import Wizard from '../../lib';

const main = async () => {
const wizard = new Wizard(questions);
const selections = await wizard.init();
const wizard = new Wizard(questions);
wizard.init().then(selections => {
console.log(selections);
};
main();
process.exit();
});

6

example/src/questions.js

@@ -9,3 +9,3 @@ export default {

],
next: {
then: {
template: {

@@ -35,3 +35,3 @@ question: 'Pick a template:',

],
next: {
then: {
testing: {

@@ -46,3 +46,3 @@ question: 'Which testing framework would you like to use?',

],
next: {
then: {
useReact: {

@@ -49,0 +49,0 @@ question: 'Will you be using react?',

@@ -16,65 +16,140 @@ "use strict";

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
class Component {
constructor(styles) {
this.styles = styles;
this.ansi = _ansiEscapes.default;
this.colors = _chalk.default;
this.keys = _keys.default; // Event Handlers
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
this._onKeyHandler = null;
this._onKeyEnter = null;
this._onKeyArrowUp = null;
this._onKeyArrowDown = null;
this._onKeyArrowLeft = null;
this._onKeyArrowRight = null;
this._onKeySpace = null;
} // Accessors
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
/** When the Enter key is pressed. */
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var Component =
/*#__PURE__*/
function () {
function Component() {
_classCallCheck(this, Component);
set onKeyEnter(handler) {
this._onKeyEnter = handler;
}
/** When the Up arrow is pressed. */
_defineProperty(this, "ansi", _ansiEscapes.default);
_defineProperty(this, "colors", _chalk.default);
set onKeyUp(handler) {
this._onKeyArrowUp = handler;
}
/** When the Down arrow is pressed. */
_defineProperty(this, "keys", _keys.default);
this.handleEscape();
set onKeyDown(handler) {
this._onKeyArrowDown = handler;
}
/** When the Left arrow is pressed. */
_createClass(Component, [{
key: "write",
value: function write(text) {
process.stdout.write("\r".concat(text));
set onKeyLeft(handler) {
this._onKeyArrowLeft = handler;
}
/** When the Right arrow is pressed. */
set onKeyRight(handler) {
this._onKeyArrow = handler;
}
/** When the Space key is pressed. */
set onKeySpace(handler) {
this._onKeySpace = handler;
} // Component Methods
/** Write text to screen. */
write(text) {
process.stdout.write(`\r${text}`);
}
/** Write a newline to the screen. */
newline() {
this.write('\n');
}
/** Clear a components output. */
clear() {
if (this.styles.preserveQuestion) {
this.write(this.ansi.cursorUp());
}
}, {
key: "newline",
value: function newline() {
process.stdout.write('\r\n');
}
}, {
key: "cleanAndExit",
value: function cleanAndExit() {
process.stdout.write(_ansiEscapes.default.cursorShow);
process.exit();
} // Ensure app is killable
}, {
key: "handleEscape",
value: function handleEscape() {
var _this = this;
this.write(this.ansi.eraseDown);
}
/** Exit gracefully. */
process.stdin.on('data', function (key) {
switch (key) {
case _keys.default.KEY_ESC:
_this.cleanAndExit();
break;
cleanAndExit() {
this.write(this.ansi.cursorShow);
process.exit();
}
/** Throw error */
default:
break;
}
});
throw(err) {
throw err;
}
/**
* Initializes the component.
* Registers event listeners and prints question.
* @param {string} question
*/
initialize(question) {
this.write(this.ansi.eraseLine);
this.write(this.styles.question.color(question));
this.newline();
this.update();
this._onKeyHandler = this.onKeyHandler.bind(this);
process.stdin.addListener('data', this._onKeyHandler);
}
onKeyHandler(key) {
switch (key) {
case this.keys.KEY_UP:
return this._onKeyArrowUp ? this._onKeyArrowUp() : null;
case this.keys.KEY_DOWN:
return this._onKeyArrowDown ? this._onKeyArrowDown() : null;
case this.keys.KEY_LEFT:
return this._onKeyArrowLeft ? this._onKeyArrowLeft() : null;
case this.keys.KEY_RIGHT:
return this._onKeyArrowRight ? this._onKeyArrowRight() : null;
case this.keys.KEY_SPACE:
return this._onKeySpace ? this._onKeySpace() : null;
case this.keys.KEY_ENTER:
case this.keys.KEY_RETURN:
process.stdin.removeListener('data', this._onKeyHandler);
return this._onKeyEnter ? this._onKeyEnter() : this.throw(new Error('Keypress Unhandled'));
case this.keys.CTRL_C:
this.cleanAndExit();
return null;
default:
return null;
}
}]);
}
return Component;
}();
}
var _default = Component;
exports.default = _default;

@@ -8,117 +8,59 @@ "use strict";

var _Component2 = _interopRequireDefault(require("./Component"));
var _Component = _interopRequireDefault(require("./Component"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
class List extends _Component.default {
constructor(question, styles) {
super(styles);
this.styles = styles;
this.question = question.question;
this.options = question.options;
this.chosen = 0;
}
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
init() {
return new Promise(resolve => {
this.onKeyEnter = () => {
this.clear();
resolve(this.options[this.chosen]);
};
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
this.onKeyUp = () => {
this.chosen = this.chosen === 0 ? this.styles.list.wrapToTop ? this.options.length - 1 : 0 : this.chosen - 1;
this.update();
};
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
this.onKeyDown = () => {
this.chosen = this.chosen === this.options.length - 1 ? this.styles.list.wrapToTop ? 0 : this.options.length - 1 : this.chosen + 1;
this.update();
};
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
var List =
/*#__PURE__*/
function (_Component) {
_inherits(List, _Component);
function List(question, styles) {
var _this;
_classCallCheck(this, List);
_this = _possibleConstructorReturn(this, _getPrototypeOf(List).call(this));
_this.styles = styles;
_this.question = question.question;
_this.options = question.options;
_this.chosen = 0;
return _this;
this.initialize(this.question);
});
}
_createClass(List, [{
key: "init",
value: function init() {
var _this2 = this;
update() {
this.options.forEach((option, index) => {
this.write(this.ansi.eraseLine);
const formatted = option.name.padStart(option.name.length + this.styles.list.paddingLeft, ' '.repeat(this.styles.list.paddingLeft));
return new Promise(function (resolve) {
_this2.write(_this2.styles.question.color(_this2.question));
_this2.newline();
process.stdin.on('data', function (key) {
var value = _this2.handleInput(key);
if (value !== null) {
resolve(value);
}
});
_this2.updateDisplay();
});
}
}, {
key: "updateDisplay",
value: function updateDisplay() {
var _this3 = this;
this.options.forEach(function (option, index) {
var formatted = option.name;
formatted = formatted.padStart(formatted.length + _this3.styles.list.paddingLeft, ' '.repeat(_this3.styles.list.paddingLeft));
if (index === _this3.chosen) {
if (_this3.styles.caret.icon) {
_this3.write(_this3.styles.caret.color(_this3.styles.caret.icon.padStart(_this3.styles.caret.paddingLeft + 1, ' '.repeat(_this3.styles.caret.paddingLeft))) + ' '.repeat(_this3.styles.caret.paddingRight) + _this3.styles.list.selectedColor(option.name));
} else {
_this3.write(_this3.styles.list.selectedColor(formatted));
}
if (index === this.chosen) {
if (this.styles.caret.icon) {
this.write(this.styles.caret.color(this.styles.caret.icon.padStart(this.styles.caret.paddingLeft + 1, ' '.repeat(this.styles.caret.paddingLeft))) + ' '.repeat(this.styles.caret.paddingRight) + this.styles.list.selectedColor(option.name));
} else {
_this3.write(_this3.styles.list.defaultColor(formatted));
this.write(this.styles.list.selectedColor(formatted));
}
} else {
this.write(this.styles.list.defaultColor(formatted));
}
_this3.newline();
});
this.write(this.ansi.cursorUp(this.options.length));
}
}, {
key: "handleInput",
value: function handleInput(key) {
switch (key) {
case this.keys.KEY_UP:
this.chosen = this.chosen === 0 ? this.styles.list.wrapToTop ? this.options.length - 1 : 0 : this.chosen - 1;
this.updateDisplay();
return null;
this.newline();
});
this.write(this.ansi.cursorUp(this.options.length));
}
case this.keys.KEY_DOWN:
this.chosen = this.chosen === this.options.length - 1 ? this.styles.list.wrapToTop ? 0 : this.options.length - 1 : this.chosen + 1;
this.updateDisplay();
return null;
}
case this.keys.KEY_RETURN:
case this.keys.KEY_ENTER:
this.write(this.ansi.eraseDown);
process.stdin.removeAllListeners('data');
this.handleEscape();
return this.options[this.chosen];
default:
return null;
}
}
}]);
return List;
}(_Component2.default);
var _default = List;
exports.default = _default;

@@ -8,131 +8,74 @@ "use strict";

var _Component2 = _interopRequireDefault(require("./Component"));
var _Component = _interopRequireDefault(require("./Component"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
class ListToggle extends _Component.default {
constructor(question, styles) {
super(styles);
this.styles = styles;
this.question = question.question;
this.options = question.options;
this.selected = new Array(this.options.length);
this.chosen = 0;
}
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
init() {
return new Promise(resolve => {
this.onKeyEnter = () => {
this.clear();
resolve({
value: this.selected.filter(Boolean),
then: this.options[0].then
});
};
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
this.onKeyUp = () => {
this.chosen = this.chosen === 0 ? this.styles.list.wrapToTop ? this.options.length - 1 : 0 : this.chosen - 1;
this.update();
};
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
this.onKeyDown = () => {
this.chosen = this.chosen === this.options.length - 1 ? this.styles.list.wrapToTop ? 0 : this.options.length - 1 : this.chosen + 1;
this.update();
};
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
this.onKeySpace = () => {
this.selected[this.chosen] = this.selected[this.chosen] ? null : this.options[this.chosen].value;
};
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
var ListToggle =
/*#__PURE__*/
function (_Component) {
_inherits(ListToggle, _Component);
function ListToggle(question, styles) {
var _this;
_classCallCheck(this, ListToggle);
_this = _possibleConstructorReturn(this, _getPrototypeOf(ListToggle).call(this));
_this.styles = styles;
_this.question = question.question;
_this.options = question.options;
_this.selected = new Array(_this.options.length);
_this.chosen = 0;
return _this;
this.initialize(this.question);
});
}
_createClass(ListToggle, [{
key: "init",
value: function init() {
var _this2 = this;
update() {
this.options.forEach((option, index) => {
this.write(this.ansi.eraseLine);
let formatted = option.name;
formatted = formatted.padStart(formatted.length + this.styles.list.paddingLeft, ' '.repeat(this.styles.list.paddingLeft));
return new Promise(function (resolve) {
_this2.write(_this2.styles.question.color(_this2.question));
_this2.newline();
process.stdin.on('data', function (key) {
var value = _this2.handleInput(key);
if (value !== null) {
resolve(value);
}
});
_this2.updateDisplay();
});
}
}, {
key: "updateDisplay",
value: function updateDisplay() {
var _this3 = this;
this.options.forEach(function (option, index) {
var formatted = option.name;
formatted = formatted.padStart(formatted.length + _this3.styles.list.paddingLeft, ' '.repeat(_this3.styles.list.paddingLeft));
if (index === _this3.chosen) {
if (_this3.styles.caret.icon) {
_this3.write(_this3.styles.caret.color(_this3.styles.caret.icon.padStart(_this3.styles.caret.paddingLeft + _this3.styles.caret.paddingLeft, ' '.repeat(_this3.styles.caret.paddingLeft))) + ' '.repeat(_this3.styles.caret.paddingRight) + _this3.styles.list.selectedColor(option.name));
} else {
_this3.write(_this3.styles.list.selectedColor(formatted));
}
} else if (_this3.selected[index]) {
if (_this3.styles.list.toggle.icon) {
_this3.write(_this3.styles.list.toggle.color(_this3.styles.list.toggle.icon.padStart(_this3.styles.list.toggle.paddingLeft + 1, ' '.repeat(_this3.styles.list.toggle.paddingLeft))) + ' '.repeat(_this3.styles.list.toggle.paddingRight) + _this3.styles.list.toggledColor(option.name));
} else {
_this3.write(_this3.styles.list.toggledColor(formatted));
}
if (index === this.chosen) {
if (this.styles.caret.icon) {
this.write(this.styles.caret.color(this.styles.caret.icon.padStart(this.styles.caret.paddingLeft + this.styles.caret.paddingLeft, ' '.repeat(this.styles.caret.paddingLeft))) + ' '.repeat(this.styles.caret.paddingRight) + this.styles.list.selectedColor(option.name));
} else {
_this3.write(_this3.styles.list.defaultColor(formatted));
this.write(this.styles.list.selectedColor(formatted));
}
} else if (this.selected[index]) {
if (this.styles.list.toggle.icon) {
this.write(this.styles.list.toggle.color(this.styles.list.toggle.icon.padStart(this.styles.list.toggle.paddingLeft + 1, ' '.repeat(this.styles.list.toggle.paddingLeft))) + ' '.repeat(this.styles.list.toggle.paddingRight) + this.styles.list.toggledColor(option.name));
} else {
this.write(this.styles.list.toggledColor(formatted));
}
} else {
this.write(this.styles.list.defaultColor(formatted));
}
_this3.newline();
});
this.write(this.ansi.cursorUp(this.options.length));
}
}, {
key: "handleInput",
value: function handleInput(key) {
switch (key) {
case this.keys.KEY_UP:
this.chosen = this.chosen === 0 ? this.styles.list.wrapToTop ? this.options.length - 1 : 0 : this.chosen - 1;
this.updateDisplay();
return null;
this.newline();
});
this.write(this.ansi.cursorUp(this.options.length));
}
case this.keys.KEY_DOWN:
this.chosen = this.chosen === this.options.length - 1 ? this.styles.list.wrapToTop ? 0 : this.options.length - 1 : this.chosen + 1;
this.updateDisplay();
return null;
}
case this.keys.KEY_SPACE:
this.selected[this.chosen] = this.selected[this.chosen] ? null : this.options[this.chosen].value;
return null;
case this.keys.KEY_RETURN:
case this.keys.KEY_ENTER:
this.write(this.ansi.eraseDown);
process.stdin.removeAllListeners('data');
this.handleEscape();
return {
value: this.selected.filter(Boolean),
then: this.options[0].then
};
default:
return null;
}
}
}]);
return ListToggle;
}(_Component2.default);
var _default = ListToggle;
exports.default = _default;

@@ -8,3 +8,3 @@ "use strict";

var _Component2 = _interopRequireDefault(require("./Component"));
var _Component = _interopRequireDefault(require("./Component"));

@@ -17,47 +17,16 @@ var _List = _interopRequireDefault(require("./List"));

function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
var Wizard =
/*#__PURE__*/
function (_Component) {
_inherits(Wizard, _Component);
function Wizard(steps, styles, components) {
var _this;
_classCallCheck(this, Wizard);
_this = _possibleConstructorReturn(this, _getPrototypeOf(Wizard).call(this));
_this.components = _objectSpread({
list: _List.default,
listToggle: _ListToggle.default
}, components);
var styleDefaults = {
// TODO - Add tests
class Wizard extends _Component.default {
constructor(steps, styles, components) {
super(styles);
const styleDefaults = {
preserveAnswer: true,
question: {
color: this.colors.white,
prefix: '',
paddingLeft: 0
},
caret: {
icon: '❯',
color: _this.colors.white,
color: this.colors.white,
paddingRight: 1,

@@ -68,133 +37,90 @@ paddingLeft: 0

wrapToTop: false,
defaultColor: _this.colors.gray,
selectedColor: _this.colors.white,
toggledColor: _this.colors.red,
preserveAnswer: true,
defaultColor: this.colors.gray,
selectedColor: this.colors.white,
toggledColor: this.colors.red,
paddingLeft: 2,
toggle: {
icon: '*',
color: _this.colors.red,
color: this.colors.red,
paddingRight: 1,
paddingLeft: 0
}
},
question: {
color: _this.colors.white,
prefix: '',
paddingLeft: 0
}
};
_this.styles = _objectSpread({}, styleDefaults, styles);
_this.steps = steps;
_this.selections = {};
return _this;
this.components = {
list: _List.default,
listToggle: _ListToggle.default,
...components
};
this.styles = { ...styleDefaults,
...styles
};
this.steps = steps;
this.selections = {};
}
_createClass(Wizard, [{
key: "init",
value: function init() {
process.stdin.setRawMode(true);
process.stdin.resume();
process.stdin.setEncoding('utf8');
this.write(this.ansi.cursorHide);
this.handleEscape();
return this.traverse(this.steps);
}
}, {
key: "traverse",
value: function traverse(section) {
var _this2 = this;
async init() {
process.stdin.setRawMode(true);
process.stdin.resume();
process.stdin.setEncoding('utf8');
this.write(this.ansi.cursorHide);
const selections = await this.traverse(this.steps);
return selections;
}
return new Promise(
/*#__PURE__*/
function () {
var _ref = _asyncToGenerator(
/*#__PURE__*/
regeneratorRuntime.mark(function _callee(resolve, reject) {
var ComponentType, component, response;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
if (!_this2.validateSection(section)) {
_this2.write('Error in Configuration');
async traverse(section) {
try {
return new Promise(async (resolve, reject) => {
if (!this.validateSection(section)) {
this.cleanAndExit();
throw new Error('Invalid configuration');
}
_this2.cleanAndExit();
}
const ComponentType = this.components[section.type];
ComponentType = _this2.components[section.type];
if (ComponentType) {
const component = new ComponentType(section, this.styles);
const response = await component.init();
this.selections[section.id] = response.value;
if (!ComponentType) {
_context.next = 21;
break;
}
if (section.then && section.then[response.then]) {
resolve((await this.traverse(section.then[response.then])));
return null;
}
component = new ComponentType(section, _this2.styles);
_context.next = 6;
return component.init();
if (!response.then) {
this.write(this.ansi.cursorShow);
resolve(this.selections);
return null;
}
case 6:
response = _context.sent;
_this2.selections[section.id] = response.value;
if (!section.then) {
this.write(this.ansi.cursorShow);
reject(new Error('Invalid configuration'));
return null;
}
if (response.then) {
_context.next = 12;
break;
}
this.write(this.ansi.cursorShow);
reject(new Error('An unknown error occured'));
return null;
}
_this2.write(_this2.ansi.cursorShow);
this.write(this.ansi.cursorShow);
reject(new Error('Invalid configuration'));
return null;
});
} catch (err) {
this.write(this.colors.red(err));
this.cleanAndExit();
return null;
}
}
resolve(_this2.selections);
return _context.abrupt("return", null);
validateSection(section) {
return (section.question || section.options || section.id || section.type) && true;
}
case 12:
if (!section.next[response.then]) {
_context.next = 18;
break;
}
}
_context.t0 = resolve;
_context.next = 16;
return _this2.traverse(section.next[response.then]);
case 16:
_context.t1 = _context.sent;
(0, _context.t0)(_context.t1);
case 18:
_this2.write(_this2.ansi.cursorShow);
reject();
return _context.abrupt("return", null);
case 21:
_this2.write(_this2.ansi.cursorShow);
reject();
return _context.abrupt("return", null);
case 24:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
return function (_x, _x2) {
return _ref.apply(this, arguments);
};
}());
}
}, {
key: "validateSection",
value: function validateSection(section) {
return (section.question || section.options || section.id || section.type) && true;
}
}]);
return Wizard;
}(_Component2.default);
var _default = Wizard;
exports.default = _default;

@@ -7,13 +7,13 @@ "use strict";

exports.default = void 0;
var ESC = "\x1B";
const ESC = '\u001B';
var _default = {
KEY_UP: "".concat(ESC, "[A"),
KEY_DOWN: "".concat(ESC, "[B"),
KEY_RIGHT: "".concat(ESC, "[C"),
KEY_LEFT: "".concat(ESC, "[D"),
KEY_ENTER: "\u2324",
KEY_RETURN: "\r",
KEY_SPACE: " ",
KEY_ESC: "\x03"
KEY_UP: `${ESC}[A`,
KEY_DOWN: `${ESC}[B`,
KEY_RIGHT: `${ESC}[C`,
KEY_LEFT: `${ESC}[D`,
KEY_ENTER: '\u2324',
KEY_RETURN: '\u000D',
KEY_SPACE: '\u0020',
CTRL_C: '\u0003'
};
exports.default = _default;

@@ -8,3 +8,3 @@ "use strict";

enumerable: true,
get: function get() {
get: function () {
return _Component.default;

@@ -15,4 +15,2 @@ }

require("@babel/polyfill");
var _Wizard = _interopRequireDefault(require("./components/Wizard"));

@@ -19,0 +17,0 @@

{
"name": "wizard",
"version": "1.0.0",
"version": "2.0.0",
"description": "Wizard is a highly configurable library for building complex CLI based installation/setup wizards",
"main": "lib/index.js",
"scripts": {
"start": "babel src -d lib -w",
"start": "npm run build && npm run build:example && node example/build",
"watch": "babel src -d lib -w",
"build": "babel src -d lib",
"build:demo": "babel example/src -d build",
"watch:example": "babel example/src -d example/build -w",
"build:example": "babel example/src -d example/build",
"precommit": "lint-staged",

@@ -31,8 +33,6 @@ "prepare": "npm run build"

"@babel/core": "^7.0.0",
"@babel/plugin-proposal-class-properties": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"babel-eslint": "^9.0.0",
"eslint": "^5.5.0",
"eslint-config-airbnb-base": "^13.1.0",
"eslint-plugin-import": "^2.14.0",
"eslint-config-prettier": "^3.4.0",
"husky": "^0.14.3",

@@ -43,3 +43,2 @@ "lint-staged": "^7.2.2",

"dependencies": {
"@babel/polyfill": "^7.0.0",
"ansi-escapes": "^3.1.0",

@@ -46,0 +45,0 @@ "chalk": "^2.4.1"

@@ -21,9 +21,7 @@ <div align="center">

const main = async () => {
const wizard = new Wizard(questions);
const selections = await wizard.init();
const wizard = new Wizard(questions);
wizard.init().then(selections => {
console.log(selections);
};
main();
process.exit();
});
```

@@ -56,4 +54,4 @@

- **question** (string) Your question
- **id** (string) The variable name that the answer will be stored under.
- **type** (string) The type of input asociated with this question (See _Input types_).
- **id** (string) The key that the answer will be stored under.
- **type** (string) The input component type (See _Input types_).

@@ -72,25 +70,31 @@ Depending on the input type, you may be required to have:

```
question: 'My question'
id: 'my-question',
type: 'list',
options: [
{ name: 'Answer 1', value: 'answer-1', then: 'question2' },
{ name: 'Answer 2', value: 'answer-2', then: 'question3' },
],
then: {
question2: {
question: 'Question 2',
id: 'question-2',
type: 'text',
},
question3: {
question: 'Question 3',
id: 'question-3',
type: 'list',
options: [
{ name: 'Answer 1, value: 'answer-1' },
{ name: 'Answer 2, value: 'answer-2' },
{ name: 'Answer 3, value: 'answer-3' },
{ name: 'Answer 4, value: 'answer-4' },
]
{
question: 'My question',
id: 'my-question',
type: 'list',
options: [
{ name: 'Answer 1', value: 'answer-1', then: 'question2' },
{ name: 'Answer 2', value: 'answer-2', then: 'question3' },
],
then: {
question2: {
question: 'Question 2',
id: 'question-2',
type: 'list',
options: [
{ name: 'Answer 1', value: 'answer-1' },
{ name: 'Answer 2', value: 'answer-2' },
]
},
question3: {
question: 'Question 3',
id: 'question-3',
type: 'list',
options: [
{ name: 'Answer 1', value: 'answer-1' },
{ name: 'Answer 2', value: 'answer-2' },
{ name: 'Answer 3', value: 'answer-3' },
{ name: 'Answer 4', value: 'answer-4' },
]
}
}

@@ -106,2 +110,8 @@ }

{
preserveAnswer: bool - Preserve the previous question when finished
question: {
color: function - The color of the question
prefex: string - Question text prefix
paddingLeft: int - Left padding for question
}
caret : {

@@ -112,3 +122,3 @@ icon: string - The character representing the caret

paddingLeft: int - Left padding for the caret
},
}
list: {

@@ -119,3 +129,2 @@ wrapToTop: bool - Whether the caret wraps to top

toggledColor: function - The color of toggled items
preserveAnswer: bool - Whether the previous questions and answers are printed
paddingLeft: int - Left padding for the whole list

@@ -148,40 +157,32 @@ toggle: {

### Custom Components
## Custom Inputs
You can make your very own personalized inputs if you can't achieve what you wish through styling. A `Component` class is made available through: `import { Component } from 'wizard` that allows you to create and use your own inputs.
You can make your very own personalized inputs if the ones provided don't suit your needs. A `Component` class is available by importing it - `import { Component } from 'wizard`. It provides a number of methods and events to extend wizard however you wish.
Each Input must have an `init` method.
Each Input must have an `init` and an `update` method.
- **init** A method that starts your input - This must be a promise!
- **init()** Starts your input component - This is a promise that will return the users selected or provided input.
- **update()** Repaints the screen. Leave empty if making a simple input.
To create a basic component:
```
```javascript
import { Component } from 'wizard';
class MyComponent extends Component {
constructor() {
super();
}
init() {
return new Promise(resolve => {
this.write('Welcome to my component!');
this.newline();
this.onKeySpace = () => {
this.write('Space Pressed!');
}
process.stdin.on('data', key => {
const value = this.handleInput(key);
if (value !== null) {
resolve(value);
}
});
this.initialize('My new input!');
});
}
handleInput(key) {
switch(key) {
this.keys.KEY_SPACE:
this.write(this.colors.red('Space pressed'));
this.newline();
return 'some value';
default:
return null;
}
}
update() {}
}

@@ -209,2 +210,48 @@ ```

For coloring, we make the `chalk` library useful by way of `this.color`. Check out the library here: https://github.com/chalk/chalk
### Methods
The `Component` class provides a number of methods to use when creating your input.
#### `initialize(question)` Initialize the component.
- **question** (string) The questions text.
#### `write(text)` Write string to screen.
- **text** (string) Text to write to the screen.
#### `newline()` Write a newline to the screen.
#### `clear()` Clear the components output.
#### `cleanAndExit()` Restore the cursor and gracefully exit.
### Events
A number of `keyPress` events can be handled. The only manditory handler is for `onKeyEnter`. This must resolve the component and clear the screen for the next question. The following event handlers are available:
- **onKeyEnter**
- **onKeyUp**
- **onKeyDown**
- **onKeyLeft**
- **onKeyRight**
- **onKeySpace**
Example:
```javascript
this.onKeyEnter = () => {
this.clear();
resolve('test');
}
```
---
We use the `chalk` library for coloring, and `ansi-escapes` for cursor manipulation. Access them through `this.color` and `this.ansi` respectively.

@@ -7,12 +7,55 @@ import ansiEscapes from 'ansi-escapes';

class Component {
constructor() {
this.handleEscape();
constructor(styles) {
this.styles = styles;
this.ansi = ansiEscapes;
this.colors = chalk;
this.keys = keys;
// Event Handlers
this._onKeyHandler = null;
this._onKeyEnter = null;
this._onKeyArrowUp = null;
this._onKeyArrowDown = null;
this._onKeyArrowLeft = null;
this._onKeyArrowRight = null;
this._onKeySpace = null;
}
ansi = ansiEscapes;
// Accessors
colors = chalk;
/** When the Enter key is pressed. */
set onKeyEnter(handler) {
this._onKeyEnter = handler;
}
keys = keys;
/** When the Up arrow is pressed. */
set onKeyUp(handler) {
this._onKeyArrowUp = handler;
}
/** When the Down arrow is pressed. */
set onKeyDown(handler) {
this._onKeyArrowDown = handler;
}
/** When the Left arrow is pressed. */
set onKeyLeft(handler) {
this._onKeyArrowLeft = handler;
}
/** When the Right arrow is pressed. */
set onKeyRight(handler) {
this._onKeyArrow = handler;
}
/** When the Space key is pressed. */
set onKeySpace(handler) {
this._onKeySpace = handler;
}
// Component Methods
/** Write text to screen. */
write(text) {

@@ -22,25 +65,68 @@ process.stdout.write(`\r${text}`);

/** Write a newline to the screen. */
newline() {
process.stdout.write('\r\n');
this.write('\n');
}
/** Clear a components output. */
clear() {
if (this.styles.preserveQuestion) {
this.write(this.ansi.cursorUp());
}
this.write(this.ansi.eraseDown);
}
/** Exit gracefully. */
cleanAndExit() {
process.stdout.write(ansiEscapes.cursorShow);
this.write(this.ansi.cursorShow);
process.exit();
}
// Ensure app is killable
handleEscape() {
process.stdin.on('data', key => {
switch (key) {
case keys.KEY_ESC:
this.cleanAndExit();
break;
default:
break;
}
});
/** Throw error */
throw(err) {
throw err;
}
/**
* Initializes the component.
* Registers event listeners and prints question.
* @param {string} question
*/
initialize(question) {
this.write(this.ansi.eraseLine);
this.write(this.styles.question.color(question));
this.newline();
this.update();
this._onKeyHandler = this.onKeyHandler.bind(this);
process.stdin.addListener('data', this._onKeyHandler);
}
onKeyHandler(key) {
switch (key) {
case this.keys.KEY_UP:
return this._onKeyArrowUp ? this._onKeyArrowUp() : null;
case this.keys.KEY_DOWN:
return this._onKeyArrowDown ? this._onKeyArrowDown() : null;
case this.keys.KEY_LEFT:
return this._onKeyArrowLeft ? this._onKeyArrowLeft() : null;
case this.keys.KEY_RIGHT:
return this._onKeyArrowRight ? this._onKeyArrowRight() : null;
case this.keys.KEY_SPACE:
return this._onKeySpace ? this._onKeySpace() : null;
case this.keys.KEY_ENTER:
case this.keys.KEY_RETURN:
process.stdin.removeListener('data', this._onKeyHandler);
return this._onKeyEnter
? this._onKeyEnter()
: this.throw(new Error('Keypress Unhandled'));
case this.keys.CTRL_C:
this.cleanAndExit();
return null;
default:
return null;
}
}
}
export default Component;

@@ -5,3 +5,3 @@ import Component from './Component';

constructor(question, styles) {
super();
super(styles);

@@ -17,21 +17,37 @@ this.styles = styles;

return new Promise(resolve => {
this.write(this.styles.question.color(this.question));
this.newline();
this.onKeyEnter = () => {
this.clear();
resolve(this.options[this.chosen]);
};
process.stdin.on('data', key => {
const value = this.handleInput(key);
if (value !== null) {
resolve(value);
}
});
this.onKeyUp = () => {
this.chosen =
this.chosen === 0
? this.styles.list.wrapToTop
? this.options.length - 1
: 0
: this.chosen - 1;
this.update();
};
this.updateDisplay();
this.onKeyDown = () => {
this.chosen =
this.chosen === this.options.length - 1
? this.styles.list.wrapToTop
? 0
: this.options.length - 1
: this.chosen + 1;
this.update();
};
this.initialize(this.question);
});
}
updateDisplay() {
update() {
this.options.forEach((option, index) => {
let formatted = option.name;
formatted = formatted.padStart(
formatted.length + this.styles.list.paddingLeft,
this.write(this.ansi.eraseLine);
const formatted = option.name.padStart(
option.name.length + this.styles.list.paddingLeft,
' '.repeat(this.styles.list.paddingLeft),

@@ -58,41 +74,8 @@ );

}
this.newline();
});
this.write(this.ansi.cursorUp(this.options.length));
}
handleInput(key) {
switch (key) {
case this.keys.KEY_UP:
this.chosen =
this.chosen === 0
? this.styles.list.wrapToTop
? this.options.length - 1
: 0
: this.chosen - 1;
this.updateDisplay();
return null;
case this.keys.KEY_DOWN:
this.chosen =
this.chosen === this.options.length - 1
? this.styles.list.wrapToTop
? 0
: this.options.length - 1
: this.chosen + 1;
this.updateDisplay();
return null;
case this.keys.KEY_RETURN:
case this.keys.KEY_ENTER:
this.write(this.ansi.eraseDown);
process.stdin.removeAllListeners('data');
this.handleEscape();
return this.options[this.chosen];
default:
return null;
}
}
}
export default List;

@@ -5,3 +5,3 @@ import Component from './Component';

constructor(question, styles) {
super();
super(styles);

@@ -18,18 +18,44 @@ this.styles = styles;

return new Promise(resolve => {
this.write(this.styles.question.color(this.question));
this.newline();
this.onKeyEnter = () => {
this.clear();
resolve({
value: this.selected.filter(Boolean),
then: this.options[0].then,
});
};
process.stdin.on('data', key => {
const value = this.handleInput(key);
if (value !== null) {
resolve(value);
}
});
this.onKeyUp = () => {
this.chosen =
this.chosen === 0
? this.styles.list.wrapToTop
? this.options.length - 1
: 0
: this.chosen - 1;
this.update();
};
this.updateDisplay();
this.onKeyDown = () => {
this.chosen =
this.chosen === this.options.length - 1
? this.styles.list.wrapToTop
? 0
: this.options.length - 1
: this.chosen + 1;
this.update();
};
this.onKeySpace = () => {
this.selected[this.chosen] = this.selected[this.chosen]
? null
: this.options[this.chosen].value;
};
this.initialize(this.question);
});
}
updateDisplay() {
update() {
this.options.forEach((option, index) => {
this.write(this.ansi.eraseLine);
let formatted = option.name;

@@ -74,49 +100,8 @@ formatted = formatted.padStart(

}
this.newline();
});
this.write(this.ansi.cursorUp(this.options.length));
}
handleInput(key) {
switch (key) {
case this.keys.KEY_UP:
this.chosen =
this.chosen === 0
? this.styles.list.wrapToTop
? this.options.length - 1
: 0
: this.chosen - 1;
this.updateDisplay();
return null;
case this.keys.KEY_DOWN:
this.chosen =
this.chosen === this.options.length - 1
? this.styles.list.wrapToTop
? 0
: this.options.length - 1
: this.chosen + 1;
this.updateDisplay();
return null;
case this.keys.KEY_SPACE:
this.selected[this.chosen] = this.selected[this.chosen]
? null
: this.options[this.chosen].value;
return null;
case this.keys.KEY_RETURN:
case this.keys.KEY_ENTER:
this.write(this.ansi.eraseDown);
process.stdin.removeAllListeners('data');
this.handleEscape();
return {
value: this.selected.filter(Boolean),
then: this.options[0].then,
};
default:
return null;
}
}
}
export default ListToggle;

@@ -0,1 +1,3 @@

// TODO - Add tests
import Component from './Component';

@@ -8,11 +10,11 @@

constructor(steps, styles, components) {
super();
super(styles);
this.components = {
list,
listToggle,
...components,
};
const styleDefaults = {
preserveAnswer: true,
question: {
color: this.colors.white,
prefix: '',
paddingLeft: 0,
},
caret: {

@@ -29,3 +31,2 @@ icon: '❯',

toggledColor: this.colors.red,
preserveAnswer: true,
paddingLeft: 2,

@@ -39,5 +40,10 @@ toggle: {

},
question: { color: this.colors.white, prefix: '', paddingLeft: 0 },
};
this.components = {
list,
listToggle,
...components,
};
this.styles = {

@@ -52,3 +58,3 @@ ...styleDefaults,

init() {
async init() {
process.stdin.setRawMode(true);

@@ -59,38 +65,47 @@ process.stdin.resume();

this.handleEscape();
const selections = await this.traverse(this.steps);
return this.traverse(this.steps);
return selections;
}
traverse(section) {
return new Promise(async (resolve, reject) => {
if (!this.validateSection(section)) {
this.write('Error in Configuration');
this.cleanAndExit();
}
async traverse(section) {
try {
return new Promise(async (resolve, reject) => {
if (!this.validateSection(section)) {
this.cleanAndExit();
throw new Error('Invalid configuration');
}
const ComponentType = this.components[section.type];
if (ComponentType) {
const component = new ComponentType(section, this.styles);
const response = await component.init();
this.selections[section.id] = response.value;
const ComponentType = this.components[section.type];
if (ComponentType) {
const component = new ComponentType(section, this.styles);
const response = await component.init();
this.selections[section.id] = response.value;
if (!response.then) {
if (section.then && section.then[response.then]) {
resolve(await this.traverse(section.then[response.then]));
return null;
}
if (!response.then) {
this.write(this.ansi.cursorShow);
resolve(this.selections);
return null;
}
if (!section.then) {
this.write(this.ansi.cursorShow);
reject(new Error('Invalid configuration'));
return null;
}
this.write(this.ansi.cursorShow);
resolve(this.selections);
reject(new Error('An unknown error occured'));
return null;
}
if (section.next[response.then]) {
resolve(await this.traverse(section.next[response.then]));
}
this.write(this.ansi.cursorShow);
reject();
reject(new Error('Invalid configuration'));
return null;
}
this.write(this.ansi.cursorShow);
reject();
});
} catch (err) {
this.write(this.colors.red(err));
this.cleanAndExit();
return null;
});
}
}

@@ -97,0 +112,0 @@

@@ -11,3 +11,3 @@ const ESC = '\u001B';

KEY_SPACE: '\u0020',
KEY_ESC: '\u0003',
CTRL_C: '\u0003',
};

@@ -1,3 +0,1 @@

import '@babel/polyfill';
import Wizard from './components/Wizard';

@@ -4,0 +2,0 @@ import Component from './components/Component';

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet