diff --git a/docs/configuring_your_cli.md b/docs/configuring_your_cli.md index 11c41a13..b5f6358a 100644 --- a/docs/configuring_your_cli.md +++ b/docs/configuring_your_cli.md @@ -3,7 +3,9 @@ title: Configuring Your CLI description: All about configuring oclif --- -You can configure the behavior of oclif inside your CLI or plugin's package.json. All of the configuration options should be placed under the `oclif` section. For example: +You can configure the behavior of oclif inside your CLI or plugin's package.json or using an rc file. + +In you use the `package.json`, all of the configuration options should be placed under the `oclif` section. For example: ```json { @@ -21,6 +23,35 @@ You can configure the behavior of oclif inside your CLI or plugin's package.json } ``` +If you'd like to use an rc file, then you do not need to put the configuration under `oclif`. For instance: + +```javascript +//.oclifrc.js + +module.exports = { + bin: "mycli", + dirname: "mycli", + commands: "./dist/commands", + topicSeparator: " " +} +``` + +The following rc files are supported: +``` +.oclifrc +.oclifrc.json +.oclifrc.yaml +.oclifrc.yml +.oclifrc.js +.oclifrc.ts +.oclifrc.mjs +.oclifrc.cjs +oclif.config.js +oclif.config.ts +oclif.config.mjs +oclif.config.cjs +``` + Here's a list of all the options that you can configure. | Property | Description | diff --git a/docs/jit_plugins.md b/docs/jit_plugins.md index 0dd8eb73..be73ce29 100644 --- a/docs/jit_plugins.md +++ b/docs/jit_plugins.md @@ -29,12 +29,15 @@ In the case of JIT plugin installation, there are many possible user experiences Here's an example of how you might implement the hook, ```typescript -import { Hook, Errors, ux } from '@oclif/core'; +import { Hook, Errors } from '@oclif/core'; +import confirm from '@inquirer/confirm'; const hook: Hook.JitPluginNotInstalled = async function (opts) { try { - const answer = await ux.confirm(`${opts.command.pluginName} not installed. Would you like to install?`) - if (answer === 'y') { + const answer = await confirm({ + message: `${opts.command.pluginName} not installed. Would you like to install?` + }) + if (answer) { await opts.config.runCommand('plugins:install', [`${opts.command.pluginName}@${opts.pluginVersion}`]); } } catch (error) { diff --git a/docs/logging.md b/docs/logging.md new file mode 100644 index 00000000..d802a27a --- /dev/null +++ b/docs/logging.md @@ -0,0 +1,78 @@ +--- +title: Logging +description: oclif-generated logging and custom loggers +--- + +By default oclif uses [debug](https://www.npmjs.com/package/debug) to generate debug logs that can be viewed using the `DEBUG` environment variable. To see all the logs, you can set `DEBUG=oclif*`. + +You can also provide oclif with a custom logger, if you prefer for oclif's logs to be sent to that instead of `debug`. + +This is the interface that your logger must match: + +```typescript +export type Logger = { + debug: (formatter: unknown, ...args: unknown[]) => void + error: (formatter: unknown, ...args: unknown[]) => void + info: (formatter: unknown, ...args: unknown[]) => void + trace: (formatter: unknown, ...args: unknown[]) => void + warn: (formatter: unknown, ...args: unknown[]) => void + child: (namespace: string) => Logger + namespace: string +} +``` + +And here's an example: + +```typescript +// oclif-logger.ts +import { format } from 'node:util'; +import { Interfaces } from '@oclif/core'; +import { Logger } from './my-cli-logger'; + +export const customLogger = (namespace: string): Interfaces.Logger => { + const myLogger = new Logger(namespace); + return { + child: (ns: string, delimiter?: string) => customLogger(`${namespace}${delimiter ?? ':'}${ns}`), + debug: (formatter: unknown, ...args: unknown[]) => myLogger.debug(format(formatter, ...args)), + error: (formatter: unknown, ...args: unknown[]) => myLogger.error(format(formatter, ...args)), + info: (formatter: unknown, ...args: unknown[]) => myLogger.info(format(formatter, ...args)), + trace: (formatter: unknown, ...args: unknown[]) => myLogger.trace(format(formatter, ...args)), + warn: (formatter: unknown, ...args: unknown[]) => myLogger.warn(format(formatter, ...args)), + namespace, + }; +}; + +export const logger = customLogger('my-cli'); +``` + +You now need to provide this logger to oclif so that it can use it: + +```javascript +// bin/run.js +#!/usr/bin/env node + +async function main() { + const {execute} = await import('@oclif/core'); + const { logger } = await import('../dist/oclif-logger.js'); + await oclif.execute({ + dir: import.meta.url, + loadOptions: { + root: import.meta.dirname, + logger, + }, + }); +} + +await main(); +``` + +You can also provide the logger to `Config`, in the event that you instantiate `Config` before calling `run` or `execute` + +```javascript +import {Config, run} from '@oclif/core' +const config = await config.load({ + logger, +}); + +await run(process.argv.slice(2), config) +``` diff --git a/docs/themes.md b/docs/themes.md index 72afdcec..b0537818 100644 --- a/docs/themes.md +++ b/docs/themes.md @@ -5,7 +5,7 @@ description: Make help output pretty oclif supports themes that you can ship with your CLI, which users can then override if they choose. -By default, the theme only applies to help output but you can extend the theme for your own purposes if you want. See [Extending Themes](#extending-themes) section below. +By default, the theme only applies to help and JSON output but you can extend the theme for your own purposes if you want. See [Extending Themes](#extending-themes) section below. ## theme.json @@ -22,6 +22,17 @@ The theme file takes the following shape: "flagOptions": "white", "flagRequired": "red", "flagSeparator": "white", + "json": { + "brace": "magenta", + "bracket": "magenta", + "colon": "dim", + "comma": "dim", + "key": "yellow", + "string": "green", + "number": "green", + "boolean": "green", + "null": "red" + }, "sectionDescription": "white", "sectionHeader": "underline", "topic": "white", @@ -31,7 +42,7 @@ The theme file takes the following shape: ### Supported Theme Properties -As mentioned, the theme only applies to help output by default. The following properties can be used: +As mentioned, the theme only applies to help and JSON output by default. The following properties can be used: - `alias`: the aliases under the `ALIASES` section - `bin`: the name of your CLI's executable (e.g. `sf`, `heroku`) @@ -43,6 +54,16 @@ As mentioned, the theme only applies to help output by default. The following pr - `flagOptions`: the valid options for a flag - `flagRequired`: the `(required)` that shows on required flags - `flagSeparator`: the `,` that separates the short char and long flag names (e.g. `-f, --foo`) +- `json`: the theme for JSON output + - `brace`: the `[` and `]` + - `bracket`: the `{` and `}` + - `colon`: the `:` + - `comma`: the `,` + - `key`: all keys + - `string`: string values + - `number`: number values + - `boolean`: boolean values + - `null `: null values - `sectionDescription`: the text inside of each section (e.g. everything under `DESCRIPTION`) - `sectionHeader`: the section header (e.g. `DESCRIPTION`) - `topic`: the topics under the `TOPICS` section @@ -51,7 +72,7 @@ As mentioned, the theme only applies to help output by default. The following pr The values for each of these must be one of the following: - a hex code, e.g. `#FF0000` - a rgb, e.g. `rgb(255,255,255)` -- a style supported by `chalk` (see https://github.com/chalk/chalk/#styles) +- a standard ANSI color (see https://github.com/chalk/chalk/#styles) Any invalid values will be ignored. diff --git a/docs/user_experience.md b/docs/user_experience.md index 2ff0a109..3bce24f1 100644 --- a/docs/user_experience.md +++ b/docs/user_experience.md @@ -7,14 +7,13 @@ oclif's philosophy is that developers should be free to design any user experien So many times we utilize [hooks](./hooks.md) whenever a user experience is required (e.g. the provided command isn't found). That way, you can design the exact experience you want your users to have. In the case of error handling, you're [able to override](./error_handling.md) oclif's default behavior. -But to make it easy for you, `@oclif/core` exports a [`ux` module](https://github.com/oclif/core/blob/main/src/cli-ux/README.md) that offers several tools to implement your desired user experience. +But to make it easy for you, `@oclif/core` exports a [`ux` module](https://github.com/oclif/core/blob/main/src/ux/README.md) that offers a small number of tools to implement your desired user experience. -However, due to time constraints we are not able to support this module as well as we would like. For that reason, we **strongly** recommend that you find npm libraries that specialize in the UX components you want to use. Here's a brief list of some of the libraries we like: +If you need more complex user experiences, we suggest the following libraries: - For prompts: [inquirer](https://www.npmjs.com/package/inquirer) - For spinners: [ora](https://www.npmjs.com/package/ora) - For progress bars: [cli-progress](https://www.npmjs.com/package/cli-progress) -- For hyperlinks: [hyperlink](https://www.npmjs.com/package/hyperlink) - For tables: [tty-table](https://www.npmjs.com/package/tty-table), [cliui](https://www.npmjs.com/package/cliui) - For trees: [object-treeify](https://www.npmjs.com/package/object-treeify) - For colored JSON: [color-json](https://www.npmjs.com/package/color-json) diff --git a/website/docusaurus.config.ts b/website/docusaurus.config.ts index 71145223..c17e634e 100644 --- a/website/docusaurus.config.ts +++ b/website/docusaurus.config.ts @@ -89,8 +89,9 @@ export default async function createConfigAsync() { ], }, announcementBar: { - id: 'announcementBar-1', // Increment on change (otherwise new announcements won't show up for users who have already dismissed old ones) - content: `@oclif/core v3.0 is now out! 🥳️`, + // Increment on change (otherwise new announcements won't show up for users who have already dismissed old ones) + id: 'announcementBar-2', + content: `@oclif/core v4.0 is now out! 🥳️`, }, footer: { links: [], diff --git a/website/sidebars.ts b/website/sidebars.ts index c3393e39..8c654f8c 100644 --- a/website/sidebars.ts +++ b/website/sidebars.ts @@ -26,6 +26,7 @@ const sidebars: SidebarsConfig = { 'flexible_taxonomy', 'jit_plugins', 'json', + 'logging', 'nsis-installer_customization', 'releasing', 'running_programmatically',