UNPKG

suman-interactive

Version:

Suman interactive project to guide users through advanced use cases

328 lines (257 loc) 9.74 kB
'use strict'; //polyfills const process = require('suman-browser-polyfills/modules/process'); const global = require('suman-browser-polyfills/modules/global'); //core const assert = require('assert'); const util = require('util'); const fs = require('fs'); const path = require('path'); const cp = require('child_process'); //npm const async = require('async'); const colors = require('colors/safe'); //project const _suman = global.__suman = (global.__suman || {}); const rejectionHandler = require('./interactive-rejection-handler'); const choices = require('./helpers/choices'); const su = require('suman-utils'); //////////////////////////////////////////////////////////////////////// process.on('warning', function (w) { if (su.weAreDebugging) { // if we are debugging, log all warnings console.log(' => Suman interactive warning => ', w.stack || w); } else if (!(/deprecated/i.test(String(w)))) { //there were some really useless warnings about deprecation console.log(' => Suman interactive warning => ', w.stack || w); } }); ////////////////////////////////////////////////////// process.stdin.setMaxListeners(20); /////////////////////////////////////////////////////// const interactiveDebugPath = path.resolve(__dirname + '/helpers/debug-interactive.log'); fs.writeFileSync(interactiveDebugPath, '\n new run \n', {flag: 'w'}); _suman._interactiveDebug = function () { fs.writeFileSync(interactiveDebugPath, '\n\n', {flag: 'a'}); const args = Array.from(arguments); const data = args.map(function (a) { return (typeof a === 'string' ? a : util.inspect(a)); }).join('\n'); fs.writeFileSync(interactiveDebugPath, data, {flag: 'a'}) }; _suman.onBackspace = function (cb) { process.stdin.listeners('readable').forEach(function (fn) { if (process.stdin.listenerCount('readable') > 4) process.stdin.removeListener('readable', fn); }); process.stdin.listeners('close').forEach(function (fn) { if (process.stdin.listenerCount('close') > 4) process.stdin.removeListener('close', fn); }); process.stdin.listeners('keypress').forEach(function (fn) { if (process.stdin.listenerCount('keypress') > 4) process.stdin.removeListener('keypress', fn); }); process.stdin.listeners('exit').forEach(function (fn) { if (process.stdin.listenerCount('exit') > 4) process.stdin.removeListener('exit', fn); }); process.stdin.listeners('end').forEach(function (fn) { if (process.stdin.listenerCount('end') > 4) process.stdin.removeListener('end', fn); }); process.nextTick(cb); }; _suman._implementationError = function (msg) { msg = msg || ''; msg = typeof msg === 'string' ? msg : util.inspect(msg); throw new Error(colors.red(' => Suman interactive internal implementation problem ' + (msg || '.'))); }; exports.start = function () { _suman._interactiveDebug(' => beginning of interactive session => '); ////////////////////////////////////////////////////// const testDir = _suman.sumanConfig.testDir; let rootDir; try { rootDir = path.resolve(_suman.projectRoot + '/' + testDir); if (!(fs.statSync(rootDir).isDirectory())) { throw new Error('Path given by => "' + rootDir + '" is not a directory'); } } catch (err) { rootDir = _suman.projectRoot; } console.log('\n'); const loadingMessage = colors.bgYellow.blue(' => Loading suman interactive mode...'); console.log(loadingMessage); const _cwd = path.resolve(process.env.HOME + '/.suman/global'); async.parallel({ installSumanInquirer: function (cb) { try { require.resolve('suman-inquirer'); return process.nextTick(cb); } catch (err) { cp.exec('npm install suman-inquirer@latest', { cwd: _cwd }, cb); } }, installSumanInquirerDirectory: function (cb) { try { require.resolve('suman-inquirer-directory'); return process.nextTick(cb); } catch (err) { cp.exec('npm install suman-inquirer-directory@latest', { cwd: _cwd }, cb); } } }, function (err) { if (err) { throw err; } const inquirer = require('suman-inquirer'); const inqDir = require('suman-inquirer-directory'); inquirer.registerPrompt('directory', inqDir); let firstQuestionSeen = false; const firstSetOfQuestions = [ { type: 'confirm', name: 'suman', message: colors.yellow.underline(' => Welcome to Suman land!') + '\n' + colors.blue(' This interactive utility allows you to familiarize yourself with Suman, as well as keep up to date with the API.\n' + ' You can generate a terminal command with this tool which you can then go run yourself.\n' + ' This tool can also help you troubleshoot or debug tests.') + '\n' + ' \n To skip this messsage the future, just use ' + colors.magenta('"suman --interactive --fast"') + '.\n\n' + ' To ' + colors.green('continue') + ', hit enter, or type "y" or "yes".\n\n ', when: function () { if (!firstQuestionSeen) { firstQuestionSeen = true; if (process.argv.indexOf('--fast') < 0) { console.log('\n\n ---------------------------------------------------- \n\n'); return true; } } } }, { type: 'list', name: 'action', message: 'What would you like to do?', default: 0, onLeftKey: function () { _suman._interactiveDebug('left key fired in top level!'); _suman.onBackspace(start); }, choices: Object.values(choices.topLevelOpts), //add empty option for formatting purposes when: function (d) { if (d.suman === false) { console.log('\n\n'); console.log('\n => Confirmation was false...ok, we will exit then!'); process.exit(1); } else { console.log('\n\n ---------------------------------------------------- \n\n'); return true; } } } ]; const secondSetOfQuestions = [ { type: 'list', name: 'firstAction', message: 'What would you like to do?', onLeftKey: function () { _suman._interactiveDebug('left key fired in generate list!'); _suman.onBackspace(start); }, default: 0, choices: fs.readdirSync(path.resolve(__dirname + '/generate-command')), when: function () { console.log('\n\n ----------------------------------------------------- \n\n'); return true; } } ]; function generateList(obj, onBackspace) { const dir = obj.firstAction; const root = path.resolve(__dirname + '/generate-command'); const items = fs.readdirSync(root + '/' + dir); _suman._interactiveDebug('ITEMS => ', items); return inquirer.prompt([ { type: 'list', name: 'secondAction', message: 'What would you like to do?', onLeftKey: function () { _suman._interactiveDebug('left key fired in generate list!'); _suman.onBackspace(onBackspace); }, default: 0, choices: items.map(function (item) { return String(item).slice(0, -3); // get rid of ".js" }), when: function () { console.log('\n\n ----------------------------------------------------- \n\n'); return true; }, filter: function (items) { return items; // return items.map(function (item) { // return path.resolve(root + '/' + item); // }); } } ]) .then(function (answers) { return Object.assign(obj, answers); }); } function secondSet() { return inquirer.prompt(secondSetOfQuestions).then(function (obj) { return thirdSet(obj, secondSet); }); } function thirdSet(obj, cb) { _suman._interactiveDebug('in THIRD SET => ', obj); const _thirdSet = thirdSet.bind(null, obj, cb); return generateList(obj, cb).then(function (obj) { _suman._interactiveDebug('obj in SECOND => ', obj); const pth = path.resolve(__dirname + '/generate-command/' + obj.firstAction + '/' + obj.secondAction + '.js'); _suman._interactiveDebug('RESOLVED PATH => ', pth); return require(pth)({ rootDir: rootDir }, _thirdSet); }); } function start() { // process.stdin.removeAllListeners('keypress'); // process.stdin.removeAllListeners('end'); _suman._interactiveDebug('readable count:', process.stdin.listenerCount('readable')); _suman._interactiveDebug('keypress count:', process.stdin.listenerCount('keypress')); _suman._interactiveDebug('keypress count:', process.stdin.listenerCount('keypress')); inquirer.restoreDefaultPrompts(); inquirer.prompt(firstSetOfQuestions).then(function (respuestas) { if (respuestas.action === choices.topLevelOpts.GenerateCommand) { return secondSet(start); } else if (respuestas.action === choices.topLevelOpts.Learn) { throw new Error('Learn the Suman API is not implemented yet.'); } else if (respuestas.action === choices.topLevelOpts.Troubleshoot) { throw new Error('Troubleshoot is not implemented yet.'); } else { throw new Error('Action not recognized.'); } }) .catch(rejectionHandler); } start(); }); }; exports.default = module.exports;