From f2bb1954444ebc0c9c0d9bc99c43875e5ad64017 Mon Sep 17 00:00:00 2001 From: BenjaminJ Date: Tue, 9 Aug 2016 11:20:20 +0900 Subject: [PATCH 01/18] Improving code quality --- src/index.js | 143 +++++++++++++++++++-------------------- test/helpers/readline.js | 2 +- test/spec/index.spec.js | 2 +- 3 files changed, 71 insertions(+), 76 deletions(-) diff --git a/src/index.js b/src/index.js index 50bde3a..b27f7cb 100644 --- a/src/index.js +++ b/src/index.js @@ -2,7 +2,7 @@ /** * `directory` type prompt */ -var rx = require('rx-lite'); +var rx = require("rx-lite"); var util = require("util"); var chalk = require("chalk"); var figures = require("figures"); @@ -13,8 +13,8 @@ var Paginator = require("inquirer/lib/utils/paginator"); var Choices = require('inquirer/lib/objects/choices'); var Separator = require('inquirer/lib/objects/separator'); -var path = require('path'); -var fs = require('fs'); +var path = require("path"); +var fs = require("fs"); /** @@ -23,10 +23,62 @@ var fs = require('fs'); var CHOOSE = "choose this directory"; var BACK = ".."; + + /** - * Constructor + * Function for rendering list choices + * @param {Number} pointer Position of the pointer + * @return {String} Rendered content */ +function listRender(choices, pointer) { + var output = ''; + var separatorOffset = 0; + choices.forEach(function(choice, i) { + if (choice.type === 'separator') { + separatorOffset++; + output += ' ' + choice + '\n'; + return; + } + + var isSelected = (i - separatorOffset === pointer); + var line = (isSelected ? figures.pointer + ' ' : ' ') + choice.name; + if (isSelected) { + line = chalk.cyan(line); + } + output += line + ' \n'; + }); + + return output.replace(/\n$/, ''); +} + +/** + * Function for getting list of folders in directory + * @param {String} basePath the path the folder to get a list of containing folders + * @return {Array} array of folder names inside of basePath + */ +function getDirectories(basePath) { + return fs + .readdirSync(basePath) + .filter(function(file) { + try { + var stats = fs.lstatSync(path.join(basePath, file)); + if (stats.isSymbolicLink()) { + return false; + } + var isDir = stats.isDirectory(); + var isNotDotFile = path.basename(file).indexOf('.') !== 0; + return isDir && isNotDotFile; + } catch (e) { + return false; + } + }) + .sort(); +} + +/** + * Constructor + */ function Prompt() { Base.apply(this, arguments); if (!this.opt.basePath) { @@ -81,7 +133,7 @@ Prompt.prototype._run = function(cb) { return e.key.name === 'backspace' || alphaNumericRegex.test(e.value); }).share(); - var searchTerm = keySlash.flatMap(function(md) { + var searchTerm = keySlash.flatMap(function() { self.searchMode = true; self.searchTerm = ''; self.render(); @@ -159,6 +211,9 @@ Prompt.prototype.render = function() { /** * When user press `enter` key + * + * @param {any} e + * @returns */ Prompt.prototype.handleSubmit = function(e) { var self = this; @@ -200,7 +255,6 @@ Prompt.prototype.handleDrill = function() { * when user selects ".. back" */ Prompt.prototype.handleBack = function() { - var choice = this.opt.choices.getChoice(this.selected); this.currentPath = path.dirname(this.currentPath); this.opt.choices = new Choices(this.createChoices(this.currentPath), this.answers); this.selected = 0; @@ -243,28 +297,21 @@ Prompt.prototype.onDownKey = function() { this.render(); }; -Prompt.prototype.onSlashKey = function(e) { - this.render(); -}; - -Prompt.prototype.onKeyPress = function(e) { - var index = findIndex.call(this, this.searchTerm); - if (index >= 0) { - this.selected = index; - } +Prompt.prototype.onSlashKey = function(/*e*/) { this.render(); }; -function findIndex(term) { +Prompt.prototype.onKeyPress = function(/*e*/) { var item; - for (var i = 0; i < this.opt.choices.realLength; i++) { - item = this.opt.choices.realChoices[i].name.toLowerCase(); - if (item.indexOf(term) === 0) { - return i; + for (var index = 0; index < this.opt.choices.realLength; index++) { + item = this.opt.choices.realChoices[index].name.toLowerCase(); + if (item.indexOf(this.searchTerm) === 0) { + this.selected = index; + break; } } - return -1; -} + this.render(); +}; /** * Helper to create new choices based on previous selection. @@ -283,58 +330,6 @@ Prompt.prototype.createChoices = function(basePath) { }; -/** - * Function for rendering list choices - * @param {Number} pointer Position of the pointer - * @return {String} Rendered content - */ -function listRender(choices, pointer) { - var output = ''; - var separatorOffset = 0; - - choices.forEach(function(choice, i) { - if (choice.type === 'separator') { - separatorOffset++; - output += ' ' + choice + '\n'; - return; - } - - var isSelected = (i - separatorOffset === pointer); - var line = (isSelected ? figures.pointer + ' ' : ' ') + choice.name; - if (isSelected) { - line = chalk.cyan(line); - } - output += line + ' \n'; - }); - - return output.replace(/\n$/, ''); -} - -/** - * Function for getting list of folders in directory - * @param {String} basePath the path the folder to get a list of containing folders - * @return {Array} array of folder names inside of basePath - */ -function getDirectories(basePath) { - return fs - .readdirSync(basePath) - .filter(function(file) { - try { - var stats = fs.lstatSync(path.join(basePath, file)); - if (stats.isSymbolicLink()) { - return false; - } - var isDir = stats.isDirectory(); - var isNotDotFile = path.basename(file).indexOf('.') !== 0; - return isDir && isNotDotFile; - } catch (e) { - return false; - } - }) - .sort(); -} - - /** * Module exports */ diff --git a/test/helpers/readline.js b/test/helpers/readline.js index 81619ef..ec2f928 100644 --- a/test/helpers/readline.js +++ b/test/helpers/readline.js @@ -42,7 +42,7 @@ _.assign(ReadlineStub.prototype, stub); ReadlineStub.prototype.keyPress = function(letter) { this.input.emit('keypress', letter, { - name: letter, + name: letter }); }; ReadlineStub.prototype.moveDown = function() { diff --git a/test/spec/index.spec.js b/test/spec/index.spec.js index fa1421a..008f6d8 100644 --- a/test/spec/index.spec.js +++ b/test/spec/index.spec.js @@ -42,7 +42,7 @@ describe('inquirer-directory', function() { expect(function() { new Prompt({ message: 'foo', - name: 'name', + name: 'name' }); }).to.throw(/basePath/); }); From 73548a1b11c9e45a51b3880a81ac06de1d2db415 Mon Sep 17 00:00:00 2001 From: BenjaminJ Date: Tue, 9 Aug 2016 11:35:30 +0900 Subject: [PATCH 02/18] Improving code quality --- src/index.js | 56 ++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/index.js b/src/index.js index b27f7cb..c2456fa 100644 --- a/src/index.js +++ b/src/index.js @@ -10,7 +10,7 @@ var cliCursor = require("cli-cursor"); var Base = require("inquirer/lib/prompts/base"); var observe = require("inquirer/lib/utils/events"); var Paginator = require("inquirer/lib/utils/paginator"); -var Choices = require('inquirer/lib/objects/choices'); +var Choices = require("inquirer/lib/objects/choices"); var Separator = require('inquirer/lib/objects/separator'); var path = require("path"); @@ -34,22 +34,22 @@ function listRender(choices, pointer) { var output = ''; var separatorOffset = 0; - choices.forEach(function(choice, i) { + choices.forEach(function(choice, index) { if (choice.type === 'separator') { separatorOffset++; - output += ' ' + choice + '\n'; + output += " " + choice + "\n"; return; } - var isSelected = (i - separatorOffset === pointer); - var line = (isSelected ? figures.pointer + ' ' : ' ') + choice.name; + var isSelected = (index - separatorOffset === pointer); + var line = (isSelected ? figures.pointer + " " : " ") + choice.name; if (isSelected) { line = chalk.cyan(line); } - output += line + ' \n'; + output += line + " \n"; }); - return output.replace(/\n$/, ''); + return output.replace(/\n$/, ""); } /** @@ -67,9 +67,9 @@ function getDirectories(basePath) { return false; } var isDir = stats.isDirectory(); - var isNotDotFile = path.basename(file).indexOf('.') !== 0; + var isNotDotFile = path.basename(file).indexOf(".") !== 0; return isDir && isNotDotFile; - } catch (e) { + } catch (error) { return false; } }) @@ -94,7 +94,7 @@ function Prompt() { // Make sure no default is set (so it won't be printed) this.opt.default = null; - this.searchTerm = ''; + this.searchTerm = ""; this.paginator = new Paginator(); } @@ -102,48 +102,48 @@ util.inherits(Prompt, Base); /** * Start the Inquiry session - * @param {Function} cb Callback when prompt is done + * @param {Function} callback Callback when prompt is done * @return {this} */ -Prompt.prototype._run = function(cb) { +Prompt.prototype._run = function(callback) { var self = this; self.searchMode = false; - this.done = cb; + this.done = callback; var alphaNumericRegex = /\w|\.|\-/i; var events = observe(this.rl); - var keyUps = events.keypress.filter(function(e) { - return e.key.name === 'up' || (!self.searchMode && e.key.name === 'k'); + var keyUps = events.keypress.filter(function(evt) { + return evt.key.name === "up" || (!self.searchMode && evt.key.name === "k"); }).share(); - var keyDowns = events.keypress.filter(function(e) { - return e.key.name === 'down' || (!self.searchMode && e.key.name === 'j'); + var keyDowns = events.keypress.filter(function(evt) { + return evt.key.name === "down" || (!self.searchMode && evt.key.name === "j"); }).share(); - var keySlash = events.keypress.filter(function(e) { - return e.value === '/'; + var keySlash = events.keypress.filter(function(evt) { + return evt.value === "/"; }).share(); - var keyMinus = events.keypress.filter(function(e) { - return e.value === '-'; + var keyMinus = events.keypress.filter(function(evt) { + return evt.value === "-"; }).share(); - var alphaNumeric = events.keypress.filter(function(e) { - return e.key.name === 'backspace' || alphaNumericRegex.test(e.value); + var alphaNumeric = events.keypress.filter(function(evt) { + return evt.key.name === "backspace" || alphaNumericRegex.test(evt.value); }).share(); var searchTerm = keySlash.flatMap(function() { self.searchMode = true; - self.searchTerm = ''; + self.searchTerm = ""; self.render(); var end$ = new rx.Subject(); var done$ = rx.Observable.merge(events.line, end$); - return alphaNumeric.map(function(e) { - if (e.key.name === 'backspace' && self.searchTerm.length) { + return alphaNumeric.map(function(evt) { + if (evt.key.name === 'backspace' && self.searchTerm.length) { self.searchTerm = self.searchTerm.slice(0, -1); - } else if (e.value) { - self.searchTerm += e.value; + } else if (evt.value) { + self.searchTerm += evt.value; } if (self.searchTerm === '') { end$.onNext(true); From f57bce81bd1490fea3f11a69338dd39ee0aaf455 Mon Sep 17 00:00:00 2001 From: BenjaminJ Date: Thu, 18 Aug 2016 15:46:32 +0900 Subject: [PATCH 03/18] Always display '(Use arrow keys)' --- src/index.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/index.js b/src/index.js index c2456fa..7ba5ff8 100644 --- a/src/index.js +++ b/src/index.js @@ -89,8 +89,6 @@ function Prompt() { this.opt.choices = new Choices(this.createChoices(this.currentPath), this.answers); this.selected = 0; - this.firstRender = true; - // Make sure no default is set (so it won't be printed) this.opt.default = null; @@ -185,26 +183,22 @@ Prompt.prototype.render = function() { // Render question var message = this.getQuestion(); - if (this.firstRender) { - message += chalk.dim("(Use arrow keys)"); - } - // Render choices or answer depending on the state if (this.status === "answered") { message += chalk.cyan(this.currentPath); } else { // message += chalk.bold("\n Current directory: ") + path.resolve(this.opt.basePath) + path.sep + chalk.cyan(path.relative(this.opt.basePath, this.currentPath)); message += chalk.bold("\n Current directory: ") + chalk.cyan(path.resolve(this.opt.basePath, this.currentPath)); + message += chalk.bold("\n"); var choicesStr = listRender(this.opt.choices, this.selected); message += "\n" + this.paginator.paginate(choicesStr, this.selected, this.opt.pageSize); + message += chalk.dim("\n(Use arrow keys)"); } if (this.searchMode) { message += ("\nSearch: " + this.searchTerm); } else { message += "\n(Use \"/\" key to search this directory)"; } - - this.firstRender = false; this.screen.render(message); }; From 11d6f60af1420f8a0f9a1b64874428608dfc0901 Mon Sep 17 00:00:00 2001 From: BenjaminJ Date: Thu, 18 Aug 2016 15:48:36 +0900 Subject: [PATCH 04/18] Do not display '(Use arrow keys)' in search mode --- src/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 7ba5ff8..16f3a18 100644 --- a/src/index.js +++ b/src/index.js @@ -192,13 +192,13 @@ Prompt.prototype.render = function() { message += chalk.bold("\n"); var choicesStr = listRender(this.opt.choices, this.selected); message += "\n" + this.paginator.paginate(choicesStr, this.selected, this.opt.pageSize); - message += chalk.dim("\n(Use arrow keys)"); } if (this.searchMode) { message += ("\nSearch: " + this.searchTerm); } else { - message += "\n(Use \"/\" key to search this directory)"; + message += chalk.dim("\n(Use \"/\" key to search this directory)"); } + message += chalk.dim("\n(Use arrow keys)"); this.screen.render(message); }; From d929614c156a449e53798845ea483b7291165ae7 Mon Sep 17 00:00:00 2001 From: BenjaminJ Date: Thu, 18 Aug 2016 15:50:01 +0900 Subject: [PATCH 05/18] Clearing the output before any command --- test/helpers/readline.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/helpers/readline.js b/test/helpers/readline.js index ec2f928..b5e35eb 100644 --- a/test/helpers/readline.js +++ b/test/helpers/readline.js @@ -6,6 +6,8 @@ var _ = require('lodash'); var stub = {}; +var isArray = util.isArray || Array.isArray; + _.extend(stub, { write: sinon.stub().returns(stub), moveCursor: sinon.stub().returns(stub), @@ -41,23 +43,33 @@ util.inherits(ReadlineStub, EventEmitter); _.assign(ReadlineStub.prototype, stub); ReadlineStub.prototype.keyPress = function(letter) { + this.output.clear(); this.input.emit('keypress', letter, { name: letter }); }; +ReadlineStub.prototype.sendWord = function(word) { + word = word || ''; + word.split('').forEach(function(letter) { + this.keyPress(letter); + }, this); +}; ReadlineStub.prototype.moveDown = function() { + this.output.clear(); this.input.emit('keypress', '', { name: 'down' }); }; ReadlineStub.prototype.moveUp = function() { + this.output.clear(); this.input.emit('keypress', '', { name: 'up' }); }; ReadlineStub.prototype.enter = function() { + this.output.clear(); this.emit('line'); }; -module.exports = ReadlineStub; \ No newline at end of file +module.exports = ReadlineStub; From 8cab2bba7a8c0a442f2625d4811b68985d92c19c Mon Sep 17 00:00:00 2001 From: BenjaminJ Date: Thu, 18 Aug 2016 15:51:03 +0900 Subject: [PATCH 06/18] Added tests for '/' and '.' shortcuts --- test/spec/index.spec.js | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/test/spec/index.spec.js b/test/spec/index.spec.js index 008f6d8..2f22d04 100644 --- a/test/spec/index.spec.js +++ b/test/spec/index.spec.js @@ -15,6 +15,7 @@ describe('inquirer-directory', function() { 'folder1': { 'folder1-1': {} }, + 'folder2': {}, 'zfolder2': {}, 'some.png': new Buffer([8, 6, 7, 5, 3, 0, 9]), 'a-symlink': mock.symlink({ @@ -50,6 +51,7 @@ describe('inquirer-directory', function() { it('should list folders', function() { this.prompt.run(); expect(this.rl.output.__raw__).to.contain('folder1'); + expect(this.rl.output.__raw__).to.contain('folder2'); expect(this.rl.output.__raw__).to.contain('zfolder2'); }); @@ -74,8 +76,8 @@ describe('inquirer-directory', function() { this.prompt.run(); this.rl.enter(); expect(this.rl.output.__raw__).to.contain('..'); - this.rl.output.clear(); this.rl.moveDown(); + expect(this.rl.output.__raw__).to.not.contain('zfolder2'); this.rl.enter(); expect(this.rl.output.__raw__).to.contain('zfolder2'); }); @@ -90,11 +92,31 @@ describe('inquirer-directory', function() { it('should not display back option in root folder', function () { this.prompt.run(); while (this.prompt.currentPath !== path.parse(path.resolve('.')).root) { - this.rl.output.clear(); this.rl.enter(); } expect(this.rl.output.__raw__).to.not.contain('..'); }); + + it('should allow users to go back using "-" shortcut', function() { + this.prompt.run(); + expect(this.rl.output.__raw__).to.contain('zfolder2'); + this.rl.keyPress('-'); + expect(this.rl.output.__raw__).to.contain('..'); + expect(this.rl.output.__raw__).to.not.contain('zfolder2'); + }); + + it('should allow users search for a folder using "/" shortcut', function() { + this.prompt.run(); + expect(this.rl.output.__raw__).to.not.contain('Search:'); + this.rl.keyPress('/'); + expect(this.rl.output.__raw__).to.contain('Search:'); + + expect(this.rl.output.__raw__).to.not.contain('> folder1'); + this.rl.keyPress('f'); + expect(this.rl.output.__raw__).to.contain('> folder1'); + this.rl.sendWord('older2') + expect(this.rl.output.__raw__).to.contain('> folder2'); + }); // it('should allow users to press keys to shortcut to that value', function (done) { // prompt.run(function (answer) { // expect(answer).to.equal('zfolder2'); From 6c16a2d618fc0083c514a5cb6b140930c88fc2ac Mon Sep 17 00:00:00 2001 From: BenjaminJ Date: Thu, 18 Aug 2016 15:52:38 +0900 Subject: [PATCH 07/18] Test more node versions --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b4ca0ba..a00fbac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ language: node_js node_js: + - "0.10" - "0.12" - - "4.2" - - "5.2" \ No newline at end of file + - "4" + - "5" + - "6" From b679763e77d01d533845badff5ccc1366650d43b Mon Sep 17 00:00:00 2001 From: BenjaminJ Date: Thu, 18 Aug 2016 16:42:17 +0900 Subject: [PATCH 08/18] Fixed build on node 0.12 4 and 5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests fail because the console render ❯ instead of > --- test/spec/index.spec.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/test/spec/index.spec.js b/test/spec/index.spec.js index 2f22d04..483cbbb 100644 --- a/test/spec/index.spec.js +++ b/test/spec/index.spec.js @@ -109,13 +109,16 @@ describe('inquirer-directory', function() { this.prompt.run(); expect(this.rl.output.__raw__).to.not.contain('Search:'); this.rl.keyPress('/'); + var raw = this.rl.output.__raw__.replace('❯', '>'); + expect(raw).to.not.contain('> folder1'); expect(this.rl.output.__raw__).to.contain('Search:'); - - expect(this.rl.output.__raw__).to.not.contain('> folder1'); this.rl.keyPress('f'); - expect(this.rl.output.__raw__).to.contain('> folder1'); - this.rl.sendWord('older2') - expect(this.rl.output.__raw__).to.contain('> folder2'); + + raw = this.rl.output.__raw__.replace('❯', '>'); + expect(raw).to.have.string('> folder1'); + this.rl.sendWord('older2'); + raw = this.rl.output.__raw__.replace('❯', '>'); + expect(raw).to.contain('> folder2'); }); // it('should allow users to press keys to shortcut to that value', function (done) { // prompt.run(function (answer) { From 0e334b19ef4527df16d9a0340b9de49ef5bbef8e Mon Sep 17 00:00:00 2001 From: BenjaminJ Date: Thu, 18 Aug 2016 16:50:36 +0900 Subject: [PATCH 09/18] Update mock-fs version For node 6 tests purpose --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6e6f2c3..0e837ba 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "chai": "^3.4.1", "events": "^1.1.0", "mocha": "^2.3.4", - "mock-fs": "^3.5.0", + "mock-fs": "^3.11.0", "sinon": "^1.17.2" } } From 89bdb77cd765f14b45dfabdf7dc1f9fb26ad8ff6 Mon Sep 17 00:00:00 2001 From: BenjaminJ Date: Thu, 18 Aug 2016 17:01:48 +0900 Subject: [PATCH 10/18] Add node 6 version --- appveyor.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index e7b61d7..eabccb9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,8 +2,9 @@ environment: matrix: - nodejs_version: "0.12" - - nodejs_version: "4.2" - - nodejs_version: "5.2" + - nodejs_version: "4" + - nodejs_version: "5" + - nodejs_version: "6" # Install scripts. (runs after repo cloning) install: # Get the latest stable version of Node.js or io.js @@ -24,4 +25,4 @@ test_script: - npm test # Don't actually build. -build: off \ No newline at end of file +build: off From 70d4e85e3e2221eca881dad6cecc70267a47f5fe Mon Sep 17 00:00:00 2001 From: BenjaminJ Date: Thu, 18 Aug 2016 17:02:21 +0900 Subject: [PATCH 11/18] Remove node 0.10 from buid process --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a00fbac..c4b1276 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: node_js node_js: - - "0.10" - "0.12" - "4" - "5" From bafb01352adc23850b4a99e0a43004dd3ec837a4 Mon Sep 17 00:00:00 2001 From: benjaminJ Date: Thu, 6 Oct 2016 12:20:42 +0200 Subject: [PATCH 12/18] Add '-' help message --- src/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 16f3a18..eefa8a5 100644 --- a/src/index.js +++ b/src/index.js @@ -196,7 +196,8 @@ Prompt.prototype.render = function() { if (this.searchMode) { message += ("\nSearch: " + this.searchTerm); } else { - message += chalk.dim("\n(Use \"/\" key to search this directory)"); + message += chalk.dim('\n(Use "/" key to search this directory)'); + message += chalk.dim('\n(Use "-" key to navigate to the parent folder'); } message += chalk.dim("\n(Use arrow keys)"); this.screen.render(message); @@ -328,4 +329,4 @@ Prompt.prototype.createChoices = function(basePath) { * Module exports */ -module.exports = Prompt; \ No newline at end of file +module.exports = Prompt; From 62d38163d399e129bd6a5df7969f0fb2b50130a9 Mon Sep 17 00:00:00 2001 From: benjaminJ Date: Thu, 20 Oct 2016 12:23:26 +0200 Subject: [PATCH 13/18] Add '.' link to current directory --- src/index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index eefa8a5..7c19f7f 100644 --- a/src/index.js +++ b/src/index.js @@ -22,6 +22,7 @@ var fs = require("fs"); */ var CHOOSE = "choose this directory"; var BACK = ".."; +var CURRENT = "."; @@ -217,7 +218,7 @@ Prompt.prototype.handleSubmit = function(e) { }).share(); var done = obx.filter(function(choice) { - return choice === CHOOSE; + return choice === CHOOSE || choice === CURRENT; }).take(1); var back = obx.filter(function(choice) { @@ -225,7 +226,7 @@ Prompt.prototype.handleSubmit = function(e) { }).takeUntil(done); var drill = obx.filter(function(choice) { - return choice !== BACK && choice !== CHOOSE; + return choice !== BACK && choice !== CHOOSE && choice !== CURRENT; }).takeUntil(done); return { @@ -316,6 +317,7 @@ Prompt.prototype.createChoices = function(basePath) { if (basePath !== this.root) { choices.unshift(BACK); } + choices.unshift(CURRENT); if (choices.length > 0) { choices.push(new Separator()); } From a79d098f5bdaea820d4b3876b00eebfa6ec2b1b5 Mon Sep 17 00:00:00 2001 From: benjaminJ Date: Tue, 25 Oct 2016 14:08:34 +0200 Subject: [PATCH 14/18] Fix tests regarding changes introduced in 62d381 --- test/spec/index.spec.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/spec/index.spec.js b/test/spec/index.spec.js index 483cbbb..0693964 100644 --- a/test/spec/index.spec.js +++ b/test/spec/index.spec.js @@ -68,12 +68,15 @@ describe('inquirer-directory', function() { it('should allow users to drill into folder', function() { this.prompt.run(); this.rl.moveDown(); + this.rl.moveDown(); this.rl.enter(); expect(this.rl.output.__raw__).to.contain('folder1-1'); }); it('should allow users to go back after drilling', function() { this.prompt.run(); + this.rl.moveDown(); + this.rl.moveDown(); this.rl.enter(); expect(this.rl.output.__raw__).to.contain('..'); this.rl.moveDown(); @@ -81,22 +84,23 @@ describe('inquirer-directory', function() { this.rl.enter(); expect(this.rl.output.__raw__).to.contain('zfolder2'); }); - + // it('should allow users to go past basePath', function() { this.prompt.run(); + this.rl.moveDown(); this.rl.enter(); expect(this.rl.output.__raw__).to.contain('..'); - expect(this.prompt.opt.choices.realChoices[0].name).to.equal('..'); + expect(this.prompt.opt.choices.realChoices[1].name).to.equal('..'); }); it('should not display back option in root folder', function () { this.prompt.run(); while (this.prompt.currentPath !== path.parse(path.resolve('.')).root) { + this.rl.moveDown(); this.rl.enter(); } expect(this.rl.output.__raw__).to.not.contain('..'); }); - it('should allow users to go back using "-" shortcut', function() { this.prompt.run(); expect(this.rl.output.__raw__).to.contain('zfolder2'); @@ -104,7 +108,7 @@ describe('inquirer-directory', function() { expect(this.rl.output.__raw__).to.contain('..'); expect(this.rl.output.__raw__).to.not.contain('zfolder2'); }); - + it('should allow users search for a folder using "/" shortcut', function() { this.prompt.run(); expect(this.rl.output.__raw__).to.not.contain('Search:'); From a92e34c5b0aca829c866462edb7398d6c74b1a52 Mon Sep 17 00:00:00 2001 From: benjaminJ Date: Wed, 26 Oct 2016 12:57:17 +0200 Subject: [PATCH 15/18] Update version number --- README.md | 12 ++++++------ package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ab90f6e..183b7c0 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This project is a fork of [Inquirer-directory](https://github.com/nicksrandall/i ![](https://img.shields.io/badge/license-MIT-blue.svg) -![](https://img.shields.io/badge/release-v0.1.0-blue.svg) +[![](https://img.shields.io/badge/release-v1.0.0-blue.svg)](https://github.com/KamiKillertO/inquirer-select-directory/releases/tag/v1.0.0) [![Build Status](https://travis-ci.org/KamiKillertO/inquirer-select-directory.svg)](https://travis-ci.org/KamiKillertO/inquirer-select-directory) [![Build status](https://ci.appveyor.com/api/projects/status/fdyk5g3y56381742?svg=true)](https://ci.appveyor.com/project/KamiKillertO/inquirer-select-directory) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/e6a963539c4440b69356649c0048ea30)](https://www.codacy.com/app/kamikillerto/inquirer-select-directory?utm_source=github.com&utm_medium=referral&utm_content=KamiKillertO/inquirer-select-directory&utm_campaign=Badge_Grade) @@ -19,14 +19,14 @@ npm install --save inquirer-select-directory --> ## Features -- Support for symlinked files -- Vim style navigation -- Search for file with "/" key +- Support for symlinked files +- Vim style navigation +- Search for file with "/" key ### Key Maps -- Press "/" key to enter search mode. -- Press "-" key to go up (back) a directory. +- Press "/" key to enter search mode. +- Press "-" key to go up (back) a directory. ## Usage diff --git a/package.json b/package.json index 0e837ba..02cfeff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "inquirer-select-directory", - "version": "0.1.0", + "version": "1.0.0", "description": "A directory prompt for Inquirer.js", "main": "src/index.js", "scripts": { From 85d4261de77395fc8eb08584b0450f674ae84ec9 Mon Sep 17 00:00:00 2001 From: benjaminJ Date: Wed, 26 Oct 2016 13:04:22 +0200 Subject: [PATCH 16/18] Improve code quality --- example/example.js | 4 +- src/index.js | 16 ++--- test/helpers/readline.js | 2 - test/spec/index.spec.js | 124 +++++++++++++++++++-------------------- 4 files changed, 72 insertions(+), 74 deletions(-) diff --git a/example/example.js b/example/example.js index 3a07193..4a7e378 100644 --- a/example/example.js +++ b/example/example.js @@ -4,7 +4,7 @@ "use strict"; var inquirer = require("inquirer"); -inquirer.registerPrompt('directory', require('../src/index')); +inquirer.registerPrompt("directory", require("../src/index")); inquirer.prompt([{ type: "directory", @@ -13,4 +13,4 @@ inquirer.prompt([{ basePath: "./node_modules" }], function(answers) { console.log(JSON.stringify(answers, null, " ")); -}); \ No newline at end of file +}); diff --git a/src/index.js b/src/index.js index 7c19f7f..65e795a 100644 --- a/src/index.js +++ b/src/index.js @@ -11,7 +11,7 @@ var Base = require("inquirer/lib/prompts/base"); var observe = require("inquirer/lib/utils/events"); var Paginator = require("inquirer/lib/utils/paginator"); var Choices = require("inquirer/lib/objects/choices"); -var Separator = require('inquirer/lib/objects/separator'); +var Separator = require("inquirer/lib/objects/separator"); var path = require("path"); var fs = require("fs"); @@ -32,11 +32,11 @@ var CURRENT = "."; * @return {String} Rendered content */ function listRender(choices, pointer) { - var output = ''; + var output = ""; var separatorOffset = 0; choices.forEach(function(choice, index) { - if (choice.type === 'separator') { + if (choice.type === "separator") { separatorOffset++; output += " " + choice + "\n"; return; @@ -90,7 +90,7 @@ function Prompt() { this.opt.choices = new Choices(this.createChoices(this.currentPath), this.answers); this.selected = 0; - // Make sure no default is set (so it won't be printed) + // Make sure no default is set (so it won"t be printed) this.opt.default = null; this.searchTerm = ""; @@ -139,12 +139,12 @@ Prompt.prototype._run = function(callback) { var end$ = new rx.Subject(); var done$ = rx.Observable.merge(events.line, end$); return alphaNumeric.map(function(evt) { - if (evt.key.name === 'backspace' && self.searchTerm.length) { + if (evt.key.name === "backspace" && self.searchTerm.length) { self.searchTerm = self.searchTerm.slice(0, -1); } else if (evt.value) { self.searchTerm += evt.value; } - if (self.searchTerm === '') { + if (self.searchTerm === "") { end$.onNext(true); } return self.searchTerm; @@ -197,8 +197,8 @@ Prompt.prototype.render = function() { if (this.searchMode) { message += ("\nSearch: " + this.searchTerm); } else { - message += chalk.dim('\n(Use "/" key to search this directory)'); - message += chalk.dim('\n(Use "-" key to navigate to the parent folder'); + message += chalk.dim("\n(Use "/" key to search this directory)"); + message += chalk.dim("\n(Use "-" key to navigate to the parent folder"); } message += chalk.dim("\n(Use arrow keys)"); this.screen.render(message); diff --git a/test/helpers/readline.js b/test/helpers/readline.js index b5e35eb..430415e 100644 --- a/test/helpers/readline.js +++ b/test/helpers/readline.js @@ -6,8 +6,6 @@ var _ = require('lodash'); var stub = {}; -var isArray = util.isArray || Array.isArray; - _.extend(stub, { write: sinon.stub().returns(stub), moveCursor: sinon.stub().returns(stub), diff --git a/test/spec/index.spec.js b/test/spec/index.spec.js index 0693964..a927622 100644 --- a/test/spec/index.spec.js +++ b/test/spec/index.spec.js @@ -1,25 +1,25 @@ "use strict"; -var expect = require('chai').expect; -var mock = require('mock-fs'); -var ReadlineStub = require('../helpers/readline'); -var Prompt = require('../../src/index'); -var path = require('path'); +var expect = require("chai").expect; +var mock = require("mock-fs"); +var ReadlineStub = require("../helpers/readline"); +var Prompt = require("../../src/index"); +var path = require("path"); -describe('inquirer-directory', function() { +describe("inquirer-directory", function() { before(function() { mock({ - 'root': { - '.git': {}, - 'folder1': { - 'folder1-1': {} + "root": { + ".git": {}, + "folder1": { + "folder1-1": {} }, - 'folder2': {}, - 'zfolder2': {}, - 'some.png': new Buffer([8, 6, 7, 5, 3, 0, 9]), - 'a-symlink': mock.symlink({ - path: 'folder1' + "folder2": {}, + "zfolder2": {}, + "some.png": new Buffer([8, 6, 7, 5, 3, 0, 9]), + "a-symlink": mock.symlink({ + path: "folder1" }) } }); @@ -31,107 +31,107 @@ describe('inquirer-directory', function() { // need to clear "console after every action" this.rl = new ReadlineStub(); this.prompt = new Prompt({ - message: 'Choose a directory', - name: 'name', + message: "Choose a directory", + name: "name", basePath: "./root/" }, this.rl); }); afterEach(function() { this.rl.output.clear(); }); - it('requires a basePath', function() { + it("requires a basePath", function() { expect(function() { new Prompt({ - message: 'foo', - name: 'name' + message: "foo", + name: "name" }); }).to.throw(/basePath/); }); - it('should list folders', function() { + it("should list folders", function() { this.prompt.run(); - expect(this.rl.output.__raw__).to.contain('folder1'); - expect(this.rl.output.__raw__).to.contain('folder2'); - expect(this.rl.output.__raw__).to.contain('zfolder2'); + expect(this.rl.output.__raw__).to.contain("folder1"); + expect(this.rl.output.__raw__).to.contain("folder2"); + expect(this.rl.output.__raw__).to.contain("zfolder2"); }); - it('should not contain folders starting with "." (private folders)', function() { + it("should not contain folders starting with '.' (private folders)", function() { this.prompt.run(); - expect(this.rl.output.__raw__).to.not.contain('.git'); + expect(this.rl.output.__raw__).to.not.contain(".git"); }); - it('should not contain files', function() { + it("should not contain files", function() { this.prompt.run(); - expect(this.rl.output.__raw__).to.not.contain('some.png'); + expect(this.rl.output.__raw__).to.not.contain("some.png"); }); - it('should allow users to drill into folder', function() { + it("should allow users to drill into folder", function() { this.prompt.run(); this.rl.moveDown(); this.rl.moveDown(); this.rl.enter(); - expect(this.rl.output.__raw__).to.contain('folder1-1'); + expect(this.rl.output.__raw__).to.contain("folder1-1"); }); - it('should allow users to go back after drilling', function() { + it("should allow users to go back after drilling", function() { this.prompt.run(); this.rl.moveDown(); this.rl.moveDown(); this.rl.enter(); - expect(this.rl.output.__raw__).to.contain('..'); + expect(this.rl.output.__raw__).to.contain(".."); this.rl.moveDown(); - expect(this.rl.output.__raw__).to.not.contain('zfolder2'); + expect(this.rl.output.__raw__).to.not.contain("zfolder2"); this.rl.enter(); - expect(this.rl.output.__raw__).to.contain('zfolder2'); + expect(this.rl.output.__raw__).to.contain("zfolder2"); }); // - it('should allow users to go past basePath', function() { + it("should allow users to go past basePath", function() { this.prompt.run(); this.rl.moveDown(); this.rl.enter(); - expect(this.rl.output.__raw__).to.contain('..'); - expect(this.prompt.opt.choices.realChoices[1].name).to.equal('..'); + expect(this.rl.output.__raw__).to.contain(".."); + expect(this.prompt.opt.choices.realChoices[1].name).to.equal(".."); }); - it('should not display back option in root folder', function () { + it("should not display back option in root folder", function () { this.prompt.run(); - while (this.prompt.currentPath !== path.parse(path.resolve('.')).root) { + while (this.prompt.currentPath !== path.parse(path.resolve(".")).root) { this.rl.moveDown(); this.rl.enter(); } - expect(this.rl.output.__raw__).to.not.contain('..'); + expect(this.rl.output.__raw__).to.not.contain(".."); }); - it('should allow users to go back using "-" shortcut', function() { + it("should allow users to go back using "-" shortcut", function() { this.prompt.run(); - expect(this.rl.output.__raw__).to.contain('zfolder2'); - this.rl.keyPress('-'); - expect(this.rl.output.__raw__).to.contain('..'); - expect(this.rl.output.__raw__).to.not.contain('zfolder2'); + expect(this.rl.output.__raw__).to.contain("zfolder2"); + this.rl.keyPress("-"); + expect(this.rl.output.__raw__).to.contain(".."); + expect(this.rl.output.__raw__).to.not.contain("zfolder2"); }); - - it('should allow users search for a folder using "/" shortcut', function() { + + it("should allow users search for a folder using "/" shortcut", function() { this.prompt.run(); - expect(this.rl.output.__raw__).to.not.contain('Search:'); - this.rl.keyPress('/'); - var raw = this.rl.output.__raw__.replace('❯', '>'); - expect(raw).to.not.contain('> folder1'); - expect(this.rl.output.__raw__).to.contain('Search:'); - this.rl.keyPress('f'); + expect(this.rl.output.__raw__).to.not.contain("Search:"); + this.rl.keyPress("/"); + var raw = this.rl.output.__raw__.replace("❯", ">"); + expect(raw).to.not.contain("> folder1"); + expect(this.rl.output.__raw__).to.contain("Search:"); + this.rl.keyPress("f"); - raw = this.rl.output.__raw__.replace('❯', '>'); - expect(raw).to.have.string('> folder1'); - this.rl.sendWord('older2'); - raw = this.rl.output.__raw__.replace('❯', '>'); - expect(raw).to.contain('> folder2'); + raw = this.rl.output.__raw__.replace("❯", ">"); + expect(raw).to.have.string("> folder1"); + this.rl.sendWord("older2"); + raw = this.rl.output.__raw__.replace("❯", ">"); + expect(raw).to.contain("> folder2"); }); - // it('should allow users to press keys to shortcut to that value', function (done) { + // it("should allow users to press keys to shortcut to that value", function (done) { // prompt.run(function (answer) { - // expect(answer).to.equal('zfolder2'); + // expect(answer).to.equal("zfolder2"); // done(); // }); - // keyPress('z'); + // keyPress("z"); // enter(); // enter(); // }); -}); \ No newline at end of file +}); From ad4cc6db230bd94d7362febeb27f2e237e4566b3 Mon Sep 17 00:00:00 2001 From: benjaminJ Date: Wed, 26 Oct 2016 13:13:26 +0200 Subject: [PATCH 17/18] Improve code quality --- test/helpers/readline.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/test/helpers/readline.js b/test/helpers/readline.js index 430415e..767abba 100644 --- a/test/helpers/readline.js +++ b/test/helpers/readline.js @@ -1,8 +1,8 @@ "use strict"; -var EventEmitter = require('events').EventEmitter; -var sinon = require('sinon'); -var util = require('util'); -var _ = require('lodash'); +var EventEmitter = require("events").EventEmitter; +var sinon = require("sinon"); +var util = require("util"); +var _ = require("lodash"); var stub = {}; @@ -21,7 +21,7 @@ _.extend(stub, { end: sinon.stub(), mute: sinon.stub(), unmute: sinon.stub(), - __raw__: '', + __raw__: "", write: function(str) { this.__raw__ += str; }, @@ -32,7 +32,7 @@ _.extend(stub, { }); var ReadlineStub = function() { - this.line = ''; + this.line = ""; this.input = new EventEmitter(); EventEmitter.apply(this, arguments); }; @@ -42,31 +42,31 @@ _.assign(ReadlineStub.prototype, stub); ReadlineStub.prototype.keyPress = function(letter) { this.output.clear(); - this.input.emit('keypress', letter, { + this.input.emit("keypress", letter, { name: letter }); }; ReadlineStub.prototype.sendWord = function(word) { - word = word || ''; - word.split('').forEach(function(letter) { + word = word || ""; + word.split("").forEach(function(letter) { this.keyPress(letter); }, this); }; ReadlineStub.prototype.moveDown = function() { this.output.clear(); - this.input.emit('keypress', '', { - name: 'down' + this.input.emit("keypress", "", { + name: "down" }); }; ReadlineStub.prototype.moveUp = function() { this.output.clear(); - this.input.emit('keypress', '', { - name: 'up' + this.input.emit("keypress", "", { + name: "up" }); }; ReadlineStub.prototype.enter = function() { this.output.clear(); - this.emit('line'); + this.emit("line"); }; From c0991e8123d979004cfa27575d24fdfba5111d68 Mon Sep 17 00:00:00 2001 From: benjaminJ Date: Wed, 26 Oct 2016 13:38:34 +0200 Subject: [PATCH 18/18] Test the folder selection --- src/index.js | 15 +++++++-------- test/spec/index.spec.js | 17 +++++++++++++++-- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/index.js b/src/index.js index 65e795a..11c80e3 100644 --- a/src/index.js +++ b/src/index.js @@ -193,14 +193,14 @@ Prompt.prototype.render = function() { message += chalk.bold("\n"); var choicesStr = listRender(this.opt.choices, this.selected); message += "\n" + this.paginator.paginate(choicesStr, this.selected, this.opt.pageSize); + if (this.searchMode) { + message += ("\nSearch: " + this.searchTerm); + } else { + message += chalk.dim("\n(Use "/" key to search this directory)"); + message += chalk.dim("\n(Use "-" key to navigate to the parent folder"); + } + message += chalk.dim("\n(Use arrow keys)"); } - if (this.searchMode) { - message += ("\nSearch: " + this.searchTerm); - } else { - message += chalk.dim("\n(Use "/" key to search this directory)"); - message += chalk.dim("\n(Use "-" key to navigate to the parent folder"); - } - message += chalk.dim("\n(Use arrow keys)"); this.screen.render(message); }; @@ -220,7 +220,6 @@ Prompt.prototype.handleSubmit = function(e) { var done = obx.filter(function(choice) { return choice === CHOOSE || choice === CURRENT; }).take(1); - var back = obx.filter(function(choice) { return choice === BACK; }).takeUntil(done); diff --git a/test/spec/index.spec.js b/test/spec/index.spec.js index a927622..5470177 100644 --- a/test/spec/index.spec.js +++ b/test/spec/index.spec.js @@ -101,7 +101,7 @@ describe("inquirer-directory", function() { } expect(this.rl.output.__raw__).to.not.contain(".."); }); - it("should allow users to go back using "-" shortcut", function() { + it("should allow users to go back using '-' shortcut", function() { this.prompt.run(); expect(this.rl.output.__raw__).to.contain("zfolder2"); this.rl.keyPress("-"); @@ -109,7 +109,7 @@ describe("inquirer-directory", function() { expect(this.rl.output.__raw__).to.not.contain("zfolder2"); }); - it("should allow users search for a folder using "/" shortcut", function() { + it("should allow users search for a folder using '/' shortcut", function() { this.prompt.run(); expect(this.rl.output.__raw__).to.not.contain("Search:"); this.rl.keyPress("/"); @@ -124,6 +124,19 @@ describe("inquirer-directory", function() { raw = this.rl.output.__raw__.replace("❯", ">"); expect(raw).to.contain("> folder2"); }); + + it("should allow users to select a folder using 'choose this directory' choice", function() { + this.prompt.run(); + this.rl.moveUp(); + this.rl.enter(); + expect(this.prompt.currentPath.split('/').slice(-1)[0]).to.equal("root"); + }); + + it("should allow users to select a folder using '.' choice", function() { + this.prompt.run(); + this.rl.enter(); + expect(this.prompt.currentPath.split('/').slice(-1)[0]).to.equal("root"); + }); // it("should allow users to press keys to shortcut to that value", function (done) { // prompt.run(function (answer) { // expect(answer).to.equal("zfolder2");