Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
c0ef5fa
feat: replaced excludeTags with includeTags
jurerotar Mar 19, 2026
2726fd7
feat: added both includeTags and excludeTags
jurerotar Mar 19, 2026
3650731
chore: bumped version
jurerotar Mar 19, 2026
3c24f7e
chore: bumped vite peer dep version
jurerotar Mar 20, 2026
f63edf4
release: v2.0.8-rc.29
xban1x Mar 21, 2026
915f9fd
release: v2.0.8-rc.30
xban1x Mar 21, 2026
5f43b32
release: v2.0.8-rc.31
xban1x Mar 21, 2026
9fcdd89
release: v2.0.8-rc.32
xban1x Mar 21, 2026
040123b
release: v2.0.8-rc.33
xban1x Mar 21, 2026
b683a85
Improve workspace context
xban1x Mar 30, 2026
985a6f9
Improve workspace context
xban1x Mar 30, 2026
42e9118
feat: option defaultOnError config
urbankrepel May 14, 2026
9f8475d
release: v2.0.8-rc.36
urbankrepel May 15, 2026
3bd691c
feat: workspace context enchantments
urbankrepel May 15, 2026
80eb6d0
release: v2.0.8-rc.37
urbankrepel May 15, 2026
db27d34
feat: support workspaceContext on ACLs
urbankrepel May 15, 2026
35d20a0
feat: enhance endpoint response handling and add optional parameter s…
gent124 May 15, 2026
01d63dd
Merge pull request #64 from povio/fix/codegen-zod-response-and-query-…
gent124 May 19, 2026
54f7e8b
Bump Version to 2.0.8-rc.38
gent124 May 19, 2026
6ed58e2
chore: bump version to 2.0.8-rc.39
gent124 May 19, 2026
69d3141
fix: pin yargs to v17 so bundled CLI works
gent124 May 19, 2026
12dcf7b
chore: bump version to 2.0.8-rc.40
gent124 May 19, 2026
84a16c9
chore: bump version to 2.0.8-rc.41
gent124 May 19, 2026
895de3b
chore: bump version to 2.0.8-rc.41
gent124 May 19, 2026
6ea85b0
feat: support nested response params in infinite query getNextPageParam
arlindaxhemailii May 20, 2026
13f3ea3
chore: bump version to 2.0.9
arlindaxhemailii May 20, 2026
1cce020
Merge pull request #65 from povio/feat/nested-infinite-query-params
arlindaxhemailii May 20, 2026
d28b23a
chore: bump version to 2.0.4
arlindaxhemailii May 20, 2026
6a8d6f0
feat: add mutationScope option for sequential mutations via TanStack …
arlindaxhemailii May 26, 2026
d848c03
Merge branch 'main' into feat/include-tags
arlindaxhemailii May 26, 2026
61ca0f4
Merge remote-tracking branch 'origin/feat/include-tags' into feat/inc…
arlindaxhemailii May 26, 2026
2e66642
Merge remote-tracking branch 'origin/feat/mutation-scope' into feat/i…
urbankrepel May 26, 2026
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
28 changes: 24 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ yarn openapi-codegen generate --config my-config.ts
--splitByTags Organize output into separate folders based on OpenAPI operation tags (default: true)
--defaultTag (Requires `--splitByTags`) Default tag for shared code across multiple tags (default: 'Common')

--includeTags Comma-separated list of tags to include in generation
--excludeTags Comma-separated list of tags to exclude from generation
--excludePathRegex Exclude operations whose paths match the given regular expression
--excludeRedundantZodSchemas Exclude any redundant Zod schemas (default: true)
Expand All @@ -91,7 +92,9 @@ yarn openapi-codegen generate --config my-config.ts
--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)
--mutationScope Serialize mutations for the same path-param resource via TanStack scope.id (default: false)
--mutationDefaultOnError Use OpenApiQueryConfig.onError as the default onError for mutation hooks (default: false)
--workspaceContext Comma-separated list of path/ACL params that generated hooks may resolve from OpenApiWorkspaceContext
--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)
Expand All @@ -115,6 +118,7 @@ yarn openapi-codegen generate --config my-config.ts
--splitByTags Organize output into separate folders based on OpenAPI operation tags (default: true)
--defaultTag (Requires `--splitByTags`) Default tag for shared code across multiple tags (default: 'Common')

--includeTags Comma-separated list of tags to include in generation
--excludeTags Comma-separated list of tags to exclude from generation
--excludePathRegex Exclude operations whose paths match the given regular expression
--excludeRedundantZodSchemas Exclude any redundant Zod schemas (default: true)
Expand Down Expand Up @@ -192,20 +196,36 @@ const config: OpenAPICodegenConfig = {
export default config;
```

### Default mutation errors

Set `mutationDefaultOnError: true` in codegen config (or pass `--mutationDefaultOnError`) to let generated mutation hooks fall back to `OpenApiQueryConfig.Provider` when a mutation call does not define its own `onError`.

```tsx
import { ErrorHandler, OpenApiQueryConfig } from "@povio/openapi-codegen-cli";

<OpenApiQueryConfig.Provider
onError={(error) => {
errorToast({ text: ErrorHandler.getErrorMessage(error) });
}}
>
<App />
</OpenApiQueryConfig.Provider>;
```

### 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`).
Set `workspaceContext` to a list of param names in codegen config (or pass `--workspaceContext officeId,projectId`) and wrap your app subtree with `OpenApiWorkspaceContext.Provider` if generated hooks frequently repeat workspace-scoped params.

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

