Skip to content

Commit

Permalink
feat: add node ace add command (#4296)
Browse files Browse the repository at this point in the history
* feat: add Add command

* refactor: pass unknown args to configure command

* fix: test on windows
  • Loading branch information
Julien-R44 committed Feb 20, 2024
1 parent d83e970 commit e7c668c
Show file tree
Hide file tree
Showing 2 changed files with 485 additions and 0 deletions.
157 changes: 157 additions & 0 deletions commands/add.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* @adonisjs/core
*
* (c) AdonisJS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { detectPackageManager, installPackage } from '@antfu/install-pkg'

import { CommandOptions } from '../types/ace.js'
import { args, BaseCommand, flags } from '../modules/ace/main.js'

/**
* The install command is used to `npm install` and `node ace configure` a new package
* in one go.
*/
export default class Add extends BaseCommand {
static commandName = 'install'
static description = 'Install and configure a package'
static options: CommandOptions = {
allowUnknownFlags: true,
}

@args.string({ description: 'Package name' })
declare name: string

@flags.boolean({ description: 'Display logs in verbose mode' })
declare verbose?: boolean

@flags.string({ description: 'Select the package manager you want to use' })
declare packageManager?: 'npm' | 'pnpm' | 'yarn'

@flags.boolean({ description: 'Should we install the package as a dev dependency', alias: 'D' })
declare dev?: boolean

@flags.boolean({ description: 'Forcefully overwrite existing files' })
declare force?: boolean

/**
* Detect the package manager to use
*/
async #getPackageManager() {
const pkgManager =
this.packageManager || (await detectPackageManager(this.app.makePath())) || 'npm'

if (['npm', 'pnpm', 'yarn'].includes(pkgManager)) {
return pkgManager as 'npm' | 'pnpm' | 'yarn'
}

throw new Error('Invalid package manager. Must be one of npm, pnpm or yarn')
}

/**
* Configure the package by delegating the work to the `node ace configure` command
*/
async #configurePackage() {
/**
* Sending unknown flags to the configure command
*/
const flagValueArray = this.parsed.unknownFlags
.filter((flag) => !!this.parsed.flags[flag])
.map((flag) => `--${flag}=${this.parsed.flags[flag]}`)

const configureArgs = [
this.name,
this.force ? '--force' : undefined,
this.verbose ? '--verbose' : undefined,
...flagValueArray,
].filter(Boolean) as string[]

return await this.kernel.exec('configure', configureArgs)
}

/**
* Install the package using the selected package manager
*/
async #installPackage(npmPackageName: string) {
const colors = this.colors
const spinner = this.logger
.await(`installing ${colors.green(this.name)} using ${colors.grey(this.packageManager!)}`)
.start()

spinner.start()

try {
await installPackage(npmPackageName, {
dev: this.dev,
silent: this.verbose === true ? false : true,
cwd: this.app.makePath(),
packageManager: this.packageManager,
})

spinner.update('package installed successfully')
spinner.stop()

return true
} catch (error) {
spinner.update('unable to install the package')
spinner.stop()

this.logger.fatal(error)
this.exitCode = 1
return false
}
}

/**
* Run method is invoked by ace automatically
*/
async run() {
const colors = this.colors
this.packageManager = await this.#getPackageManager()

/**
* Handle special packages to configure
*/
let npmPackageName = this.name
if (this.name === 'vinejs') {
npmPackageName = '@vinejs/vine'
} else if (this.name === 'edge') {
npmPackageName = 'edge.js'
}

/**
* Prompt the user to confirm the installation
*/
const cmd = colors.grey(`${this.packageManager} add ${this.dev ? '-D ' : ''}${this.name}`)
this.logger.info(`Installing the package using the following command : ${cmd}`)

const shouldInstall = await this.prompt.confirm('Continue ?', { name: 'install' })
if (!shouldInstall) {
this.logger.info('Installation cancelled')
return
}

/**
* Install package
*/
const pkgWasInstalled = await this.#installPackage(npmPackageName)
if (!pkgWasInstalled) {
return
}

/**
* Configure package
*/
const { exitCode } = await this.#configurePackage()
this.exitCode = exitCode
if (exitCode === 0) {
this.logger.success(`Installed and configured ${colors.green(this.name)}`)
} else {
this.logger.fatal(`Unable to configure ${colors.green(this.name)}`)
}
}
}

0 comments on commit e7c668c

Please sign in to comment.