Socket
Socket
Sign inDemoInstall

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 1.0.0 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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc