Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add usage section #70

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 184 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,41 @@

🚧 This project is under heavy development. More features are coming soon!

## Usage
## Install

Install package:

```sh
# npm
npm install citty
```

# yarn
```sh
yarn add citty
```

# pnpm
```sh
pnpm install citty
```

Import:
## Usage

### Import Package

```js
// ESM
import { defineCommand, runMain } from "citty";
```

```js
// CommonJS
const { defineCommand, runMain } = require("citty");
```

Define main command to run:
### Main Command

```ts
Create a main command is the first step to create a CLI app. You can do it in a `index.mjs` file.

```js
import { defineCommand, runMain } from "citty";

const main = defineCommand({
Expand All @@ -64,19 +71,187 @@ const main = defineCommand({
description: "Use friendly greeting",
},
},
run({ args }) {
run({ args }) { // Command can be async
console.log(`${args.friendly ? "Hi" : "Greetings"} ${args.name}!`);
},
});

runMain(main);
```

Then, you can execute your CLI app:

```sh
node index.mjs john
# output: Greetings john!
```

### Sub Commands

You can define sub commands and attach them to main command to create a nested command structure. This is recursive so you can attach sub commands to sub commands, etc.

```js
import { defineCommand, runMain } from "citty";

// First, you define a new command
const sub = defineCommand({
meta: {
name: "sub",
description: "Sub command",
},
args: { // Sub commands can have their own arguments like any other command
name: {
type: "positional",
description: "Your name",
required: true,
},
},
run({ args }) { // Command can be async
console.log(`Hello ${args.name}!`);
},
});

// Then, you define a main command and attach sub command to it
const main = defineCommand({
meta: {
name: "hello",
version: "1.0.0",
description: "My Awesome CLI App",
},
commands: {
sub, // Attach sub command to main command
},
});

runMain(main);
```

Barbapapazes marked this conversation as resolved.
Show resolved Hide resolved
Then, you can execute your CLI app:

```sh
node index.mjs sub john
# output: Hello john!
```

### Hooks

`citty` supports a `setup` and `cleanup` functions that are called before and after command execution. This is useful for setting up and cleaning up resources.

Only the `setup` and `cleanup` functions from the command called are executed. For example, if you run `hello sub`, only the `setup` and `cleanup` functions from `sub` command are executed and not the ones from `hello` command.

```js
import { defineCommand, runMain } from "citty";

const main = defineCommand({
meta: {
name: "hello",
version: "1.0.0",
description: "My Awesome CLI App",
},
setup() { // Setup function is called before command execution or before any sub command execution
console.log("Setting up...");
},
cleanup() { // Cleanup function is called after command execution or after any sub command execution
console.log("Cleaning up...");
},
run() {
console.log("Hello World!");
},
});

runMain(main);
```

Barbapapazes marked this conversation as resolved.
Show resolved Hide resolved
Now, you can run your CLI app:

```sh
node index.mjs
```

And you will see:

```sh
Setting up...
Hello World!
Cleaning up...
```

### Lazy Load Commands

For large CLI apps, you may want to only load the command that is being executed.

First, create a command in a file and export it.
Barbapapazes marked this conversation as resolved.
Show resolved Hide resolved

```js
import { defineCommand } from "citty";

export default defineCommand({
meta: {
name: "sub",
description: "Sub command",
},
run({ args }) {
console.log(`Hello ${args.name}!`);
},
});
```

Then, create the main command and import the sub command.

```js
const main = defineCommand({
meta: {
name: "hello",
version: "1.0.0",
description: "My Awesome CLI App",
},
commands: {
sub: () => import("./sub.js").then((m) => m.default), // Lazy Import Sub Command
Barbapapazes marked this conversation as resolved.
Show resolved Hide resolved
},
});
```

Now, when you run `node index.mjs sub`, the sub command will be loaded and executed. This avoid to load all commands at once when you start your app.

### Publish CLI App as an Executable

You must first bundle your CLI app. To do so, you can use [`unjs/unbuild`](https://github.com/unjs/unbuild).

Then, you must create a file named `index.mjs` in a folder named `bin` at the root of your package. This file must export the main command from the `dist` build.

```js
#!/usr/bin/env node

import { runMain } from '../dist/index.mjs'

runMain()
```

Then, you will need to update your `package.json` file to enable the usage as a CLI:

```json
{
"type": "module",
"bin": "./bin/index.mjs",
// Name of the CLI will be the name of the package. You can provide an object to change the name.
// @see https://docs.npmjs.com/cli/v10/configuring-npm/package-json#bin
// "bin": {
// "my-cli": "./bin/index.mjs"
// },
"files": [
"bin",
"dist"
]
}
```

You're ready to publish your CLI app to npm!

## Utils

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we rename it to API and add more stuff like what other "type" are available for commands and explain default & required?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you refer to the args object @jd-solanki from defineCommand?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes args's type property.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good idea! I will add a section about it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added!


### `defineCommand`

`defineCommand` is a type helper for defining commands.
A type helper for defining commands.

### `runMain`

Expand Down