diff --git a/README.md b/README.md index 8abe010..7e4d2e5 100644 --- a/README.md +++ b/README.md @@ -207,3 +207,26 @@ yargsInteractive() ``` ➜ node my-cli.js --name='Johh' --likesPizza ``` + +### Inquirer plugins support + +Inquirer plugins support must be opt-in by setting `allowInquirerPlugins` to `true` in the interactive mode options: + +```js +const options = { + interactive: { + allowInquirerPlugins: true, + default: true, + }, + ... +}; + +yargsInteractive() + .usage('$0 [args]') + .interactive(options) + .then((result) => { + // The tool will prompt questions and will output your answers. + // TODO: Do something with the result (e.g result.name) + console.log(result) + }); +``` diff --git a/src/interactive-mode.js b/src/interactive-mode.js index f449f37..5f3fdaf 100644 --- a/src/interactive-mode.js +++ b/src/interactive-mode.js @@ -3,10 +3,10 @@ const inquirer = require('inquirer'); /** * Initiate an interactive prompt to get values from the user. * @param {object} values The values to configure the prompt + * @param {object} inquirerOptions Payload encapsulating runtime configuration options for inquirer, mainly "allowInquirerPlugins", which enables support of inquirer plugins * @return {object} A promise that, when fullfilled, will contain answer of the questions prompted to the user */ -module.exports = (values = {}) => { - const prompt = inquirer.createPromptModule(); +module.exports = (values = {}, inquirerOptions = {}) => { const questions = Object.keys(values).map((key) => { const value = values[key]; return Object.assign({}, value, { @@ -17,5 +17,12 @@ module.exports = (values = {}) => { }); }); + if (inquirerOptions.allowInquirerPlugins) { + return inquirer.prompt(questions); + } + + // https://github.com/SBoudrias/Inquirer.js#inquirercreatepromptmodule---prompt-function + const prompt = inquirer.createPromptModule(); + return prompt(questions); }; diff --git a/src/yargs-interactive.js b/src/yargs-interactive.js index 715ab26..9f595ce 100755 --- a/src/yargs-interactive.js +++ b/src/yargs-interactive.js @@ -44,8 +44,13 @@ const yargsInteractive = (processArgs = process.argv.slice(2), cwd) => { return isEmpty(argv[key]) && isEmpty(item.default); }); + // Assess self-contained mode -- Wheteher to create a self contained inquirer module or allow other libraries to be usable. + const inquirerOptions = { + allowInquirerPlugins: !!(options.interactive && options.interactive.allowInquirerPlugins) + }; + // Check if we should get the values from the interactive mode - return argv.interactive ? interactiveMode(interactiveOptions).then((result) => Object.assign({}, argv, result)) : Promise.resolve(argv); + return argv.interactive ? interactiveMode(interactiveOptions, inquirerOptions).then((result) => Object.assign({}, argv, result)) : Promise.resolve(argv); }; return yargsConfig; diff --git a/test/interactive-mode.test.js b/test/interactive-mode.test.js index 46a47f7..2fdcfa6 100644 --- a/test/interactive-mode.test.js +++ b/test/interactive-mode.test.js @@ -2,32 +2,40 @@ const inquirer = require('inquirer'); const interactiveMode = require('../src/interactive-mode'); describe('interactive-mode', () => { - let inquirerCreatePromptModuleStub; - let inquirerPromptStub; + let stubCreatePrompt; + let stubPrompt; + let stubSelfContainedPrompt; let values; beforeAll(() => { - inquirerPromptStub = jest.fn(); - inquirerCreatePromptModuleStub = jest.spyOn(inquirer, 'createPromptModule').mockReturnValue(inquirerPromptStub); + stubSelfContainedPrompt = jest.fn(); + stubCreatePrompt = jest.spyOn(inquirer, 'createPromptModule').mockReturnValue(stubSelfContainedPrompt); + stubPrompt = jest.spyOn(inquirer, 'prompt').mockResolvedValue({}); }); describe('with no values', () => { beforeAll(() => { + jest.clearAllMocks(); values = undefined; interactiveMode(values); }); - test('should call createPromptModule', () => { - expect(inquirerCreatePromptModuleStub).toHaveBeenCalled(); + test('should call inquirer.createPromptModule() method', () => { + expect(stubCreatePrompt).toHaveBeenCalled(); }); - test('should call prompt', () => { - expect(inquirerPromptStub).toHaveBeenCalled(); + test('should call prompt() of created module', () => { + expect(stubSelfContainedPrompt).toHaveBeenCalled(); + }); + + test('should NOT default inquirer.prompt() method', () => { + expect(stubPrompt).not.toHaveBeenCalled(); }); }); describe('with values', () => { beforeAll(() => { + jest.clearAllMocks(); values = { title: { type: 'input', @@ -43,16 +51,62 @@ describe('interactive-mode', () => { interactiveMode(values); }); - test('should call createPromptModule', () => { - expect(inquirerCreatePromptModuleStub).toHaveBeenCalled(); + test('should call inquirer.createPromptModule() method', () => { + expect(stubCreatePrompt).toHaveBeenCalled(); + }); + + test('should call prompt() of created module', () => { + expect(stubSelfContainedPrompt).toHaveBeenCalled(); + }); + + test('should NOT default inquirer.prompt() method', () => { + expect(stubPrompt).not.toHaveBeenCalled(); + }); + + test('should properly transform the values to inquirer values', () => { + const args = stubSelfContainedPrompt.mock.calls[0][0]; + expect(args.length).toEqual(Object.keys(values).length); + + args.forEach((question) => { + const inputValues = values[question.name]; + expect(inputValues).toBeTruthy(); + expect(question.type).toBe(inputValues.type); + expect(question.message).toBe(inputValues.describe); + expect(question.default).toBe(inputValues.default); + expect(question.choices).toBe(inputValues.choices); + }); + }); + }); + + describe('with support of inquirer plugins', () => { + beforeAll(() => { + jest.clearAllMocks(); + values = { + title: { + type: 'input', + describe: 'Do you like plugins?', + default: 'Who does not?', + }, + }; + interactiveMode(values, { + allowInquirerPlugins: true, + }); + }); + + test('should NOT call inquirer.createPromptModule() method', () => { + expect(stubCreatePrompt).not.toHaveBeenCalled(); + }); + + test('should NOT call prompt() of created module', () => { + expect(stubSelfContainedPrompt).not.toHaveBeenCalled(); }); - test('should call prompt', () => { - expect(inquirerPromptStub).toHaveBeenCalled(); + test('should default inquirer.prompt() method', () => { + expect(stubPrompt).toHaveBeenCalled(); }); test('should properly transform the values to inquirer values', () => { - const args = inquirerPromptStub.mock.calls[1][0]; + const args = stubPrompt.mock.calls[0][0]; expect(args.length).toEqual(Object.keys(values).length); args.forEach((question) => {