CLI
Code-generation commands for scaffolding models, services, controllers, and exceptions, plus a codegen step for API clients.Contents
Install
Requires a matching version of @ozanarslan/corpus to be installed.
bun add @ozanarslan/corpus-cli Usage
corpus <command> <name> | [--name, -n] <name> Every command accepts -h/--help to print its usage and exit.
Global options
| Flag | Alias | Description |
|---|---|---|
--help | -h | Print the command's help text and exit. |
--name <name> | -n | Name of the entity to generate. Falls back to the first positional argument if omitted — so corpus model foo and corpus model -n foo are equivalent. |
--main <path> | -m | Override the entry file path used for wiring imports and instantiation. |
--silent | -s | Suppress info logs. |
--output <path> | -o | Override the output directory. |
--empty | -e | Generate a bare file with no default CRUD shape, where supported. |
If a file already exists at the target path, the module logs a warning and skips writing rather than overwriting it.
resource
corpus resource <name> | [--name, -n] <name> corpus res <name> | [--name, -n] <name> Scaffolds a full resource in one pass: model, exception, service, and controller, then wires the service and controller into the entry file.
Options
--name/-n— required.--empty/-e— generate a bare model with no default CRUD shape (the service and controller are then generated against whatever model shape was actually written).
Behavior
- Delegates to
model,exception,service, andcontrollergeneration internally, in that order, so the service and controller are generated against the model that was just written. - Adds import lines and instantiation lines (
new Service(),new Controller(service)) to the main file via the sharedMainFileUpdater.
model
corpus model <name> | [--name, -n] <name> corpus mdl <name> | [--name, -n] <name> Scaffolds a standalone model with a default CRUD-shaped interface or validation schema.
Options
--name/-n— required.--empty/-e— generate a bare model (a singleentityinterface with just anid), skipping the default CRUD method shapes.
Behavior
- If no validation library is configured, generates a plain
interfacewithget,getByParams,create,update, andremoveshapes, each keyed by the configured method property names. - If a validation library is configured (
zod,yup, orarktype), generates a schema class with static properties forentityand each CRUD method instead of a plain interface, and exports an inferred type alongside it. - Does not touch any other file — only writes the model file.
service
corpus service <name> | [--name, -n] <name> corpus svc <name> | [--name, -n] <name> Scaffolds a standalone service with stubbed CRUD methods, and wires it into the entry file.
Options
--name/-n— required.--empty/-e— generate a bare service with just a constructor, skipping stubbed methods.
Behavior
- If a model of the same name already exists, generates one method per model method, each typed against the model's
params/search/body/responseshapes and throwingMethod not implemented.(or the resource'sNotImplementedexception, if one exists). - If no matching model exists and
--emptyisn't set, generates stubbed, untyped methods for each of the configured default CRUD methods. - Adds an import line and an instantiation line (
const service = new Service();) to the main file.
controller
corpus controller <name> | [--name, -n] <name> corpus ctrl <name> | [--name, -n] <name> Scaffolds a standalone controller with stubbed CRUD routes, and wires it into the entry file.
Options
--name/-n— required.--empty/-e— generate a bare controller with just aprefix, skipping stubbed routes.
Behavior
- If a matching model and service both exist, generates one typed route per model method: HTTP method and path are inferred from the model's
body/paramsshapes (body+params →PUT, body only →POST, params only →DELETE, neither →GET), and path params are extracted from theparamsshape's keys (e.g.GET /:id). - If no matching model/service exist and
--emptyisn't set, generates stubbed routes for the configured default CRUD methods, each throwingMethod not implemented.. - Adds an import line and an instantiation line (
new Controller(service);) to the main file. - Note: generating a controller alone (without a matching model/service) produces untyped routes that just throw — pair it with
model/service, or useresourceto scaffold all three together.
exception
corpus exception <name> | [--name, -n] <name> corpus exc <name> | [--name, -n] <name> Scaffolds a standalone exception class.
Options
--name/-n— required.--empty/-e— generate a bare class with no default exceptions.
Behavior
- By default, generates a class with a static
NotImplementedexception (C.Status.INTERNAL_SERVER_ERROR), whichserviceandcontrollergeneration will automatically detect and throw instead of a genericError. - Does not touch any other file.
api
corpus api Generates types, model interfaces, and (unless disabled in config) an API client from your app's registered routes.
Requirements
- Your entry file must call
.listen(), either at the top level or inside a single function.
Behavior
- Reads the entry file and locates the
.listen()call. - If
.listen()is called inside a named function, rewrites the file to ensure that function is actually invoked (await fn();). - Replaces the
.listen()call with a generator invocation that reads the nearest app's routes and config, then exits. - Transpiles the rewritten file to a temporary
.mjsfile next to the entry file. - Runs the temp file in a subprocess (inheriting stdio) to execute the generator.
- Deletes the temp file afterward, whether or not generation succeeded.
Fails fatally if no .listen() call is found, or if the generator subprocess exits non-zero.
Configuration File
All fields are optional.
// corpus.config.ts
import { defineConfig } from "@ozanarslan/corpus-cli";
export default defineConfig({
silent: false,
main: "./src/main.ts",
output: "./src/corpus.gen.ts",
pkgPath: "@ozanarslan/corpus",
casing: "pascal",
validationLibrary: null,
apiClient: {
disabled: false,
exportAs: "CorpusApi",
useStaticClass: false,
},
ignoreGlobalPrefix: false,
defaultMethods: {
get: { propertyKey: "get", address: "GET /" },
getByParams: { propertyKey: "getByParams", address: "GET /:id" },
create: { propertyKey: "create", address: "POST /" },
update: { propertyKey: "update", address: "PUT /:id" },
remove: { propertyKey: "remove", address: "DELETE /:id" },
},
folderStructure: {
model: "{resource}/{resource}-model.ts",
service: "{resource}/{resource}-service.ts",
controller: "{resource}/{resource}-controller.ts",
route: "{resource}/{resource}-route.ts",
},
exportModelsNamespace: true,
exportArgsNamespace: true,
});