Migrating to @oclif/core
from the deprecated oclif libraries (@oclif/config
, @oclif/command
, @oclif/error
, @oclif/parser
) is relatively straight forward.
Replace imports from the old libraries with @oclif/core
. For example,
import Help from '@oclif/plugin-help';
import {Topic} from '@oclif/config';
import {Command, Flags} from '@oclif/command'
With this import:
import {Command, Flags, Topic, Help} from '@oclif/core';
We updated the Command.args
to more closely resemble flags
Before
import { Command } from '@oclif/core'
export default MyCommand extends Command {
static args = [{name: arg1, description: 'an argument', required: true}]
public async run(): Promise<void> {
const {args} = await this.parse(MyCommand) // args is useless {[name: string]: any}
}
}
After
import { Command, Args } from '@oclif/core'
export default MyCommand extends Command {
static args = {
arg1: Args.string({description: 'an argument', required: true})
}
public async run(): Promise<void> {
const {args} = await this.parse(MyCommand) // args is { arg1: string }
}
}
These are the available Args:
- string
- integer
- boolean
- url
- file
- directory
- custom
@oclif/core
now supports separate bin scripts for production and development.
You can copy these new bin scripts directly from our example repository.
We recommend that all oclif plugins specify the main
field in their package.json so that we can begin working on supporting Yarn v2.
{
"main": "lib/index.js"
}
All plugins will be required to have this field in the next major version of @oclif/core
.
@oclif/config
automatically added -h
as a short flag for --help
, -v
as a short flag for --version
, and version
as an alias for --version
.
@oclif/core
removes these so you can now use those flags for whatever you want! However, we've added a way to restore that functionality if you want to keep it.
Simply add the additionalHelpFlags
and additionalVersionFlags
properties to the oclif section of your package.json:
{
"oclif": {
"additionalHelpFlags": ["-h"],
"additionalVersionFlags": ["-v"]
}
}
To get the version
command, install @oclif/plugin-version
into your CLI:
{
"dependencies": {
"@oclif/plugin-version": "^3"
},
"oclif": {
"plugins": [
"@oclif/plugin-version"
]
}
}
By default, the topicSeparator
is set to a colon (:
) to maintain backwards compatibility with existing CLIs. If you prefer, you can now set it to a space.
For colons:
{
"oclif": {
"topicSeparator": ":"
}
}
For spaces:
{
"oclif": {
"topicSeparator": " "
}
}
NOTE: Using colons always works, even if you set the topicSeparator
to spaces. This means that you can enable spaces in your CLI without introducing a breaking change to your users.
The parse
method on Command
is now asynchronous (more here). So you'll now need to await
any calls to this.parse
:
const { args, flags } = this.parse(MyCommand)
=> const { args, flags } = await this.parse(MyCommand)
The default
property on flag definitions is now asynchronous. So you'll now need to await those.
Example:
import {Command, Flags} from '@oclif/core'
import {readFile} from 'fs/promises'
function getTeam(): Promise<string> {
return readFile('team.txt', 'utf-8')
}
export const team = Flags.build({
char: 't',
description: 'team to use',
default: () => getTeam(),
})
export class MyCLI extends Command {
static flags = {
team: team(),
}
async run() {
const {flags} = this.parse(MyCLI)
if (flags.team) console.log(`--team is ${flags.team}`)
}
}
The cli-ux
library has also been moved into @oclif/core
in order to break a complex circular dependency between the two projects.
All the exports that were available from cli-ux
are now available under the ux
namespace, with the exception of the cli
export which was identical to the ux
export.
Old:
import { cli } from 'cli-ux`
cli.log('hello world')
cli.action.start('doing things')
cli.action.stop()
New:
import { ux } from '@oclif/core`
ux.log('hello world')
ux.action.start('doing things')
ux.action.stop()
Single command CLIs now are configured in a different way. To ensure your migrated CLI work as before, you have to add the following to your oclif
configuration in the package.json
:
"oclif": {
"default": ".",
"commands": "./lib"
}
Where ./lib
points to the folder in which your tsconfig.json
is configured to output to (if you are using TypeScript), and your single command CLI entrypoint index.(ts|js)
is located.