2019-03-14 10:07:47 +00:00
import path from 'path'
2019-03-03 08:12:46 +00:00
import consola from 'consola'
2018-12-20 11:15:48 +00:00
import minimist from 'minimist'
2018-10-25 07:43:42 +00:00
import { name , version } from '../package.json'
2019-04-11 10:04:21 +00:00
import { forceExit } from './utils'
import { loadNuxtConfig } from './utils/config'
2019-02-06 19:23:42 +00:00
import { indent , foldLines , colorize } from './utils/formatting'
import { startSpaces , optionSpaces , forceExitTimeout } from './utils/constants'
2019-03-29 19:19:30 +00:00
import { detectTypeScript } from './utils/typescript'
2018-10-25 07:43:42 +00:00
import * as imports from './imports'
export default class NuxtCommand {
2018-12-20 11:15:48 +00:00
constructor ( cmd = { name : '' , usage : '' , description : '' } , argv = process . argv . slice ( 2 ) ) {
if ( ! cmd . options ) {
cmd . options = { }
}
2018-12-09 10:42:22 +00:00
this . cmd = cmd
2018-12-20 11:15:48 +00:00
this . _argv = Array . from ( argv )
this . _parsedArgv = null // Lazy evaluate
2018-10-29 22:16:16 +00:00
}
2018-12-20 11:15:48 +00:00
static run ( cmd , argv ) {
return NuxtCommand . from ( cmd , argv ) . run ( )
2018-11-02 04:35:32 +00:00
}
2018-12-20 11:15:48 +00:00
static from ( cmd , argv ) {
if ( cmd instanceof NuxtCommand ) {
return cmd
2018-10-29 22:16:16 +00:00
}
2018-12-20 11:15:48 +00:00
return new NuxtCommand ( cmd , argv )
2018-10-25 07:43:42 +00:00
}
2019-03-16 12:42:35 +00:00
async run ( ) {
2018-12-20 11:15:48 +00:00
if ( this . argv . help ) {
this . showHelp ( )
2019-03-16 12:42:35 +00:00
return
2018-12-20 11:15:48 +00:00
}
if ( this . argv . version ) {
this . showVersion ( )
2019-03-16 12:42:35 +00:00
return
2018-12-20 11:15:48 +00:00
}
if ( typeof this . cmd . run !== 'function' ) {
2019-03-16 12:42:35 +00:00
return
2018-12-20 11:15:48 +00:00
}
2019-03-16 12:42:35 +00:00
let cmdError
try {
await this . cmd . run ( this )
} catch ( e ) {
cmdError = e
}
2019-02-06 19:23:42 +00:00
2019-03-03 08:12:46 +00:00
if ( this . argv . lock ) {
2019-03-16 12:42:35 +00:00
await this . releaseLock ( )
2019-03-03 08:12:46 +00:00
}
2019-02-08 10:06:47 +00:00
if ( this . argv [ 'force-exit' ] ) {
const forceExitByUser = this . isUserSuppliedArg ( 'force-exit' )
2019-03-16 12:42:35 +00:00
if ( cmdError ) {
consola . fatal ( cmdError )
}
forceExit ( this . cmd . name , forceExitByUser ? false : forceExitTimeout )
if ( forceExitByUser ) {
return
}
2019-02-06 19:23:42 +00:00
}
2019-03-16 12:42:35 +00:00
if ( cmdError ) {
throw cmdError
}
2018-11-08 09:15:56 +00:00
}
2018-10-25 07:43:42 +00:00
2018-11-08 09:15:56 +00:00
showVersion ( ) {
process . stdout . write ( ` ${ name } v ${ version } \n ` )
}
2018-10-25 07:43:42 +00:00
2018-11-08 09:15:56 +00:00
showHelp ( ) {
process . stdout . write ( this . _getHelp ( ) )
2018-10-25 07:43:42 +00:00
}
2018-12-20 11:15:48 +00:00
get argv ( ) {
if ( ! this . _parsedArgv ) {
const minimistOptions = this . _getMinimistOptions ( )
this . _parsedArgv = minimist ( this . _argv , minimistOptions )
2018-10-25 07:43:42 +00:00
}
2018-12-20 11:15:48 +00:00
return this . _parsedArgv
2018-10-25 07:43:42 +00:00
}
2019-03-14 10:07:47 +00:00
async getNuxtConfig ( extraOptions = { } ) {
const rootDir = path . resolve ( this . argv . _ [ 0 ] || '.' )
2019-03-29 19:19:30 +00:00
2019-05-30 10:03:57 +00:00
// Flag to indicate nuxt is running with CLI (not programmatic)
extraOptions . _cli = true
2019-03-29 19:19:30 +00:00
// Typescript support
extraOptions . _typescript = await detectTypeScript ( rootDir , {
transpileOnly : this . cmd . name === 'start'
} )
2019-03-14 10:07:47 +00:00
2018-12-20 11:15:48 +00:00
const config = await loadNuxtConfig ( this . argv )
2019-03-03 08:12:46 +00:00
const options = Object . assign ( config , extraOptions )
2018-10-25 07:43:42 +00:00
2018-12-09 10:42:22 +00:00
for ( const name of Object . keys ( this . cmd . options ) ) {
2018-12-20 11:15:48 +00:00
this . cmd . options [ name ] . prepare && this . cmd . options [ name ] . prepare ( this , options , this . argv )
2018-10-25 07:43:42 +00:00
}
return options
}
async getNuxt ( options ) {
2018-10-25 15:40:55 +00:00
const { Nuxt } = await imports . core ( )
2019-03-08 20:43:23 +00:00
2018-12-01 10:13:28 +00:00
const nuxt = new Nuxt ( options )
await nuxt . ready ( )
2019-03-08 20:43:23 +00:00
2018-12-01 10:13:28 +00:00
return nuxt
2018-10-25 07:43:42 +00:00
}
async getBuilder ( nuxt ) {
2018-10-25 15:40:55 +00:00
const { Builder } = await imports . builder ( )
const { BundleBuilder } = await imports . webpack ( )
2018-10-25 11:22:31 +00:00
return new Builder ( nuxt , BundleBuilder )
2018-10-25 07:43:42 +00:00
}
async getGenerator ( nuxt ) {
2018-10-25 15:40:55 +00:00
const { Generator } = await imports . generator ( )
2018-10-25 11:22:31 +00:00
const builder = await this . getBuilder ( nuxt )
return new Generator ( nuxt , builder )
2018-10-25 07:43:42 +00:00
}
2019-03-03 08:12:46 +00:00
async setLock ( lockRelease ) {
if ( lockRelease ) {
if ( this . _lockRelease ) {
consola . warn ( ` A previous unreleased lock was found, this shouldn't happen and is probably an error in 'nuxt ${ this . cmd . name } ' command. The lock will be removed but be aware of potential strange results ` )
await this . releaseLock ( )
this . _lockRelease = lockRelease
} else {
this . _lockRelease = lockRelease
}
}
}
async releaseLock ( ) {
if ( this . _lockRelease ) {
await this . _lockRelease ( )
this . _lockRelease = undefined
}
}
2019-02-08 10:06:47 +00:00
isUserSuppliedArg ( option ) {
return this . _argv . includes ( ` -- ${ option } ` ) || this . _argv . includes ( ` --no- ${ option } ` )
}
_getDefaultOptionValue ( option ) {
return typeof option . default === 'function' ? option . default ( this . cmd ) : option . default
}
2018-11-08 09:15:56 +00:00
_getMinimistOptions ( ) {
const minimistOptions = {
alias : { } ,
boolean : [ ] ,
string : [ ] ,
default : { }
}
2018-12-09 10:42:22 +00:00
for ( const name of Object . keys ( this . cmd . options ) ) {
const option = this . cmd . options [ name ]
2018-11-08 09:15:56 +00:00
if ( option . alias ) {
minimistOptions . alias [ option . alias ] = name
}
if ( option . type ) {
minimistOptions [ option . type ] . push ( option . alias || name )
}
if ( option . default ) {
2019-02-08 10:06:47 +00:00
minimistOptions . default [ option . alias || name ] = this . _getDefaultOptionValue ( option )
2018-11-08 09:15:56 +00:00
}
}
return minimistOptions
}
2018-10-25 07:43:42 +00:00
_getHelp ( ) {
const options = [ ]
let maxOptionLength = 0
2018-10-29 22:16:16 +00:00
2018-12-09 10:42:22 +00:00
for ( const name in this . cmd . options ) {
const option = this . cmd . options [ name ]
2018-10-29 22:16:16 +00:00
let optionHelp = '--'
2019-02-08 10:06:47 +00:00
optionHelp += option . type === 'boolean' && this . _getDefaultOptionValue ( option ) ? 'no-' : ''
2018-10-29 22:16:16 +00:00
optionHelp += name
if ( option . alias ) {
optionHelp += ` , - ${ option . alias } `
2018-10-25 07:43:42 +00:00
}
2018-10-29 22:16:16 +00:00
maxOptionLength = Math . max ( maxOptionLength , optionHelp . length )
options . push ( [ optionHelp , option . description ] )
2018-10-25 07:43:42 +00:00
}
2018-10-29 22:16:16 +00:00
const _opts = options . map ( ( [ option , description ] ) => {
const i = indent ( maxOptionLength + optionSpaces - option . length )
return foldLines (
option + i + description ,
startSpaces + maxOptionLength + optionSpaces * 2 ,
startSpaces + optionSpaces
)
2018-10-25 07:43:42 +00:00
} ) . join ( '\n' )
2018-12-09 10:42:22 +00:00
const usage = foldLines ( ` Usage: nuxt ${ this . cmd . usage } [options] ` , startSpaces )
const description = foldLines ( this . cmd . description , startSpaces )
2018-11-01 03:53:06 +00:00
const opts = foldLines ( ` Options: ` , startSpaces ) + '\n\n' + _opts
2018-10-25 07:43:42 +00:00
2018-11-08 09:15:56 +00:00
let helpText = colorize ( ` ${ usage } \n \n ` )
2018-12-09 22:00:48 +00:00
if ( this . cmd . description ) {
helpText += colorize ( ` ${ description } \n \n ` )
}
if ( options . length ) {
helpText += colorize ( ` ${ opts } \n \n ` )
}
2018-10-25 07:43:42 +00:00
2018-11-08 09:15:56 +00:00
return helpText
2018-10-25 07:43:42 +00:00
}
}