Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
6 changes: 3 additions & 3 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ jobs:
- uses: actions/setup-node@v6
with:
node-version: 24
cache: "yarn"
cache: "pnpm"

- run: yarn install --immutable
- run: pnpm install --frozen-lockfile

- run: yarn build
- run: pnpm build

- run: npm pack

Expand Down
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
!.yarn/releases
!.yarn/sdks

/test/generated/
/output
/dist

Expand All @@ -19,3 +20,9 @@ node_modules
test/*
!test/petstore.yaml
!test/config.ts
!test/generated/
!test/generated/.gitkeep
!test/generated/base/
!test/generated/base/.gitkeep
!test/generated/next/
!test/generated/next/.gitkeep
2 changes: 1 addition & 1 deletion .oxfmtrc.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"ignorePatterns": ["**/*.hbs", "node_modules", ".yarn"]
"ignorePatterns": ["**/*.hbs", "node_modules", ".yarn", "test/generated/**"]
}
1 change: 1 addition & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"$schema": "node_modules/oxlint/configuration_schema.json",
"ignorePatterns": ["test/generated/**"],
"plugins": ["eslint", "typescript", "unicorn", "import", "oxc", "promise", "vitest"],
"categories": {
"correctness": "off",
Expand Down
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ yarn openapi-codegen generate --config my-config.ts
--config Path to TS config file (default: 'openapi-codegen.config.ts')
--input Path/URL to OpenAPI JSON/YAML document
--output Output directory path (default: 'output')
--incremental Skip generation when OpenAPI and config are unchanged (default: true)
--format Format the generated code using Oxfmt (default: true)
--verbose Display detailed log messages during execution (default: false)

Expand All @@ -84,11 +85,16 @@ yarn openapi-codegen generate --config my-config.ts
--tsPath (Requires `--importPath` to be 'ts') Typescript import path (default: '@/data')
--removeOperationPrefixEndingWith Remove operation name prefixes that end with the specified string (default: 'Controller_')
--extractEnums Extract enums into separate Zod schemas (default: true)
--modelsInCommon Keep all schema declarations in defaultTag models and emit per-module proxy exports (default: false)
--replaceOptionalWithNullish Replace `.optional()` chains with `.nullish()` in generated Zod schemas (default: false)

--axiosRequestConfig Include Axios request config parameters in query hooks (default: false)
--infiniteQueries Generate infinite queries for paginated API endpoints (default: false)
--mutationEffects Add mutation effects options to mutation hooks (default: true)
--workspaceContext Allow generated hooks to resolve path/ACL params from OpenApiWorkspaceContext (default: false)
--inlineEndpoints Inline endpoint implementations into generated query files (default: false)
--inlineEndpointsExcludeModules Comma-separated modules/tags to keep as separate API files while inlineEndpoints=true
--modelsOnly Generate only model files (default: false)
--parseRequestParams Add Zod parsing to API endpoints (default: true)

--acl Generate ACL related files (default: true)
Expand Down Expand Up @@ -186,6 +192,63 @@ const config: OpenAPICodegenConfig = {
export default config;
```

### OpenApiWorkspaceContext (Path + ACL defaults)

Enable `workspaceContext: true` in codegen config (or pass `--workspaceContext`) and wrap your app subtree with `OpenApiWorkspaceContext.Provider` if generated hooks frequently repeat workspace-scoped params (for example `officeId`).

```tsx
import { OpenApiWorkspaceContext } from "@povio/openapi-codegen-cli";
// openapi-codegen.config.ts -> { workspaceContext: true }

<OpenApiWorkspaceContext.Provider values={{ officeId: "office_123" }}>
<MyWorkspacePages />
</OpenApiWorkspaceContext.Provider>;
```

Generated query/mutation hooks can then omit matching path/ACL params and resolve them from `OpenApiWorkspaceContext`.

### Generation Modes

You can control whether API endpoint files are emitted, inlined into query files, or skipped entirely.

```ts
import type { OpenAPICodegenConfig } from "@povio/openapi-codegen-cli";

const config: OpenAPICodegenConfig = {
// 1) Default mode: separate *.api.ts files are generated
// 2) Inline mode: endpoint logic is generated inside *.queries.ts
// and can be used without separate api files:
// inlineEndpoints: true,
// inlineEndpointsExcludeModules: ["Users", "Billing"],
// 3) Models-only mode: generate only *.models.ts files
// modelsOnly: true,
// 4) Keep all model declarations in common.models and generate per-module model proxies
// modelsInCommon: true,
};
```

### Vite Plugin

You can run codegen directly from Vite config (without CLI config file):

```ts
import { defineConfig } from "vite";
import { openApiCodegen } from "@povio/openapi-codegen-cli/vite";

export default defineConfig({
plugins: [
openApiCodegen({
input: "./openapi.yaml",
output: "./src/data",
inlineEndpoints: true,
incremental: true,
}),
],
});
```

The plugin runs on both `vite serve` and `vite build`, and watches local OpenAPI files in dev mode.

### Enums

If you're using Enums in your backend DTOs with `@Expose()` and `@IsEnum`, they may still not appear correctly in the OpenAPI schema unless you also provide both `enum` **and** `enumName` to `@ApiProperty`.
Expand Down
27 changes: 0 additions & 27 deletions esbuild.mjs

This file was deleted.

11 changes: 11 additions & 0 deletions openapi-codegen.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/** @type {import('./src/generators/types/config').OpenAPICodegenConfig} */
const config = {
input: "http://127.0.0.1:4000/docs-json",
output: "./test/generated/next",
excludeTags: ["auth"],
replaceOptionalWithNullish: true,
builderConfigs: true,
infiniteQueries: true,
};

export default config;
74 changes: 40 additions & 34 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
{
"name": "@povio/openapi-codegen-cli",
"version": "2.0.8-rc.5",
"version": "2.0.8-rc.6",
"keywords": [
"codegen",
"openapi",
"povio",
"react-query",
"zod"
],
"type": "module",
"homepage": "https://github.com/povio/openapi-codegen-cli",
"bugs": "https://github.com/povio/openapi-codegen-cli/issues",
"license": "BSD-3-Clause",
Expand All @@ -16,7 +17,7 @@
"url": "git+https://github.com/povio/openapi-codegen-cli.git"
},
"bin": {
"openapi-codegen": "./dist/sh.js"
"openapi-codegen": "./dist/sh.mjs"
},
"files": [
"README.md",
Expand All @@ -29,45 +30,55 @@
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.mjs"
"import": "./dist/index.mjs"
},
"./vite": {
"types": "./dist/vite.d.ts",
"import": "./dist/vite.mjs"
},
"./generator": {
"types": "./dist/generator.d.ts",
"import": "./dist/generator.js",
"require": "./dist/generator.js"
"import": "./dist/generator.mjs"
},
"./acl": {
"types": "./dist/acl.d.ts",
"import": "./dist/acl.mjs",
"require": "./dist/acl.mjs"
"import": "./dist/acl.mjs"
}
},
"scripts": {
"start": "node --import tsx ./src/sh.ts",
"test": "vitest run",
"test:watch": "vitest",
"build:clean": "rm -rf ./dist",
"build:client": "vite build",
"build:cli": "node ./esbuild.mjs && chmod +x ./dist/sh.js",
"build": "yarn build:clean && yarn build:cli && yarn build:client",
"start:dist": "node ./dist/sh.js",
"build": "tsdown",
"start:dist": "node ./dist/sh.mjs",
"gen:base": "rm -rf ./test/generated/base && mkdir -p ./test/generated/base && pnpm start generate --config ./test/config.mjs --output ./test/generated/base --no-prettier",
"gen:next": "rm -rf ./test/generated/next && mkdir -p ./test/generated/next && pnpm start generate --config ./test/config.mjs --output ./test/generated/next --no-prettier",
"test:generated-eq": "vitest run ./src/generators/generated-output-eq.test.ts",
"gen:verify": "pnpm gen:base && pnpm gen:next && pnpm test:generated-eq",
"typecheck": "tsc --noEmit",
"lint": "oxlint --type-aware --fix",
"lint:check": "oxlint --type-aware",
"format": "oxfmt",
"format:check": "oxfmt --check",
"check": "yarn typecheck && yarn lint && yarn test",
"push": "yarn exec ./scripts/publish.sh",
"dev:generate": "rm -rf ./output && yarn start generate --config ./test/config.ts",
"dev:check": "yarn start check --config ./test/config.ts"
"check": "pnpm typecheck && pnpm lint && pnpm test",
"push": "node ./scripts/publish.mjs",
"dev:generate": "rm -rf ./output && pnpm start generate --config ./test/config.mjs",
"dev:check": "pnpm start check --config ./test/config.mjs",
"snapshot:openapi-localhost": "node ./scripts/snapshot-openapi-localhost.mjs",
"bench:vite-codegen": "node ./scripts/benchmark-vite-codegen.mjs"
},
"dependencies": {
"@apidevtools/swagger-parser": "^10.1.0",
"handlebars": "^4.7.8",
"i18next": "^25.8.11",
"import-fresh": "^3.3.1"
"import-fresh": "^3.3.1",
"prompt-sync": "^4.2.0",
"reflect-metadata": "^0.2.2",
"ts-pattern": "^5.9.0",
"typescript": "^5.9.3",
"yargs": "^18.0.0"
},
"devDependencies": {
"@apidevtools/swagger-parser": "^10.1.0",
"@casl/ability": "^6.8.0",
"@casl/react": "^5.0.1",
"@tanstack/react-query": "~5.90.21",
Expand All @@ -76,32 +87,25 @@
"@types/react": "^19.2.14",
"@types/yargs": "^17.0.35",
"@vitejs/plugin-react": "^5.1.4",
"axios": "^1.13.5",
"esbuild": "0.27.3",
"handlebars": "^4.7.8",
"openapi-types": "^12.1.3",
"oxfmt": "^0.34.0",
"oxlint": "^1.49.0",
"oxlint-tsgolint": "^0.14.1",
"prompt-sync": "^4.2.0",
"react": "^19.2.4",
"reflect-metadata": "^0.2.2",
"ts-pattern": "^5.9.0",
"tsdown": "^0.21.0-beta.1",
"tsx": "^4.21.0",
"type-fest": "^5.4.4",
"typescript": "^5.9.3",
"vite": "^7.3.1",
"vite": "npm:rolldown-vite@^7.3.1",
"vite-plugin-dts": "^4.5.4",
"vitest": "4.0.18",
"yargs": "^18.0.0",
"zod": "^4.3.6"
"vitest": "4.0.18"
},
"peerDependencies": {
"@casl/ability": "^6.7.3",
"@casl/react": "^5.0.0",
"@tanstack/react-query": "^5.90.21",
"axios": "^1.13.1",
"openapi-types": "^12.1.3",
"react": "^19.1.0",
"vite": "^6.0.0 || ^7.0.0",
"zod": "^4.1.12"
},
"peerDependenciesMeta": {
Expand All @@ -110,12 +114,14 @@
},
"@casl/react": {
"optional": true
},
"vite": {
"optional": true
}
},
"engines": {
"node": ">= 14",
"npm": ">= 8",
"yarn": ">= 3.2"
"pnpm": ">= 9"
},
"packageManager": "yarn@4.2.2"
"packageManager": "pnpm@10.4.0"
}
Loading