@trapi/cli
v2.0.0
Published
CLI for generating REST-API metadata and OpenAPI / Swagger specifications.
Maintainers
Readme
@trapi/cli ⚡
A command-line wrapper around @trapi/metadata and @trapi/swagger. Point it at your sources and it emits an OpenAPI / Swagger document — config-file driven for non-trivial setups, single-flag invocations for quick scripts.
Built on citty — --help is wired up automatically and arguments are validated up-front.
Table of Contents
Installation
npm install --save-dev @trapi/cliThe CLI ships a trapi bin. Install it in the project that owns the controllers — @trapi/metadata and @trapi/swagger are pulled in transitively, but you'll typically also install the preset you want to use (e.g. @trapi/preset-decorators-express or @trapi/preset-typescript-rest).
Quick Start
npx trapi generate \
--preset @trapi/preset-decorators-express \
--entry-point 'src/**/*.ts' \
--output docs/openapi.json \
--version 3.1The example above:
- Loads the
@trapi/preset-decorators-expresspreset. - Scans every
.tsfile undersrc/for decorated controllers. - Generates an OpenAPI 3.1 document.
- Writes it to
docs/openapi.json(the.jsonextension picks the format automatically).
Pass --format yaml or use a .yaml/.yml extension to emit YAML instead. Both --version 3.1 and --version v3.1 are accepted.
Configuration File
Anything beyond a one-liner is easier in a config file. The CLI auto-discovers trapi.config.{ts,mts,cts,mjs,cjs,js,json} (or a trapi field in package.json) in the working directory.
// trapi.config.ts
import { defineConfig } from '@trapi/cli';
export default defineConfig({
metadata: {
entryPoint: 'src/controllers/**/*.ts',
preset: '@trapi/preset-decorators-express',
tsconfig: 'tsconfig.json',
ignore: ['**/*.spec.ts'],
cache: true,
},
swagger: {
version: 'v3.2',
data: {
name: 'My API',
servers: ['https://api.example.com'],
securityDefinitions: {
bearer: { type: 'apiKey', name: 'Authorization', in: 'header' },
},
},
},
output: {
path: 'docs/openapi.json',
},
});defineConfig is an identity helper — pass any TrapiConfig and you get IDE autocompletion + type checking. The shape mirrors the underlying option types (MetadataGenerateOptions, SwaggerGenerateData, DocumentFormat), so anything those accept is reachable from config.
CLI flags override config
CLI flags always win. Drop a config in your repo for the common case, then override per-invocation:
trapi generate --version v3.1 --output docs/openapi.v3.1.jsonUse --config <path> to point at a non-discovered file, or --no-config to skip discovery entirely.
Multi-target output
Export an array to emit several specs from one metadata pass — entries with identical metadata options share extraction:
// trapi.config.ts
import { defineConfig } from '@trapi/cli';
const shared = {
metadata: {
entryPoint: 'src/controllers/**/*.ts',
preset: '@trapi/preset-decorators-express',
},
};
export default defineConfig([
{ ...shared, swagger: { version: 'v3.2' }, output: { path: 'dist/openapi.v3.2.json' } },
{ ...shared, swagger: { version: 'v2' }, output: { path: 'dist/openapi.v2.yaml' } },
]);Commands
trapi generate
Generate an OpenAPI / Swagger specification from decorated TypeScript sources.
trapi generate [OPTIONS]| Flag | Description | Default |
|------|-------------|---------|
| --entry-point | Glob pattern matching the source files to scan. Required if not set in config. | config |
| --preset | Preset to load (npm package name or local path). | config |
| --tsconfig | Path to a tsconfig.json used to compile the sources. | config |
| --ignore | Comma-separated globs to skip during the source-file scan. | config |
| --allow | Comma-separated globs to include during the source-file scan. | config |
| --cache | Cache the generated metadata between runs. | false |
| --strict | true warns on unmatched decorators, throw errors out. | off |
| --output | Output file path. The extension picks the format unless --format is set. | swagger.json |
| --format | Output document format (json | yaml). | inferred from --output |
| --version | OpenAPI specification version (v2 | v3 | v3.1 | v3.2). The leading v is optional. | v3 |
| --api-name | API name written into the spec info object. | package.json |
| --api-version | API version written into the spec info object. | package.json |
| --api-description | API description written into the spec info object. | package.json |
| --servers | Comma-separated server URLs written into spec.servers. | config |
| --security-definitions | JSON string of security scheme definitions. | config |
| --cwd | Working directory. Relative paths in config + flags are resolved against it. | process.cwd() |
| --config | Path to a config file. Disables discovery. | auto-discover |
| --no-config | Skip config discovery and ignore --config. | false |
| --log-level | silent | info | debug. | info |
Run trapi generate --help to see this list rendered against the installed version.
Examples
Generate a YAML 3.0 spec from controllers under src/api/:
trapi generate \
--entry-point 'src/api/**/*.ts' \
--preset @trapi/preset-decorators-express \
--output docs/openapi.yaml \
--version 3Pass security schemes inline (escape hatch when you don't want a config file):
trapi generate \
--entry-point 'src/**/*.ts' \
--preset @trapi/preset-decorators-express \
--servers https://api.example.com \
--security-definitions '{"bearer":{"type":"apiKey","name":"Authorization","in":"header"}}'Treat unmatched decorators as errors (catches typos like @Hiden in CI):
trapi generate --entry-point 'src/**/*.ts' --strict throwtrapi watch
Re-run generate whenever source files or the config change. Accepts the same flags as trapi generate, plus --clear to reset the console between runs.
trapi watch --entry-point 'src/**/*.ts' --preset @trapi/preset-decorators-expressThe watcher uses chokidar — atomic writes from editors are handled, and the CLI's own output files are excluded from triggering re-runs.
trapi info
Print version + environment diagnostics for bug reports.
$ trapi info
trapi 0.2.0
node v22.21.1
platform darwin arm64
cwd /path/to/project
config /path/to/project/trapi.config.ts
entries 1
@trapi/core 2.0.0
@trapi/metadata 2.0.0
@trapi/swagger 2.0.0
typescript 5.5.4trapi cache clean
Delete cached metadata files (.trapi-metadata-*.json).
trapi cache clean # wipe the OS tmpdir
trapi cache clean --directory .trapi-cache # wipe a custom dir
trapi cache clean --max-age 604800000 # only delete files older than 7 daysThe metadata cache evicts files older than maxAgeMs automatically after each successful run; this command is for manual cleanup when you want to force a cold rebuild.
Programmatic Usage
The same factory the bin uses is exported from the package:
import { runMain } from 'citty';
import { createCLIEntryPointCommand } from '@trapi/cli';
const command = await createCLIEntryPointCommand();
await runMain(command);For one-shot programmatic generation, compose @trapi/metadata + @trapi/swagger directly:
import { generateMetadata } from '@trapi/metadata';
import { generateSwagger, saveSwagger } from '@trapi/swagger';
const metadata = await generateMetadata({
entryPoint: 'src/**/*.ts',
preset: '@trapi/preset-decorators-express',
});
const spec = await generateSwagger({ version: 'v3.1', metadata });
await saveSwagger(spec, { name: 'openapi', cwd: 'docs' });Structure
src/
├── bin.ts # #!/usr/bin/env node — calls runMain()
├── module.ts # createCLIEntryPointCommand() — root command factory
├── config/ # Config file discovery, defineConfig, merge precedence
├── commands/
│ ├── generate.ts # `trapi generate`
│ ├── watch.ts # `trapi watch`
│ ├── info.ts # `trapi info`
│ ├── cache.ts # `trapi cache clean`
│ └── utils.ts # Shared arg parsing + path splitting
├── logger.ts # Tiny stderr logger + CLIUserError
├── exit.ts # Exit-code wrapper
├── utils.ts # readPackageJson() for citty meta
└── index.ts # Public exports (defineConfig, createLogger, …)License
Made with 💚
Published under MIT License.
