# Programmatic API

Integrate Orval code generation into your build processes, scripts, or tools.

## Basic Usage

```ts
import orval from 'orval';

// Generate using a config file path
await orval('./orval.config.js');

// Generate using current directory's orval config
await orval();
```

Or use the named export:

```ts
import { generate } from 'orval';

await generate('./orval.config.js');
```

## Direct Configuration

Pass a configuration object directly:

```ts
import { generate, type Options } from 'orval';

const config: Options = {
  input: {
    target: './api-spec.yaml',
  },
  output: {
    target: './src/api.ts',
    client: 'axios',
  },
};

await generate(config);
```

## Global Options Override

Override config settings with global options. See the [GlobalOptions interface](https://github.com/orval-labs/orval/blob/master/packages/core/src/types.ts#L718) for all available options.

```ts
import { generate, type GlobalOptions } from 'orval';

const globalOptions: GlobalOptions = {
  // File watching
  watch: true, // Enable watch mode (boolean)
  // watch: './specs/**/*.yaml',        // Watch specific file pattern (string)
  // watch: ['./specs/*.yaml'],         // Watch multiple patterns (string[])

  // Output control
  clean: true, // Clean all output directories (boolean)
  // clean: ['./src/api', './types'],   // Clean specific directories (string[])
  output: './src/generated', // Override output directory

  // Code formatting (only one formatter can be used at a time)
  formatter: 'prettier', // 'prettier' | 'biome' | 'oxfmt'

  // HTTP client configuration
  client: 'fetch', // Override HTTP client
  httpClient: 'fetch', // HTTP implementation: 'axios' | 'fetch'

  // Generation mode
  mode: 'split', // Output mode: 'single' | 'split' | 'tags' | 'tags-split'

  // Mock data generation
  mock: true, // Enable mock data generation
  // mock: { generators: [{ type: 'msw', delay: 1000 }] },  // Configure mock options

  // TypeScript configuration
  tsconfig: './tsconfig.json', // Custom tsconfig path
  // tsconfig: { compilerOptions: {...} },  // Inline tsconfig

  // Package configuration
  packageJson: './package.json',
  input: './api-spec.yaml',

  // Logging
  logLevel: 'error', // Only log errors

  // Error handling
  throwOnError: true, // Throw initial generation errors instead of only logging them
};

await generate('./orval.config.js', process.cwd(), globalOptions);
```

## Custom Workspace

Specify a custom workspace directory:

```ts
import { generate } from 'orval';

const workspace = '/path/to/your/project';
await generate('./orval.config.js', workspace);
```

## Function Signature

```ts
function generate(
  optionsExport?: string | OptionsExport,
  workspace?: string,
  options?: GlobalOptions,
): Promise<void>;
```

**Parameters:**
- `optionsExport`: Path to config file or configuration object
- `workspace`: Working directory (defaults to `process.cwd()`)
- `options`: Global options to override config settings

## Error Handling

By default, `generate()` logs initial generation errors and resolves after processing the configured project or projects. Set `throwOnError` when a script needs to catch initial generation failures and decide how to handle them:

```ts
import { generate } from 'orval';

try {
  await generate('./orval.config.js', process.cwd(), {
    throwOnError: true,
  });
} catch {
  process.exit(1);
}
```

`generate()` logs the error through the active reporter before rethrowing. `logger.error` is a no-op outside `withReporter`, so do not use it in this catch block.

When a config file contains multiple projects, `throwOnError` stops on the first generation error during the initial run instead of continuing with later projects. Watch mode generation errors are still logged after the watcher has started.

## Reporter

Reporter selection is a programmatic execution concern, not an `orval.config.ts` option. Built-in packages emit structured events (`message`, `packageName`, and optional `projectName`) to the reporter that is active for the current async call chain.

| Entry point | Default |
| --- | --- |
| Lower-level APIs (`generateSpec`, helpers, formatters) | No-op |
| CLI (`orval`) | Console |
| Public `generate()` | Console, unless an outer `withReporter` is already active |

Use `withReporter` to install a reporter for one call chain. An outer reporter always wins over `generate()`'s console default, so tests can silence output without changing production callers.

```ts
import { generate, withReporter, noopReporter, consoleReporter } from 'orval';

// Quiet a programmatic generate() in tests
await withReporter(noopReporter, () => generate(config));

// Opt lower-level APIs into the existing terminal output
await withReporter(consoleReporter, () => generateSpec(workspace, options));
```

Custom reporters receive the structured event. When a project is in scope, the logger prefixes `message` with that project name. Messages keep their current wording and ANSI styling; strip colors if you need plain text.

```ts
import { generate, withReporter, type OrvalReporter } from 'orval';

const reporter: OrvalReporter = {
  info: (event) => process.stdout.write(`${event.packageName}: ${event.message}\n`),
  warn: (event) => process.stderr.write(`${event.packageName}: ${event.message}\n`),
  error: (event) => process.stderr.write(`${event.packageName}: ${event.message}\n`),
  verbose: (event) => process.stderr.write(`${event.packageName}: ${event.message}\n`),
  debug: (event) => {
    if (process.env.DEBUG) {
      process.stderr.write(`${event.packageName}: ${event.message}\n`);
    }
  },
};

await withReporter(reporter, () => generate(config));
```

To assert one or more events in a test, override only the levels you care about:

```ts
import { generate, noopReporter, withReporter } from 'orval';
import { vi } from 'vitest';

const warn = vi.fn();

await withReporter({ ...noopReporter, warn }, () => generate(config));

expect(warn).toHaveBeenCalledWith(
  expect.objectContaining({
    packageName: 'orval',
    message: expect.stringContaining('symbolic link'),
  }),
);
```

## Watch Mode

```ts
import { generate } from 'orval';

// Enable watch mode
await generate('./orval.config.js', process.cwd(), {
  watch: true,
});

// Watch specific files/directories
await generate('./orval.config.js', process.cwd(), {
  watch: ['./specs/*.yaml', './src/custom-types.ts'],
});
```

## Build Scripts Integration

```json
{
  "scripts": {
    "generate": "node scripts/generate-api.js",
    "dev": "npm run generate && next dev",
    "build": "npm run generate && next build"
  }
}
```

```js
const { generate } = require('orval');

async function main() {
  try {
    await generate();
    console.log('API client generated successfully');
  } catch (error) {
    console.error('Failed to generate API client:', error);
    process.exit(1);
  }
}

main();
```
