# command

A command in `nr` encapsulates a reference to an external executable (CLI, script, etc), the arguments to pass to it, and configuration related to how to handle its output. Commands may then be invoked by [scripts](https://darkobits.gitbook.io/nr/configuration-reference/script).

To create a command, use the function at the `command` property of the context object passed to your configuration function:

{% code title="nr.config.js" %}

```typescript
export default ({ command }) => {
    
};
```

{% endcode %}

## `command`

This function accepts the following parameters:

### `name: string`

Human friendly name for the command. This will be used for error-reporting and can be used to reference the command in scripts.

### `args:` [`CommandArguments`](https://github.com/darkobits/nr/blob/master/src/etc/types/CommandArguments.ts)

Array containing the executable/file to run and any arguments to pass to it. This array may take one of four forms, described below.

* `[executable]` of type `[string]`
* `[executable, positionals]` of type `[string, Array<string>]`
* `[executable, flags]` of type `[string, Record<string, any>]`
* `[executable, positionals, flags]` of type `[string, Array<string>, Record<string, any>]`

**Example:**

{% code title="nr.config.js" %}

```typescript
export default ({ command }) => {
  // [executable] form:
  command('unit-test', ['jest']);
  
  // [executable, positionals] form:
  command('lint', ['eslint', ['src']]);
  
  // [executable, flags] form:
  command('type-check', ['tsc', { noEmit: true }], {
    // See "Argument Casing" below.
    preserveArgumentCasing: true
  });
  
  // [executable, positionals, flags] form:
  command('compile', ['babel', ['src'], { outDir: 'dist' }]);
};
```

{% endcode %}

This approach may seem verbose at first, but compared to a single, raw string it separates the parts of a command invocation into discreet values that enable re-use:

{% code title="nr.config.js" %}

```typescript
export default ({ command }) => {
  // This list may be used to configure other commands as well.
  const extensions = ['.ts', '.tsx', '.js', '.jsx'];

  const commonBabelFlags = {
    extensions: extensions.join(','),
    outDir: 'dist',
    copyFiles: true,
    sourceMaps: true
    deleteDirOnStart: true
  };
  
  command('compile', ['babel', ['src'], commonBabelFlags]);
  
  command('compile-watch', ['babel', ['src'], {
    ...commonBabelFlags,
    watch: true
  }]);
};
```

{% endcode %}

{% hint style="warning" %}
Commands are **not** executed in a shell environment where you can use constructs like `&&`, `||`, or`$?`. Rather, a command should be shell-agnostic and point to a single executable file that will be invoked **without an interpreter** like `cmd.exe` or `/bin/bash`.
{% endhint %}

### `options?:` [`CommandOptions`](https://github.com/darkobits/nr/blob/master/src/etc/types/CommandOptions.ts)

Commands may be further configured by passing an optional options object as the third parameter to `command`. Its properties are detailed below.

#### `prefix?: (chalk: Chalk) => string`

Function that will be passed a `chalk` instance and should return a string. This string will be used to prefix each line of output from the command.

This feature can be useful in cases where scripts run multiple commands in parallel or when a CLIs output may not make it obvious what program the output is coming from.

**Example:**

In this example, let's add a prefix to our Babel command.

{% code title="nr.config.js" %}

```typescript
export default ({ command }) => {
  command('compile', ['babel', ['src'], { outDir: 'dist' }], {
    prefix: chalk => chalk.bgYellow.black('Babel')
  })
};
```

{% endcode %}

#### `execaOptions?:` [`execa.Options`](https://github.com/sindresorhus/execa/blob/main/index.d.ts#L249-L254)

`nr` executes commands using `execa`. Here, you may provide any option accepted by `execa` to further fine-tune how the command is executed.

**Example:**

{% code title="nr.config.js" %}

```typescript
export default ({ command }) => {
  command('compile', ['babel', ['src'], { outDir: 'dist' }], {
    execaOptions: {
      // Commands will inherit process.env, but additional variables can
      // be set here as well.
      env: {
        RAINBOWS: true,
        UNICORNS: true
      }
    }
  })
};
```

{% endcode %}

#### **`preserveArgumentCasing?: boolean`**

**Default:** `false`

Idiomatic JavaScript uses camel-case for object keys while the vast majority of CLIs accept named arguments in kebab-case. For this reason, `nr` automatically converts named arguments to kebab-case for you.

However, some CLIs (TypeScript, for example) expect named arguments to be in camel-case. To account for this, this option may be set to `true` to bypass automatic conversion of named arguments to kebab-case.

**Example:**

{% code title="nr.config.js" %}

```typescript
export default ({ command }) => {
  command('tsc', ['tsc', { noEmit: true }], {
    preserveArgumentCasing: true
  })
};
```

{% endcode %}

<table><thead><tr><th width="179">Return Type</th><th>Description</th></tr></thead><tbody><tr><td><a href="https://github.com/darkobits/nr/blob/master/src/etc/types/CommandThunk.ts"><code>CommandThunk</code></a></td><td>Value that may be provided to <code>script</code> to run the command.</td></tr></tbody></table>

When `command` is called, it creates a `CommandThunk`, a function that can be invoked to run the command. This function is added to a registry using the command's `name`, and then it is returned. There are two ways to reference a command in a script:

1. Use the `CommandThunk` directly in a script definition.
2. Use a string in the form `cmd:name` to instruct `nr` to look-up the command in the registry.

## `command.node`

This variant of `command` is useful for commands where the executable is the `node` binary itself.

It has the same signature as `command`. It can be used to execute a Node script (regardless of whether the executable flag has been set on it) using the current version of Node. This variant uses [`execaNode`](https://github.com/sindresorhus/execa#execanodescriptpath-arguments-options) to execute the script.

**Example:**

{% code title="nr.config.js" %}

```typescript
export default ({ command }) => {
  // Equivalent to "node ./server.js" with some additional quality of
  // life enhancements provided by execaNode.
  command.node('server', ['./server.js'])
};
```

{% endcode %}

## `command.babel`

This variant of `command` is useful for executing commands with `babel-node`.

It has the same signature as `command`. It can be used to execute a Node script (regardless of whether the executable flag has been set on it) using the `babel-node` CLI. This variant also uses [`execaNode`](https://github.com/sindresorhus/execa#execanodescriptpath-arguments-options) to execute the script.

**Example:**

{% code title="nr.config.js" %}

```typescript
export default ({ command }) => {
  // Equivalent to "babel-node --extensions=.ts,.tsx,.js,.jsx ./server.js"
  // with some additional quality of life enhancements provided by execaNode.
  command.babel('server', ['./server.js'])
};
```

{% endcode %}
