diff --git a/lib/ask.js b/lib/ask.js index 159b5fd1fb..c052de9d40 100644 --- a/lib/ask.js +++ b/lib/ask.js @@ -41,7 +41,8 @@ function prompt (data, key, prompt, done) { name: key, message: prompt.message || prompt.label || key, default: prompt.default, - choices: prompt.choices || [] + choices: prompt.choices || [], + validate: prompt.validate || function () { return true } }], function (answers) { if (Array.isArray(answers[key])) { data[key] = {} diff --git a/lib/options.js b/lib/options.js index 897484b052..5f909f95d1 100644 --- a/lib/options.js +++ b/lib/options.js @@ -2,6 +2,7 @@ var path = require('path') var metadata = require('read-metadata') var exists = require('fs').existsSync var getGitUser = require('./git-user') +var validateName = require('validate-npm-package-name') /** * Read prompts metadata. @@ -17,6 +18,7 @@ module.exports = function options (name, dir) { : {} setDefault(opts, 'name', name) + setValidateName(opts) var author = getGitUser() if (author) { @@ -49,3 +51,14 @@ function setDefault (opts, key, val) { prompts[key]['default'] = val } } + +function setValidateName (opts) { + opts.prompts.name.validate = function (name) { + var its = validateName(name) + if (!its.validForNewPackages) { + var errors = (its.errors || []).concat(its.warnings || []) + return 'Sorry, ' + errors.join(' and ') + '.' + } + return true + } +} diff --git a/package.json b/package.json index 460dc5eda6..30b6e3f965 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,8 @@ "request": "^2.67.0", "rimraf": "^2.5.0", "semver": "^5.1.0", - "uid": "0.0.2" + "uid": "0.0.2", + "validate-npm-package-name": "^2.2.2" }, "devDependencies": { "babel-core": "^6.7.4", diff --git a/test/e2e/test.js b/test/e2e/test.js index 6c83a34b91..b7b2ee883c 100644 --- a/test/e2e/test.js +++ b/test/e2e/test.js @@ -7,11 +7,27 @@ const crypto = require('crypto') const render = require('consolidate').handlebars.render const inquirer = require('inquirer') const async = require('async') +const extend = Object.assign || require('util')._extend const generate = require('../../lib/generate') const MOCK_TEMPLATE_REPO_PATH = './test/e2e/mock-template-repo' const MOCK_TEMPLATE_BUILD_PATH = path.resolve('./test/e2e/mock-template-build') +function monkeyPatchInquirer(answers) { + // monkey patch inquirer + inquirer.prompt = (questions, cb) => { + const key = questions[0].name + const _answers = {} + const validate = questions[0].validate + const valid = validate(answers[key]) + if (valid !== true) { + throw new Error(valid) + } + _answers[key] = answers[key] + cb(_answers) + }; +} + describe('vue-cli', () => { const answers = { name: 'vue-cli-test', @@ -24,15 +40,8 @@ describe('vue-cli', () => { pick: 'no' } - // monkey patch inquirer - inquirer.prompt = (questions, cb) => { - const key = questions[0].name - const _answers = {} - _answers[key] = answers[key] - cb(_answers) - } - it('template generation', done => { + monkeyPatchInquirer(answers) generate('test', MOCK_TEMPLATE_REPO_PATH, MOCK_TEMPLATE_BUILD_PATH, err => { if (err) done(err) @@ -56,6 +65,7 @@ describe('vue-cli', () => { }) it('avoid rendering files that do not have mustaches', done => { + monkeyPatchInquirer(answers) const binFilePath = `${MOCK_TEMPLATE_REPO_PATH}/template/bin.file` const wstream = fs.createWriteStream(binFilePath) wstream.write(crypto.randomBytes(100)) @@ -79,4 +89,14 @@ describe('vue-cli', () => { }) }) }) + + it('validate input value', done => { + // deep copy + var invalidName = extend({}, answers, {name: 'INVALID-NAME'}) + monkeyPatchInquirer(invalidName) + generate('INVALID-NAME', MOCK_TEMPLATE_REPO_PATH, MOCK_TEMPLATE_BUILD_PATH, err => { + expect(err).to.be.an('error'); + done() + }) + }) })