mirror of
https://github.com/vuejs/vue-cli.git
synced 2026-03-10 01:20:03 -05:00
feat: support prompts when invoking plugins
also add invoke prompts for eslint & typescript plugins
This commit is contained in:
50
packages/@vue/cli-plugin-eslint/prompts.js
Normal file
50
packages/@vue/cli-plugin-eslint/prompts.js
Normal file
@@ -0,0 +1,50 @@
|
||||
// these prompts are used if the plugin is late-installed into an existing
|
||||
// project and invoked by `vue invoke`.
|
||||
|
||||
const chalk = require('chalk')
|
||||
const { hasGit } = require('@vue/cli-shared-utils')
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
name: 'config',
|
||||
type: 'list',
|
||||
message: `Pick an ESLint config:`,
|
||||
choices: [
|
||||
{
|
||||
name: 'Error prevention only',
|
||||
value: 'base',
|
||||
short: 'Basic'
|
||||
},
|
||||
{
|
||||
name: 'Airbnb',
|
||||
value: 'airbnb',
|
||||
short: 'Airbnb'
|
||||
},
|
||||
{
|
||||
name: 'Standard',
|
||||
value: 'standard',
|
||||
short: 'Standard'
|
||||
},
|
||||
{
|
||||
name: 'Prettier',
|
||||
value: 'prettier',
|
||||
short: 'Prettier'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'lintOn',
|
||||
type: 'checkbox',
|
||||
message: 'Pick additional lint features:',
|
||||
choices: [
|
||||
{
|
||||
name: 'Lint on save',
|
||||
value: 'save'
|
||||
},
|
||||
{
|
||||
name: 'Lint and fix on commit' + (hasGit() ? '' : chalk.red(' (requires Git)')),
|
||||
value: 'commit'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
43
packages/@vue/cli-plugin-typescript/prompts.js
Normal file
43
packages/@vue/cli-plugin-typescript/prompts.js
Normal file
@@ -0,0 +1,43 @@
|
||||
// these prompts are used if the plugin is late-installed into an existing
|
||||
// project and invoked by `vue invoke`.
|
||||
|
||||
const chalk = require('chalk')
|
||||
const { hasGit } = require('@vue/cli-shared-utils')
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
name: `classComponent`,
|
||||
type: `confirm`,
|
||||
message: `Use class-style component syntax?`
|
||||
},
|
||||
process.env.VUE_CLI_EXPERIMENTAL ? {
|
||||
name: `experimentalCompileTsWithBabel`,
|
||||
type: `confirm`,
|
||||
message: `Compile TS with babel? ${chalk.yellow(`(experimental)`)}`
|
||||
} : {
|
||||
name: `useTsWithBabel`,
|
||||
type: `confirm`,
|
||||
message: `Use Babel alongside TypeScript for auto-detected polyfills?`
|
||||
},
|
||||
{
|
||||
name: `lint`,
|
||||
type: `confirm`,
|
||||
message: `Use TSLint?`
|
||||
},
|
||||
{
|
||||
name: `lintOn`,
|
||||
type: `checkbox`,
|
||||
when: answers => answers.lint,
|
||||
message: `Pick lint features:`,
|
||||
choices: [
|
||||
{
|
||||
name: 'Lint on save',
|
||||
value: 'save'
|
||||
},
|
||||
{
|
||||
name: 'Lint and fix on commit' + (hasGit() ? '' : chalk.red(' (requires Git)')),
|
||||
value: 'commit'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1,8 +1,12 @@
|
||||
require('../lib/invoke') // so that jest registers the file for this test
|
||||
jest.setTimeout(10000)
|
||||
jest.mock('inquirer')
|
||||
|
||||
const invoke = require('../lib/invoke')
|
||||
const { expectPrompts } = require('inquirer')
|
||||
const create = require('@vue/cli-test-utils/createTestProject')
|
||||
|
||||
test('invoke single generator', async () => {
|
||||
const project = await create('invoke', {
|
||||
async function createAndInstall (name) {
|
||||
const project = await create(name, {
|
||||
plugins: {
|
||||
'@vue/cli-plugin-babel': {}
|
||||
}
|
||||
@@ -11,10 +15,10 @@ test('invoke single generator', async () => {
|
||||
const pkg = JSON.parse(await project.read('package.json'))
|
||||
pkg.devDependencies['@vue/cli-plugin-eslint'] = '*'
|
||||
await project.write('package.json', JSON.stringify(pkg, null, 2))
|
||||
return project
|
||||
}
|
||||
|
||||
const cliBinPath = require.resolve('../bin/vue')
|
||||
await project.run(`${cliBinPath} invoke eslint --config airbnb --lintOn save,commit`)
|
||||
|
||||
async function assertUpdates (project) {
|
||||
const updatedPkg = JSON.parse(await project.read('package.json'))
|
||||
expect(updatedPkg.scripts.lint).toBe('vue-cli-service lint')
|
||||
expect(updatedPkg.devDependencies).toHaveProperty('lint-staged')
|
||||
@@ -27,4 +31,30 @@ test('invoke single generator', async () => {
|
||||
|
||||
const lintedMain = await project.read('src/main.js')
|
||||
expect(lintedMain).toMatch(';') // should've been linted in post-generate hook
|
||||
}
|
||||
|
||||
test('invoke with inline options', async () => {
|
||||
const project = await createAndInstall(`invoke-inline`)
|
||||
await project.run(`${require.resolve('../bin/vue')} invoke eslint --config airbnb --lintOn save,commit`)
|
||||
await assertUpdates(project)
|
||||
})
|
||||
|
||||
test('invoke with prompts', async () => {
|
||||
const project = await createAndInstall(`invoke-prompts`)
|
||||
expectPrompts([
|
||||
{
|
||||
message: `Pick an ESLint config`,
|
||||
choices: [`Error prevention only`, `Airbnb`, `Standard`, `Prettier`],
|
||||
choose: 1
|
||||
},
|
||||
{
|
||||
message: `Pick additional lint features`,
|
||||
choices: [`on save`, 'on commit'],
|
||||
check: [0, 1]
|
||||
}
|
||||
])
|
||||
// need to be in the same process to have inquirer mocked
|
||||
// so calling directly
|
||||
await invoke(`eslint`, {}, project.dir)
|
||||
await assertUpdates(project)
|
||||
})
|
||||
|
||||
@@ -3,6 +3,7 @@ const path = require('path')
|
||||
const execa = require('execa')
|
||||
const chalk = require('chalk')
|
||||
const resolve = require('resolve')
|
||||
const inquirer = require('inquirer')
|
||||
const Generator = require('./Generator')
|
||||
const { loadOptions } = require('./options')
|
||||
const installDeps = require('./util/installDeps')
|
||||
@@ -15,15 +16,23 @@ const {
|
||||
stopSpinner
|
||||
} = require('@vue/cli-shared-utils')
|
||||
|
||||
async function invoke (pluginName, options) {
|
||||
function load (request, context) {
|
||||
let resolvedPath
|
||||
try {
|
||||
resolvedPath = resolve.sync(request, { basedir: context })
|
||||
} catch (e) {}
|
||||
if (resolvedPath) {
|
||||
return require(resolvedPath)
|
||||
}
|
||||
}
|
||||
|
||||
async function invoke (pluginName, options = {}, context = process.cwd()) {
|
||||
delete options._
|
||||
const context = process.cwd()
|
||||
const pkgPath = path.resolve(context, 'package.json')
|
||||
const isTestOrDebug = process.env.VUE_CLI_TEST || process.env.VUE_CLI_DEBUG
|
||||
|
||||
if (!fs.existsSync(pkgPath)) {
|
||||
error(`package.json not found in ${chalk.yellow(context)}`)
|
||||
process.exit(1)
|
||||
throw new Error(`package.json not found in ${chalk.yellow(context)}`)
|
||||
}
|
||||
|
||||
const pkg = require(pkgPath)
|
||||
@@ -41,18 +50,29 @@ async function invoke (pluginName, options) {
|
||||
|
||||
const id = findPlugin(pkg.devDependencies) || findPlugin(pkg.dependencies)
|
||||
if (!id) {
|
||||
error(
|
||||
throw new Error(
|
||||
`Cannot resolve plugin ${chalk.yellow(pluginName)} from package.json. ` +
|
||||
`Did you forget to install it?`
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const generatorURI = `${id}/generator`
|
||||
const generatorPath = resolve.sync(generatorURI, { basedir: context })
|
||||
const pluginGenerator = load(`${id}/generator`, context)
|
||||
if (!pluginGenerator) {
|
||||
throw new Error(`Plugin ${id} does not have a generator.`)
|
||||
}
|
||||
|
||||
// resolve options if no command line options are passed, and the plugin
|
||||
// contains a prompt module.
|
||||
if (!Object.keys(options).length) {
|
||||
const pluginPrompts = load(`${id}/prompts`, context)
|
||||
if (pluginPrompts) {
|
||||
options = await inquirer.prompt(pluginPrompts)
|
||||
}
|
||||
}
|
||||
|
||||
const plugin = {
|
||||
id,
|
||||
apply: require(generatorPath),
|
||||
apply: pluginGenerator,
|
||||
options
|
||||
}
|
||||
|
||||
@@ -93,7 +113,7 @@ async function invoke (pluginName, options) {
|
||||
|
||||
log()
|
||||
log(` Successfully invoked generator for plugin: ${chalk.cyan(id)}`)
|
||||
if (hasGit()) {
|
||||
if (!process.env.VUE_CLI_TEST && hasGit()) {
|
||||
const { stdout } = await execa('git', ['ls-files', '--exclude-standard', '--modified', '--others'])
|
||||
log(` The following files have been updated / added:\n`)
|
||||
log(chalk.red(stdout.split(/\r?\n/g).map(line => ` ${line}`).join('\n')))
|
||||
@@ -103,9 +123,11 @@ async function invoke (pluginName, options) {
|
||||
log()
|
||||
}
|
||||
|
||||
module.exports = (pluginName, options) => {
|
||||
invoke(pluginName, options).catch(err => {
|
||||
module.exports = (...args) => {
|
||||
return invoke(...args).catch(err => {
|
||||
error(err)
|
||||
process.exit(1)
|
||||
if (!process.env.VUE_CLI_TEST) {
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user