Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
05a9e89
chore: update oazapfts to v7.3.0 and adjust compatibility layer
Suto-Michimasa Feb 19, 2026
915e215
delete enumStyle and focus migrate v7
Suto-Michimasa Feb 19, 2026
cff7886
chore: downgrade oazapfts to v7.0.0 in package.json and yarn.lock
Suto-Michimasa Feb 19, 2026
f0b39c3
chore: update oazapfts and refactor code generation
Suto-Michimasa Feb 27, 2026
f620906
refactor: simplify discriminator handling in schema processing
Suto-Michimasa Feb 27, 2026
3e3ce58
refactor: remove makeDiscriminatorPropertiesRequired function and cle…
Suto-Michimasa Feb 27, 2026
2049dc7
chore: update oazapfts to v7.5.0-alpha.5 and refine code generation
Suto-Michimasa Feb 28, 2026
57cc6f9
refactor: streamline operation name handling and improve TypeScript v…
Suto-Michimasa Feb 28, 2026
0dd993f
refactor: improve context creation in API generation
Suto-Michimasa Feb 28, 2026
59623d8
chore: update oazapfts to v7.5.0-alpha.6 and enhance code generation
Suto-Michimasa Mar 19, 2026
30e3ac4
chore: update oazapfts to v7.5.0 in package.json and yarn.lock
Suto-Michimasa Mar 21, 2026
514b812
Merge branch 'master' of https://github.com/reduxjs/redux-toolkit int…
aryaemami59 Apr 4, 2026
5151e47
chore: fix lockfile
aryaemami59 Apr 4, 2026
8c38fb6
chore: resolve formatting issues in `generate.ts`
aryaemami59 Apr 4, 2026
7264549
Merge branch 'master' of https://github.com/reduxjs/redux-toolkit int…
aryaemami59 Apr 6, 2026
74c035a
chore: fix lockfile
aryaemami59 Apr 6, 2026
713bf3e
Merge branch 'master' of https://github.com/reduxjs/redux-toolkit int…
aryaemami59 Jun 14, 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
3 changes: 2 additions & 1 deletion packages/rtk-query-codegen-openapi/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,10 @@
},
"dependencies": {
"@apidevtools/swagger-parser": "^10.1.1",
"@oazapfts/resolve": "^1.0.0",
"commander": "^6.2.0",
"lodash.camelcase": "^4.3.0",
"oazapfts": "^6.4.0",
"oazapfts": "7.5.0",
"prettier": "^3.2.5",
"semver": "^7.3.5",
"swagger2openapi": "^7.0.4",
Expand Down
104 changes: 65 additions & 39 deletions packages/rtk-query-codegen-openapi/src/generate.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { getReferenceName, isReference, resolve, resolveArray } from '@oazapfts/resolve';
import camelCase from 'lodash.camelcase';
import path from 'node:path';
import ApiGenerator, {
import { UNSTABLE_cg as cg } from 'oazapfts';
import type { OazapftsContext } from 'oazapfts/context';
import { createContext, withMode } from 'oazapfts/context';
import {
getOperationName as _getOperationName,
createPropertyAssignment,
createQuestionToken,
getReferenceName,
isReference,
isValidIdentifier,
keywordType,
supportDeepObjects,
getResponseType,
getSchemaFromContent,
getTypeFromResponse,
getTypeFromSchema,
preprocessComponents,
} from 'oazapfts/generate';
import type { OpenAPIV3 } from 'openapi-types';
import ts from 'typescript';
Expand All @@ -24,12 +26,42 @@ import type {
ParameterMatcher,
TextMatcher,
} from './types';
import { capitalize, getOperationDefinitions, getV3Doc, removeUndefined, isQuery as testIsQuery } from './utils';
import { factory } from './utils/factory';
import { capitalize, getOperationDefinitions, getV3Doc, removeUndefined, isQuery as testIsQuery } from './utils/index';

const { createPropertyAssignment, createQuestionToken, keywordType, isValidIdentifier } = cg;

const generatedApiName = 'injectedRtkApi';
const v3DocCache: Record<string, OpenAPIV3.Document> = {};

function supportDeepObjects(params: OpenAPIV3.ParameterObject[]): OpenAPIV3.ParameterObject[] {
const res: OpenAPIV3.ParameterObject[] = [];
const merged: Record<string, any> = {};
for (const p of params) {
const m = /^(.+?)\[(.*?)\]/.exec(p.name);
if (!m) {
res.push(p);
continue;
}
const [, name, prop] = m;
let obj = merged[name];
if (!obj) {
obj = merged[name] = {
name,
in: p.in,
style: 'deepObject',
schema: {
type: 'object',
properties: {} as Record<string, any>,
},
};
res.push(obj);
}
obj.schema.properties[prop] = p.schema;
}
return res;
}

function defaultIsDataResponse(code: string, includeDefault: boolean) {
if (includeDefault && code === 'default') {
return true;
Expand Down Expand Up @@ -89,9 +121,9 @@ function withQueryComment<T extends ts.Node>(node: T, def: QueryArgDefinition, h

function getPatternFromProperty(
property: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject,
apiGen: ApiGenerator
ctx: OazapftsContext
): string | null {
const resolved = apiGen.resolve(property);
const resolved = resolve(property, ctx);
if (!resolved || typeof resolved !== 'object' || !('pattern' in resolved)) return null;
if (resolved.type !== 'string') return null;
const pattern = resolved.pattern;
Expand All @@ -101,15 +133,15 @@ function getPatternFromProperty(
function generateRegexConstantsForType(
typeName: string,
schema: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject,
apiGen: ApiGenerator
ctx: OazapftsContext
): ts.VariableStatement[] {
const resolvedSchema = apiGen.resolve(schema);
const resolvedSchema = resolve(schema, ctx);
if (!resolvedSchema || !('properties' in resolvedSchema) || !resolvedSchema.properties) return [];

const constants: ts.VariableStatement[] = [];

for (const [propertyName, property] of Object.entries(resolvedSchema.properties)) {
const pattern = getPatternFromProperty(property, apiGen);
const pattern = getPatternFromProperty(property, ctx);
if (!pattern) continue;

const constantName = camelCase(`${typeName} ${propertyName} Pattern`);
Expand Down Expand Up @@ -174,17 +206,13 @@ export async function generateApi(
) {
const v3Doc = (v3DocCache[spec] ??= await getV3Doc(spec, httpResolverOptions));

const apiGen = new ApiGenerator(v3Doc, {
const ctx = createContext(v3Doc, {
unionUndefined,
useEnumType,
mergeReadWriteOnly,
useUnknown,
});

// temporary workaround for https://github.com/oazapfts/oazapfts/issues/491
if (apiGen.spec.components?.schemas) {
apiGen.preprocessComponents(apiGen.spec.components.schemas);
}
preprocessComponents(ctx);

const operationDefinitions = getOperationDefinitions(v3Doc).filter(operationMatches(filterEndpoints));

Expand Down Expand Up @@ -258,18 +286,18 @@ export async function generateApi(
),
...Object.values(interfaces),
...(outputRegexConstants
? apiGen.aliases.flatMap((alias) => {
? ctx.aliases.flatMap((alias) => {
if (!ts.isInterfaceDeclaration(alias) && !ts.isTypeAliasDeclaration(alias)) return [alias];

const typeName = alias.name.escapedText.toString();
const schema = v3Doc.components?.schemas?.[typeName];
if (!schema) return [alias];

const regexConstants = generateRegexConstantsForType(typeName, schema, apiGen);
const regexConstants = generateRegexConstantsForType(typeName, schema, ctx);
return regexConstants.length > 0 ? [alias, ...regexConstants] : [alias];
})
: apiGen.aliases),
...apiGen.enumAliases,
: ctx.aliases),
...ctx.enumAliases,
...(hooks
? [
generateReactHooks({
Expand Down Expand Up @@ -318,22 +346,20 @@ export async function generateApi(
const tags = tag ? getTags({ verb, pathItem }) : undefined;
const isQuery = testIsQuery(verb, overrides);

const returnsJson = apiGen.getResponseType(responses) === 'json';
const returnsJson = getResponseType(ctx, responses) === 'json';
let ResponseType: ts.TypeNode = factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
if (returnsJson) {
const returnTypes = Object.entries(responses || {})
.map(
([code, response]) =>
[
code,
apiGen.resolve(response),
apiGen.getTypeFromResponse(response, 'readOnly') ||
resolve(response, ctx),
getTypeFromResponse(response, withMode(ctx, 'readOnly')) ||
factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword),
] as const
)
.filter(([status, response]) =>
isDataResponse(status, includeDefault, apiGen.resolve(response), responses || {})
)
.filter(([status, response]) => isDataResponse(status, includeDefault, resolve(response, ctx), responses || {}))
.filter(([_1, _2, type]) => type !== keywordType.void)
.map(([code, response, type]) =>
ts.addSyntheticLeadingComment(
Expand All @@ -359,10 +385,10 @@ export async function generateApi(
).name
);

const operationParameters = apiGen.resolveArray(operation.parameters);
const pathItemParameters = apiGen
.resolveArray(pathItem.parameters)
.filter((pp) => !operationParameters.some((op) => op.name === pp.name && op.in === pp.in));
const operationParameters = resolveArray(ctx, operation.parameters);
const pathItemParameters = resolveArray(ctx, pathItem.parameters).filter(
(pp) => !operationParameters.some((op) => op.name === pp.name && op.in === pp.in)
);

const parameters = supportDeepObjects([...pathItemParameters, ...operationParameters]).filter(
argumentMatches(overrides?.parameterFilter)
Expand Down Expand Up @@ -395,16 +421,16 @@ export async function generateApi(
origin: 'param',
name,
originalName: param.name,
type: apiGen.getTypeFromSchema(isReference(param) ? param : param.schema, undefined, 'writeOnly'),
type: getTypeFromSchema(withMode(ctx, 'writeOnly'), isReference(param) ? param : param.schema),
required: param.required,
param,
};
}

if (requestBody) {
const body = apiGen.resolve(requestBody);
const schema = apiGen.getSchemaFromContent(body.content);
const type = apiGen.getTypeFromSchema(schema);
const body = resolve(requestBody, ctx);
const schema = getSchemaFromContent(body.content);
const type = getTypeFromSchema(ctx, schema);
const schemaName = camelCase(
(type as any).name ||
getReferenceName(schema) ||
Expand All @@ -417,7 +443,7 @@ export async function generateApi(
origin: 'body',
name,
originalName: schemaName,
type: apiGen.getTypeFromSchema(schema, undefined, 'writeOnly'),
type: getTypeFromSchema(withMode(ctx, 'writeOnly'), schema),
required: true,
body,
};
Expand Down
14 changes: 14 additions & 0 deletions packages/rtk-query-codegen-openapi/test/generateEndpoints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,20 @@ describe('openapi spec', () => {
});
});

describe('useEnumType option', () => {
it('generates TypeScript enums when useEnumType is true', async () => {
const api = await generateEndpoints({
unionUndefined: true,
schemaFile: resolve(__dirname, 'fixtures/petstore.json'),
apiFile: './fixtures/emptyApi.ts',
useEnumType: true,
filterEndpoints: ['findPetsByStatus'],
});

expect(api).toMatch(/enum\s+\w+/);
});
});

Comment thread
aryaemami59 marked this conversation as resolved.
describe('query parameters', () => {
it('parameters overridden in swagger should also be overridden in the code', async () => {
const api = await generateEndpoints({
Expand Down
47 changes: 32 additions & 15 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7043,6 +7043,15 @@ __metadata:
languageName: node
linkType: hard

"@oazapfts/resolve@npm:^1.0.0":
version: 1.0.0
resolution: "@oazapfts/resolve@npm:1.0.0"
dependencies:
openapi-types: "npm:^12.1.3"
checksum: 10/2dfc1af464172fa3b987ed83cbd33159638bc219f6fa96e017c9c007ca02c9ce861a048475353e5bb62166074994934c519b493959b1b18f8fe49c6d5a012d4c
languageName: node
linkType: hard

"@oazapfts/runtime@npm:^1.0.3":
version: 1.2.0
resolution: "@oazapfts/runtime@npm:1.2.0"
Expand Down Expand Up @@ -8365,6 +8374,7 @@ __metadata:
"@babel/core": "npm:^7.12.10"
"@babel/preset-env": "npm:^7.12.11"
"@babel/preset-typescript": "npm:^7.12.7"
"@oazapfts/resolve": "npm:^1.0.0"
"@oazapfts/runtime": "npm:^1.0.3"
"@reduxjs/toolkit": "npm:^1.6.0"
"@tanstack/intent": "npm:^0.0.19"
Expand All @@ -8382,7 +8392,7 @@ __metadata:
lodash.camelcase: "npm:^4.3.0"
msw: "npm:^2.1.5"
node-fetch: "npm:^3.3.2"
oazapfts: "npm:^6.4.0"
oazapfts: "npm:7.5.0"
openapi-types: "npm:^9.1.0"
prettier: "npm:^3.2.5"
pretty-quick: "npm:^4.0.0"
Expand Down Expand Up @@ -22013,7 +22023,7 @@ __metadata:
languageName: node
linkType: hard

"lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.7.0, lodash@npm:~4.18.1":
"lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.23, lodash@npm:^4.7.0, lodash@npm:~4.18.1":
version: 4.18.1
resolution: "lodash@npm:4.18.1"
checksum: 10/306fea53dfd39dad1f03d45ba654a2405aebd35797b673077f401edb7df2543623dc44b9effbb98f69b32152295fff725a4cec99c684098947430600c6af0c3f
Expand Down Expand Up @@ -24510,21 +24520,21 @@ __metadata:
languageName: node
linkType: hard

"oazapfts@npm:^6.4.0":
version: 6.4.0
resolution: "oazapfts@npm:6.4.0"
"oazapfts@npm:7.5.0":
version: 7.5.0
resolution: "oazapfts@npm:7.5.0"
dependencies:
"@apidevtools/swagger-parser": "npm:^12.1.0"
lodash: "npm:^4.17.21"
"@oazapfts/resolve": "npm:^1.0.0"
lodash: "npm:^4.17.23"
minimist: "npm:^1.2.8"
swagger2openapi: "npm:^7.0.8"
tapable: "npm:^2.3.0"
typescript: "npm:^5.9.3"
peerDependencies:
"@oazapfts/runtime": "*"
"@oazapfts/runtime": ^1.2.0
bin:
oazapfts: cli.js
checksum: 10/c52d1a8d786e41b5c228d6e2a52923ac58fde86eef44c1fb31dc65171788ae7c36d6b23ab53acea91fcc20a3b6121051bc7e90a6ebb633db54380562a8a16664
oazapfts: dist/cli.js
checksum: 10/349ea06e3347c4a842004a798853418617734050e61ac9d2b4461ab9709af13a5e4f66b389d9884e5f737e06af344b8f8d788ba0afc90efadf7ca0924fc80473
languageName: node
linkType: hard

Expand Down Expand Up @@ -24759,6 +24769,13 @@ __metadata:
languageName: node
linkType: hard

"openapi-types@npm:^12.1.3":
version: 12.1.3
resolution: "openapi-types@npm:12.1.3"
checksum: 10/9d1d7ed848622b63d0a4c3f881689161b99427133054e46b8e3241e137f1c78bb0031c5d80b420ee79ac2e91d2e727ffd6fc13c553d1b0488ddc8ad389dcbef8
languageName: node
linkType: hard

"openapi-types@npm:^9.1.0":
version: 9.3.1
resolution: "openapi-types@npm:9.3.1"
Expand Down Expand Up @@ -31247,7 +31264,7 @@ __metadata:
languageName: node
linkType: hard

"swagger2openapi@npm:^7.0.4, swagger2openapi@npm:^7.0.8":
"swagger2openapi@npm:^7.0.4":
version: 7.0.8
resolution: "swagger2openapi@npm:7.0.8"
dependencies:
Expand Down Expand Up @@ -32894,8 +32911,8 @@ __metadata:
linkType: hard

"vite@npm:^6.0.0 || ^7.0.0 || ^8.0.0":
version: 8.0.3
resolution: "vite@npm:8.0.3"
version: 8.0.5
resolution: "vite@npm:8.0.5"
dependencies:
fsevents: "npm:~2.3.3"
lightningcss: "npm:^1.32.0"
Expand All @@ -32906,7 +32923,7 @@ __metadata:
peerDependencies:
"@types/node": ^20.19.0 || >=22.12.0
"@vitejs/devtools": ^0.1.0
esbuild: ^0.27.0
esbuild: ^0.27.0 || ^0.28.0
jiti: ">=1.21.0"
less: ^4.0.0
sass: ^1.70.0
Expand Down Expand Up @@ -32946,7 +32963,7 @@ __metadata:
optional: true
bin:
vite: bin/vite.js
checksum: 10/745b791cb71297ac3877af061da44751d93f198413426bbb76a1f8384d76d4162a6ad739b2bcdf5fb966cd1295db59412614aee60738e40e1c99cee561e682f0
checksum: 10/eca1ddd6309193a80a8c82607e672df3fecff88d3639382c6eaaf4c3094accd0412c16e2f1cc4a25c835f055133325eaa0355e484d4c253ffb015a7d83d68250
languageName: node
linkType: hard

Expand Down
Loading