Skip to content

Commit

Permalink
dialog for project init
Browse files Browse the repository at this point in the history
  • Loading branch information
m-mcgowan committed Dec 21, 2016
1 parent 7ea126f commit 9ea72b0
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 12 deletions.
52 changes: 47 additions & 5 deletions oldlib/prompts.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ var when = require('when');
var readline = require('readline');

var inquirer = require('inquirer');
var log = require('./log');

var that = {

Expand All @@ -12,15 +13,17 @@ var that = {
* Sets up our user input
* @returns {Object} prompt object
*/
getPrompt: function () {
getPrompt: function (captureInterrupt) {
if (!that._prompt) {
that._prompt = readline.createInterface({
input: process.stdin,
output: process.stdout
});
that._prompt.on("SIGINT", function () {
process.emit("SIGINT");
});
if (captureInterrupt) {
that._prompt.on("SIGINT", function () {
process.emit("SIGINT");
});
}
}
return that._prompt;
},
Expand Down Expand Up @@ -97,12 +100,51 @@ var that = {
return dfd.promise;
},

/**
* @param {string} message The message to prompt the user
* @param {string} defaultValue The default value to use if the user simply hits return
* @param {function(string)} validator function that returns an error message if the value is not valid.
* @returns {Promise) to prompt and get the result. The result is undefined if the user hits ctrl-C.
*/
promptAndValidate(message, defaultValue, validator) {
var dfd = when.defer();
var prompt = that.getPrompt();
message += ': ';

function runPrompt() {
prompt.question(message, function (value) {
value = value || defaultValue;
var validateError;
if (validator) {
validateError = validator(value);
}

if (validateError) {
log.error(validateError);
runPrompt();
} else {
that.closePrompt();
dfd.resolve(value);
}
});
}

// process.on('SIGINT', function () {
// that.closePrompt();
// console.log();
// dfd.resolve(false);
// });

runPrompt();
return dfd.promise;
},

enterToContinueControlCToExit(message) {
if (!message) {
message = 'Press ENTER for next page, CTRL-C to exit.';
}
var dfd = when.defer();
var prompt = that.getPrompt();
var prompt = that.getPrompt(true);
prompt.question(message, function (value) {
that.closePrompt();
dfd.resolve(true);
Expand Down
117 changes: 110 additions & 7 deletions src/cli/project_init.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,109 @@
import {ProjectInitCommand, ProjectInitCommandSite} from '../cmd';

import {ProjectInitCommand, ProjectInitCommandSite, Projects} from '../cmd';
import {validateField} from 'particle-library-manager';
import path from 'path';
import log from '../app/log';
import chalk from 'chalk';
import prompt from '../../oldlib/prompts';


// todo - this is pulled from validating_editor in particle-dev-libraries. Please refactor/DRY.

function validationMessage(validationResult, fieldName) {
return fieldName+' '+validationResult.errors[fieldName];
}

function fieldValidator(fieldName) {
const validator = (value) => {
const result = validateField(fieldName, value);
return (result && result.valid) ?
'' : validationMessage(result, fieldName);
};
return validator;
}

function yesNoValidator() {
const validator = (value) => {
if (!value || (value!=='Y' && value!=='y' && value!=='N' && value!=='n')) {
return 'Please answer "y" or "n" - you typed '+value;
}
};
return validator;
}


class CLIProjectInitCommandSite extends ProjectInitCommandSite {
constructor(dir) {
constructor({name, directory}) {
super();
this.dir = dir;
this._name = name;
this._dir = directory;
}

/**
* Has a dialog with the user. Returns a truthy value if project init should continue.
* “What would you like to call your project?”
Then, you are asked to choose where you would like to save your project
“Would you like to create your project in the default project directory? (Y/n)
If you answer Y, the project directory is created under /home/particle/projects/myproject, and the CLI replies, “A new project named “myproject” was successfully created in home/particle/projects/myproject
Then, you are automatically taken to the new project directory in your current session
If you answer N to the first question, the CLI asks, “Would you like to create your project in <current path>? Type “n” to cancel. (Y/n)
If you answer Y, the project directory is created under <current path>/myproject
If you answer anything else, the `project init` process is cancelled
*/
dialog() {
const promptForName = () => {
return this._name || this.prompt('What would you like to call your project? [myproject]', 'myproject', fieldValidator('name'));
};

function isYes(result) {
return (result||'').toLowerCase()==='y';
}

const promptForLocation = (commonLocation, currentLocation) => {
return this._dir ||
this.prompt('Would you like to create your project in the default project directory? [Y/n]', 'Y', yesNoValidator())
.then(result => {
if (isYes(result)) {
return commonLocation;
} else {
return this.prompt(`Would you like to create your project in ${currentLocation}? Type “n” to cancel. [Y/n]`, 'Y', yesNoValidator())
.then((result) => {
return (isYes(result)) ? currentLocation : '';
});
}
});
};

return Promise.resolve()
.then(() => promptForName())
.then((name) => {
this._name = name;
if (name) {
return promptForLocation(new Projects().myProjectsFolder(), process.cwd());
}
})
.then(directory => {
this._dir = directory;
return this._dir && this._name; // are we ready?
});
}

/**
* Prompts the user to enter a value
* @param {string} message The message to prompt with
* @param {string} value The default value
* @param {function(value)} validator The validator that is used to validate the response.
*/
prompt(message, value, validator) {
return prompt.promptAndValidate(message, value, validator);
}

name() {
return this._name;
}

directory() {
return this.dir;
return path.join(this._dir, this._name);
}

filesystem() {
Expand Down Expand Up @@ -65,14 +158,24 @@ export default ({project, factory}) => {

// todo - move library add to its own module
factory.createCommand(project, 'init', 'Initialize a new project in the current or specified directory.', {
options: {},
options: {
'name' : {
required: false,
description: 'provide a name for the project'
}
},
params: '[dir]',

handler: function projectInitandler(argv) {
const dir = argv.params.dir || process.cwd();
const site = new CLIProjectInitCommandSite(dir);
const cmd = new ProjectInitCommand();
return site.run(cmd);
return site.dialog()
.then((ready) => {
if (ready) {
return site.run(cmd);
}
});
}
});
};

0 comments on commit 9ea72b0

Please sign in to comment.