<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`.
Generated query/mutation hooks can then omit only those matching path/ACL params and resolve them from `OpenApiWorkspaceContext`. Params not listed in `workspaceContext` remain explicit and required.

### Generation Modes

Expand Down
2 changes: 1 addition & 1 deletion openapi-codegen.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
const config = {
input: "http://127.0.0.1:4000/docs-json",
output: "./test/generated/next",
excludeTags: ["auth"],
includeTags: ["auth"],
replaceOptionalWithNullish: true,
builderConfigs: true,
infiniteQueries: true,
Expand Down
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@povio/openapi-codegen-cli",
"version": "2.0.8-rc.26",
"version": "2.0.8-rc.38",
"keywords": [
"codegen",
"openapi",
Expand Down Expand Up @@ -99,15 +99,17 @@
"type-fest": "^5.4.4",
"vite": "npm:rolldown-vite@^7.3.1",
"vite-plugin-dts": "^4.5.4",
"vitest": "4.0.18"
"vitest": "4.0.18",
"yargs": "^17.7.2",
"zod": "^4.3.6"
},
"peerDependencies": {
"@casl/ability": "^6.7.3",
"@casl/react": "^5.0.0",
"@tanstack/react-query": "^5.90.21",
"axios": "^1.13.1",
"react": "^19.1.0",
"vite": "^6.0.0 || ^7.0.0",
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0",
"zod": "^4.1.12"
},
"peerDependenciesMeta": {
Expand Down
3 changes: 3 additions & 0 deletions src/commands/check.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class CheckOptions implements CheckParams {
@YargOption({ envAlias: "defaultTag" })
defaultTag?: string;

@YargOption({ envAlias: "includeTags" })
includeTags?: string;

@YargOption({ envAlias: "excludeTags" })
excludeTags?: string;

Expand Down
9 changes: 8 additions & 1 deletion src/commands/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,18 @@ import SwaggerParser from "@apidevtools/swagger-parser";

export type CheckParams = {
config?: string;
includeTags?: string;
excludeTags?: string;
verbose?: boolean;
} & Partial<Pick<GenerateOptions, "input" | "splitByTags" | "defaultTag">>;

export async function check({ verbose, config: configParam, excludeTags: _excludeTagsParam, ...params }: CheckParams) {
export async function check({
verbose,
config: configParam,
includeTags: _includeTagsParam,
excludeTags: _excludeTagsParam,
...params
}: CheckParams) {
const start = Date.now();

if (verbose) {
Expand Down
16 changes: 14 additions & 2 deletions src/commands/generate.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ class GenerateOptions implements GenerateParams {
@YargOption({ envAlias: "output" })
output?: string;

@YargOption({ envAlias: "clearOutput", type: "boolean" })
clearOutput?: boolean;

@YargOption({ envAlias: "incremental", type: "boolean" })
incremental?: boolean;

Expand All @@ -31,6 +34,9 @@ class GenerateOptions implements GenerateParams {
@YargOption({ envAlias: "defaultTag" })
defaultTag?: string;

@YargOption({ envAlias: "includeTags" })
includeTags?: string;

@YargOption({ envAlias: "excludeTags" })
excludeTags?: string;

Expand Down Expand Up @@ -70,8 +76,14 @@ class GenerateOptions implements GenerateParams {
@YargOption({ envAlias: "mutationEffects", type: "boolean" })
mutationEffects?: boolean;

@YargOption({ envAlias: "workspaceContext", type: "boolean" })
workspaceContext?: boolean;
@YargOption({ envAlias: "mutationDefaultOnError", type: "boolean" })
mutationDefaultOnError?: boolean;

@YargOption({ envAlias: "workspaceContext" })
workspaceContext?: string;

@YargOption({ envAlias: "mutationScope", type: "boolean" })
mutationScope?: boolean;

@YargOption({ envAlias: "parseRequestParams", type: "boolean" })
parseRequestParams?: boolean;
Expand Down
5 changes: 4 additions & 1 deletion src/commands/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@ import { Profiler } from "@/helpers/profile.helper";

export type GenerateParams = {
config?: string;
includeTags?: string;
excludeTags?: string;
inlineEndpointsExcludeModules?: string;
workspaceContext?: string;
prettier?: boolean;
verbose?: boolean;
} & Partial<
Pick<
GenerateOptions,
| "input"
| "output"
| "clearOutput"
| "incremental"
| "tsNamespaces"
| "tsPath"
Expand All @@ -33,7 +36,7 @@ export type GenerateParams = {
| "infiniteQueries"
| "axiosRequestConfig"
| "mutationEffects"
| "workspaceContext"
| "mutationScope"
| "parseRequestParams"
| "inlineEndpoints"
| "builderConfigs"
Expand Down
6 changes: 5 additions & 1 deletion src/generators/const/options.const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ export const DEFAULT_GENERATE_OPTIONS: GenerateOptions = {
// Base options
input: "http://localhost:4000/docs-json/",
output: "output",
clearOutput: false,
incremental: true,
splitByTags: true,
defaultTag: "Common",
includeTags: [],
excludeTags: [],
excludePathRegex: "",
excludeRedundantZodSchemas: true,
Expand Down Expand Up @@ -60,8 +62,10 @@ export const DEFAULT_GENERATE_OPTIONS: GenerateOptions = {
queryTypesImportPath: PACKAGE_IMPORT_PATH,
axiosRequestConfig: false,
mutationEffects: true,
workspaceContext: false,
mutationDefaultOnError: false,
workspaceContext: [],
prefetchQueries: true,
mutationScope: false,
// Infinite queries options
infiniteQueries: false,
infiniteQueryParamNames: {
Expand Down
4 changes: 4 additions & 0 deletions src/generators/core/SchemaResolver.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ export class SchemaResolver {
return this.options.defaultTag;
}

if (this.options.modelsInCommon) {
return formatTag(this.options.defaultTag);
}

const extractedEnumZodSchema = this.extractedEnumZodSchemaData.find((data) => data.zodSchemaName === zodSchemaName);
if (extractedEnumZodSchema) {
return formatTag(extractedEnumZodSchema.tag ?? this.options.defaultTag);
Expand Down
42 changes: 36 additions & 6 deletions src/generators/core/endpoints/getEndpointParameter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ import { match } from "ts-pattern";

import { ALLOWED_PATH_IN } from "@/generators/const/openapi.const";
import { SchemaResolver } from "@/generators/core/SchemaResolver.class";
import { getEnumZodSchemaCodeFromEnumNames } from "@/generators/core/zod/getZodSchema";
import { getZodChain } from "@/generators/core/zod/getZodChain";
import { getEnumZodSchemaCodeFromEnumNames, getZodSchema } from "@/generators/core/zod/getZodSchema";
import { resolveZodSchemaName } from "@/generators/core/zod/resolveZodSchemaName";
import { EndpointParameter } from "@/generators/types/endpoint";
import { ParameterObject } from "@/generators/types/openapi";
import { isSchemaObject } from "@/generators/utils/openapi-schema.utils";
import {
isParamMediaTypeAllowed,
isSortingParameterObject,
Expand All @@ -16,7 +19,6 @@ import {
getParamZodSchemaName,
getZodSchemaOperationName,
} from "@/generators/utils/zod-schema.utils";
import { resolveEndpointZodSchema } from "./resolveEndpointZodSchema";

export function getEndpointParameter({
resolver,
Expand Down Expand Up @@ -79,13 +81,41 @@ export function getEndpointParameter({
parameterSortingEnumSchemaName = enumZodSchemaName;
}

const zodSchemaName = resolveEndpointZodSchema({
resolver,
const zodSchema = getZodSchema({
schema,
resolver,
meta: { isRequired: paramObj.in === "path" ? true : (paramObj.required ?? false) },
tag,
});

const schemaObject = resolver.resolveObject(schema);

/**
* Optional query/header object params (e.g. deepObject `filter`): OpenAPI marks the param
* `required: false`, so getZodChain would append `.optional()` to the named schema. The
* endpoints template already wraps named optional params with `.optional()` in
* `ZodExtended.parse`, which duplicates optionality and breaks consumers that expect a bare
* object schema (e.g. builder configs). Keep `.nullable()` / defaults / validations; only
* skip the root presence modifier for object-shaped schemas.
*/
const rootIsOptionalQueryOrHeaderObject =
(paramObj.in === "query" || paramObj.in === "header") &&
!paramObj.required &&
isSchemaObject(schemaObject) &&
(schemaObject.type === "object" || (!!schemaObject.properties && Object.keys(schemaObject.properties).length > 0));

const zodChain = getZodChain({
schema: schemaObject,
meta: rootIsOptionalQueryOrHeaderObject ? { ...zodSchema.meta, isRequired: true } : zodSchema.meta,
options: resolver.options,
});

const zodSchemaName = resolveZodSchemaName({
schema: schemaObject,
zodSchema: zodSchema.assign(zodSchema.getCodeString(tag) + zodChain),
fallbackName,
composeBeforeResolve: true,
resolver,
tag,
});

return {
Expand All @@ -99,6 +129,6 @@ export function getEndpointParameter({
.run() as "Header" | "Query" | "Path",
zodSchema: zodSchemaName,
parameterObject: paramObj,
parameterSortingEnumSchemaName,
...(parameterSortingEnumSchemaName !== undefined ? { parameterSortingEnumSchemaName } : {}),
};
}
Loading