Skip to content

Commit

Permalink
feat: make sure asking for project name before "before" task
Browse files Browse the repository at this point in the history
  • Loading branch information
3cp committed Jul 8, 2019
1 parent b298c6c commit 658cf57
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 72 deletions.
19 changes: 13 additions & 6 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ async function makes(supplier, {
let skeletonDirectory = await _skeletonDir(supplier);

const {
nameQuestion,
questions,
prependTransforms,
appendTransforms,
Expand All @@ -47,9 +48,8 @@ async function makes(supplier, {

if (!here) {
// ensure target folder is available
const namePrompt = questions.find(q => q.name === 'name');
const oldValidate = namePrompt.validate;
namePrompt.validate = async value => {
const oldValidate = nameQuestion.validate;
nameQuestion.validate = async value => {
if (oldValidate) {
const valid = await oldValidate(value);
if ((typeof valid === 'string' && valid) || valid === false) {
Expand All @@ -61,8 +61,13 @@ async function makes(supplier, {
};
}

let silentQuestions = false;
// Ask project name before running "before" task
const [{name}] = await _runQuestionnaire([nameQuestion], {
unattended,
predefinedProperties
});

let silentQuestions = false;
if (typeof before === 'function') {
const result = await before({
unattended,
Expand Down Expand Up @@ -98,11 +103,13 @@ async function makes(supplier, {
predefinedProperties
});

if (!properties.name) {
if (!name) {
throw new Error('Unexpected missing project name.');
}

const targetDir = here ? '.' : properties.name;
const targetDir = here ? '.' : name;
properties.name = name;

await _writeProject({
properties,
features,
Expand Down
13 changes: 9 additions & 4 deletions lib/skeleton-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,18 @@ module.exports = async function(dir, {
if (!questions) questions = [];

const namePromptIdx = questions.findIndex(q => q.name === 'name');
let nameQuestion;

if (namePromptIdx >= 0) {
questions[namePromptIdx] = {
const [overrideNameQuestion] = questions.splice(namePromptIdx, 1);

nameQuestion = {
...defaultNamePrompt,
...questions[namePromptIdx]
...overrideNameQuestion
};
} else {
// no question asking project name, add one
questions.unshift({...defaultNamePrompt});
// no question asking project name, use default;
nameQuestion = {...defaultNamePrompt};
}

const transformsFile = path.join(dir, 'transforms.js');
Expand Down Expand Up @@ -77,6 +81,7 @@ module.exports = async function(dir, {
}

return {
nameQuestion,
questions: questions || [],
prependTransforms: prepend || [],
appendTransforms: append || [],
Expand Down
54 changes: 31 additions & 23 deletions test/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ test.serial('makes checks target folder', async t => {
}, {
_skeletonDir: () => 'skeleton',
_skeletonConfig: () => ({
nameQuestion: {
name: 'name',
message: 'Name:'
},
questions: [
{
name: 'name',
message: 'Name:'
},
{
message: 'lorem',
choices: [
Expand Down Expand Up @@ -65,12 +65,11 @@ test.serial('makes rejects existing folder', async t => {
}, {
_skeletonDir: () => 'skeleton',
_skeletonConfig: () => ({
questions: [
{
name: 'name',
message: 'Name:'
}
]
nameQuestion: {
name: 'name',
message: 'Name:'
},
questions: []
}),
_writeProject: result => {
captured = result;
Expand All @@ -92,11 +91,11 @@ test.serial('makes writes to existing folder with --here', async t => {
}, {
_skeletonDir: () => 'skeleton',
_skeletonConfig: () => ({
nameQuestion: {
name: 'name',
message: 'Name:'
},
questions: [
{
name: 'name',
message: 'Name:'
},
{
message: 'lorem',
choices: [
Expand Down Expand Up @@ -130,16 +129,16 @@ test.serial('makes supports "before" task to change conditions', async t => {
mockfs();

await makes('supplier', {
predefinedProperties: {name: 'app'},
predefinedProperties: {},
preselectedFeatures: ['a'],
}, {
_skeletonDir: () => 'skeleton',
_skeletonConfig: () => ({
nameQuestion: {
name: 'name',
message: 'Name:'
},
questions: [
{
name: 'name',
message: 'Name:'
},
{
name: 'description',
message: 'Description'
Expand Down Expand Up @@ -168,6 +167,15 @@ test.serial('makes supports "before" task to change conditions', async t => {
}),
_writeProject: result => {
captured = result;
},
_runQuestionnaire: (questions, {unattended, preselectedFeatures, predefinedProperties}) => {
if (questions.length === 1 && questions[0].name === 'name') {
return [{name: 'app'}];
} else if (unattended) {
return [predefinedProperties, preselectedFeatures];
} else {
t.fail('should not get here');
}
}
});

Expand All @@ -194,11 +202,11 @@ test.serial('makes supports "after" task', async t => {
}, {
_skeletonDir: () => 'skeleton',
_skeletonConfig: () => ({
nameQuestion: {
name: 'name',
message: 'Name:'
},
questions: [
{
name: 'name',
message: 'Name:'
},
{
name: 'description',
message: 'Description'
Expand Down
82 changes: 43 additions & 39 deletions test/skeleton-config.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,19 @@ test.serial('skeletonConfig runs npm install when required', async t => {
const result = await config('skeleton', {_npmInstall: npmInstall});
t.truthy(installed);

const {validate} = result.questions[0];
delete result.questions[0].validate;
const {validate} = result.nameQuestion;
delete result.nameQuestion.validate;

t.is(validate('ab-1_2'), null);
t.is(validate(' a'), 'Please only use letters, numbers, dash(-) and underscore(_).');
t.is(validate('@a'), 'Please only use letters, numbers, dash(-) and underscore(_).');
t.deepEqual(result, {
questions: [{
nameQuestion: {
name: 'name',
message: 'Please name this new project:',
default: 'my-app'
}],
},
questions: [],
prependTransforms: [],
appendTransforms: [],
before: undefined,
Expand All @@ -51,18 +52,19 @@ test.serial('skeletonConfig does not run npm install when node_modules exists',

const result = await config('skeleton', {_npmInstall: npmInstall});
t.falsy(installed);
const {validate} = result.questions[0];
delete result.questions[0].validate;
const {validate} = result.nameQuestion;
delete result.nameQuestion.validate;

t.is(validate('ab-1_2'), null);
t.is(validate(' a'), 'Please only use letters, numbers, dash(-) and underscore(_).');
t.is(validate('@a'), 'Please only use letters, numbers, dash(-) and underscore(_).');
t.deepEqual(result, {
questions: [{
nameQuestion: {
name: 'name',
message: 'Please name this new project:',
default: 'my-app'
}],
},
questions: [],
prependTransforms: [],
appendTransforms: [],
before: undefined,
Expand All @@ -82,18 +84,19 @@ test.serial('skeletonConfig does not run npm install for devDependencies', async

const result = await config('skeleton', {_npmInstall: npmInstall});
t.falsy(installed);
const {validate} = result.questions[0];
delete result.questions[0].validate;
const {validate} = result.nameQuestion;
delete result.nameQuestion.validate;

t.is(validate('ab-1_2'), null);
t.is(validate(' a'), 'Please only use letters, numbers, dash(-) and underscore(_).');
t.is(validate('@a'), 'Please only use letters, numbers, dash(-) and underscore(_).');
t.deepEqual(result, {
questions: [{
nameQuestion: {
name: 'name',
message: 'Please name this new project:',
default: 'my-app'
}],
},
questions: [],
prependTransforms: [],
appendTransforms: [],
before: undefined,
Expand All @@ -113,18 +116,19 @@ test.serial('skeletonConfig skip npm install when not required', async t => {

const result = await config('skeleton', {_npmInstall: npmInstall});
t.falsy(installed);
const {validate} = result.questions[0];
delete result.questions[0].validate;
const {validate} = result.nameQuestion;
delete result.nameQuestion.validate;

t.is(validate('ab-1_2'), null);
t.is(validate(' a'), 'Please only use letters, numbers, dash(-) and underscore(_).');
t.is(validate('@a'), 'Please only use letters, numbers, dash(-) and underscore(_).');
t.deepEqual(result, {
questions: [{
nameQuestion: {
name: 'name',
message: 'Please name this new project:',
default: 'my-app'
}],
},
questions: [],
prependTransforms: [],
appendTransforms: [],
before: undefined,
Expand All @@ -144,18 +148,19 @@ test.serial('skeletonConfig skip npm install when no packge.json', async t => {

const result = await config('skeleton', {_npmInstall: npmInstall});
t.falsy(installed);
const {validate} = result.questions[0];
delete result.questions[0].validate;
const {validate} = result.nameQuestion;
delete result.nameQuestion.validate;

t.is(validate('ab-1_2'), null);
t.is(validate(' a'), 'Please only use letters, numbers, dash(-) and underscore(_).');
t.is(validate('@a'), 'Please only use letters, numbers, dash(-) and underscore(_).');
t.deepEqual(result, {
questions: [{
nameQuestion: {
name: 'name',
message: 'Please name this new project:',
default: 'my-app'
}],
},
questions: [],
prependTransforms: [],
appendTransforms: [],
before: undefined,
Expand Down Expand Up @@ -186,19 +191,19 @@ test.serial('skeletonConfig reads questions, and transforms', async t => {


const result = await config('skeleton', {_require: mockRequire});
const {validate} = result.questions[0];
delete result.questions[0].validate;
const {validate} = result.nameQuestion;
delete result.nameQuestion.validate;

t.is(validate('ab-1_2'), null);
t.is(validate(' a'), 'Please only use letters, numbers, dash(-) and underscore(_).');
t.is(validate('@a'), 'Please only use letters, numbers, dash(-) and underscore(_).');
t.deepEqual(result, {
nameQuestion: {
name: 'name',
message: 'Please name this new project:',
default: 'my-app'
},
questions: [
{
name: 'name',
message: 'Please name this new project:',
default: 'my-app'
},
{name: 'description', message: 'Des'},
{choices: [{value: 'one'}], message: 'Choose'}
],
Expand Down Expand Up @@ -230,15 +235,15 @@ test.serial('skeletonConfig does not inject question for project name if user pr
}

const result = await config('skeleton', {_require: mockRequire});
const {validate} = result.questions[0];
delete result.questions[0].validate;
const {validate} = result.nameQuestion;
delete result.nameQuestion.validate;

t.is(validate('ab-1_2'), null);
t.is(validate(' a'), 'Please only use letters, numbers, dash(-) and underscore(_).');
t.is(validate('@a'), 'Please only use letters, numbers, dash(-) and underscore(_).');
t.deepEqual(result, {
nameQuestion: {name: 'name', message: 'Name', default: 'my-app'},
questions: [
{name: 'name', message: 'Name', default: 'my-app'},
{name: 'description', message: 'Des'},
{choices: [{value: 'one'}], message: 'Choose'}
],
Expand Down Expand Up @@ -266,20 +271,19 @@ test.serial('skeletonConfig reads before and after tasks', async t => {


const result = await config('skeleton', {_require: mockRequire});
const {validate} = result.questions[0];
delete result.questions[0].validate;
const {validate} = result.nameQuestion;
delete result.nameQuestion.validate;

t.is(validate('ab-1_2'), null);
t.is(validate(' a'), 'Please only use letters, numbers, dash(-) and underscore(_).');
t.is(validate('@a'), 'Please only use letters, numbers, dash(-) and underscore(_).');
t.deepEqual(result, {
questions: [
{
name: 'name',
message: 'Please name this new project:',
default: 'my-app'
}
],
nameQuestion: {
name: 'name',
message: 'Please name this new project:',
default: 'my-app'
},
questions: [],
prependTransforms: [],
appendTransforms: [],
before: 'before',
Expand Down

0 comments on commit 658cf57

Please sign in to comment.