diff --git a/e2e/kubb.config.js b/e2e/kubb.config.js index ca65d4d6f..d844339b5 100644 --- a/e2e/kubb.config.js +++ b/e2e/kubb.config.js @@ -43,9 +43,7 @@ const baseConfig = { }, plugins: [ createSwagger({ - output: { - path: 'schemas', - }, + output: false, validate: true, }), createSwagger({ @@ -57,140 +55,56 @@ const baseConfig = { createSwaggerTS({ output: { path: 'models/ts', - extName: '.js', + exportType: false, }, group: { type: 'tag', }, enumType: 'asPascalConst', - enumSuffix: 'enum', - dateType: 'date', - override: [ - { - type: 'operationId', - pattern: 'findPetsByStatus', - options: { - enumType: 'enum', - }, - }, - ], }), createSwaggerTanstackQuery({ output: { path: './clients/hooks', - exportAs: 'hooks', }, - exclude: [ - { - type: 'tag', - pattern: 'store', - }, - ], - override: [ - { - type: 'tag', - pattern: 'pet', - options: { - infinite: { - queryParam: 'test', - initialPageParam: '0', - }, - mutate: { - methods: ['post', 'put', 'delete'], - variablesType: 'mutate', - }, - }, - }, - ], group: { type: 'tag' }, - client: { - importPath: '../../../../tanstack-query-client.ts', + mutate: { + variablesType: 'mutate', + methods: ['post', 'put', 'delete'], }, - infinite: {}, - dataReturnType: 'full', - parser: 'zod', }), createSwaggerSwr({ output: { path: './clients/swr', - exportAs: 'swrHooks', }, - exclude: [ - { - type: 'tag', - pattern: 'store', - }, - ], group: { type: 'tag' }, - client: { - importPath: '../../../../swr-client.ts', - }, - dataReturnType: 'full', }), createSwaggerClient({ output: { path: './clients/axios', - exportAs: 'clients', }, - exclude: [ - { - type: 'tag', - pattern: 'store', - }, - ], group: { type: 'tag', output: './clients/axios/{{tag}}Service' }, - client: { - importPath: '../../../../axios-client.ts', - }, - dataReturnType: 'full', - pathParamsType: 'object', }), createSwaggerZod({ output: { path: './zod', - exportAs: 'zod', }, - exclude: [ - { - type: 'tag', - pattern: 'store', - }, - ], group: { type: 'tag' }, - dateType: 'date', - typed: true, }), createSwaggerZodios({ output: { path: 'zodios.ts', - exportAs: 'zodios', }, }), createSwaggerFaker({ output: { path: 'mocks', - exportAs: 'faker', }, - exclude: [ - { - type: 'tag', - pattern: 'store', - }, - ], group: { type: 'tag' }, - dateType: 'date', }), createSwaggerMsw({ output: { path: 'msw', - exportAs: 'msw', }, - exclude: [ - { - type: 'tag', - pattern: 'store', - }, - ], group: { type: 'tag' }, }), ], diff --git a/examples/advanced/configs/kubb.config.ts b/examples/advanced/configs/kubb.config.ts index 156fd7383..b5262e9c2 100644 --- a/examples/advanced/configs/kubb.config.ts +++ b/examples/advanced/configs/kubb.config.ts @@ -162,6 +162,9 @@ export default defineConfig(async () => { ], group: { type: 'tag' }, dateType: 'date', + mapper: { + status: `faker.helpers.arrayElement(['working', 'idle']) as any`, + }, }), createSwaggerMsw({ output: { diff --git a/examples/advanced/src/gen/mocks/createAddPetRequest.ts b/examples/advanced/src/gen/mocks/createAddPetRequest.ts index ae161e75b..743e53097 100644 --- a/examples/advanced/src/gen/mocks/createAddPetRequest.ts +++ b/examples/advanced/src/gen/mocks/createAddPetRequest.ts @@ -11,7 +11,7 @@ export function createAddPetRequest(override: NonNullable category: createCategory(), photoUrls: faker.helpers.arrayElements([faker.string.alpha()]) as any, tags: faker.helpers.arrayElements([createTagTag()]) as any, - status: faker.helpers.arrayElement(['available', 'pending', 'sold']), + status: faker.helpers.arrayElement(['working', 'idle']) as any, }, ...override, } diff --git a/examples/advanced/src/gen/mocks/createOrder.ts b/examples/advanced/src/gen/mocks/createOrder.ts index 17ecd1771..bca259a72 100644 --- a/examples/advanced/src/gen/mocks/createOrder.ts +++ b/examples/advanced/src/gen/mocks/createOrder.ts @@ -10,7 +10,7 @@ export function createOrder(override: NonNullable> = {}): NonNull orderType: faker.helpers.arrayElement(['foo', 'bar']), type: faker.string.alpha(), shipDate: faker.date.anytime(), - status: faker.helpers.arrayElement(['placed', 'approved', 'delivered']), + status: faker.helpers.arrayElement(['working', 'idle']) as any, http_status: faker.helpers.arrayElement(['ok', 'not_found']), complete: faker.datatype.boolean(), }, diff --git a/examples/advanced/src/gen/mocks/createPet.ts b/examples/advanced/src/gen/mocks/createPet.ts index e2e0be150..63c7f5177 100644 --- a/examples/advanced/src/gen/mocks/createPet.ts +++ b/examples/advanced/src/gen/mocks/createPet.ts @@ -11,7 +11,7 @@ export function createPet(override: NonNullable> = {}): NonNullable category: createCategory(), photoUrls: faker.helpers.arrayElements([faker.string.alpha()]) as any, tags: faker.helpers.arrayElements([createTagTag()]) as any, - status: faker.helpers.arrayElement(['available', 'pending', 'sold']), + status: faker.helpers.arrayElement(['working', 'idle']) as any, }, ...override, } diff --git a/examples/advanced/src/gen/mocks/petController/createFindPetsByStatus.ts b/examples/advanced/src/gen/mocks/petController/createFindPetsByStatus.ts index e189734b6..8ad924703 100644 --- a/examples/advanced/src/gen/mocks/petController/createFindPetsByStatus.ts +++ b/examples/advanced/src/gen/mocks/petController/createFindPetsByStatus.ts @@ -9,7 +9,7 @@ import { createPet } from '../createPet' export function createFindPetsByStatusQueryParams(override: NonNullable> = {}): NonNullable { return { - ...{ status: faker.helpers.arrayElement(['available', 'pending', 'sold']) }, + ...{ status: faker.helpers.arrayElement(['working', 'idle']) as any }, ...override, } } diff --git a/examples/advanced/src/gen/mocks/petController/createUpdatePetWithForm.ts b/examples/advanced/src/gen/mocks/petController/createUpdatePetWithForm.ts index 39d6eaa25..ad6680bce 100644 --- a/examples/advanced/src/gen/mocks/petController/createUpdatePetWithForm.ts +++ b/examples/advanced/src/gen/mocks/petController/createUpdatePetWithForm.ts @@ -17,7 +17,7 @@ export function createUpdatePetWithFormQueryParams( override: NonNullable> = {}, ): NonNullable { return { - ...{ name: faker.string.alpha(), status: faker.string.alpha() }, + ...{ name: faker.string.alpha(), status: faker.helpers.arrayElement(['working', 'idle']) as any }, ...override, } } diff --git a/examples/faker/kubb.config.cjs b/examples/faker/kubb.config.cjs index aedf4d310..f9dab11fd 100644 --- a/examples/faker/kubb.config.cjs +++ b/examples/faker/kubb.config.cjs @@ -49,9 +49,9 @@ module.exports = defineConfig(async () => { return undefined }, }, - // mapper: { - // productName: 'faker.commerce.productName', - // }, + mapper: { + message: 'faker.commerce.productName()', + }, include: [ { type: 'operationId', diff --git a/examples/faker/src/gen/customMocks/createApiResponse.ts b/examples/faker/src/gen/customMocks/createApiResponse.ts index 167130cda..7efaddaf4 100644 --- a/examples/faker/src/gen/customMocks/createApiResponse.ts +++ b/examples/faker/src/gen/customMocks/createApiResponse.ts @@ -3,7 +3,7 @@ import type { ApiResponse } from '../models/ApiResponse' export function createApiResponse(override: NonNullable> = {}): NonNullable { return { - ...{ code: faker.number.int(), type: faker.string.alpha(), message: faker.string.alpha() }, + ...{ code: faker.number.int(), type: faker.string.alpha(), message: faker.commerce.productName() }, ...override, } } diff --git a/examples/faker/src/gen/customMocks/createUser.ts b/examples/faker/src/gen/customMocks/createUser.ts index 1a322eb2a..1fa1ef523 100644 --- a/examples/faker/src/gen/customMocks/createUser.ts +++ b/examples/faker/src/gen/customMocks/createUser.ts @@ -12,7 +12,7 @@ export function createUser(override: NonNullable> = {}): NonNullab password: faker.string.alpha(), phone: faker.string.alpha(), userStatus: faker.number.int(), - nationalityCode: faker.helpers.arrayElement([faker.string.alpha(), faker.helpers.fromRegExp(/^[A-Z]{2}$/)]), + nationalityCode: faker.helpers.arrayElement([faker.string.alpha(), faker.helpers.fromRegExp(/^[A-Z]{2}$/)]), }, ...override, } diff --git a/package.json b/package.json index 3bac22b4c..d183af232 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "lint": "bun biome lint ./packages", "lint:case": "npx case-police --fix", "lint:ci": "bun biome lint ./packages", - "lint:fix": "bun biome lint --apply ./packages && bun run lint:case", + "lint:fix": "bun biome lint --apply-unsafe ./packages && bun run lint:case", "lint:turbo": "turbo run lint", "release": "changeset publish", "release:canary": "changeset publish --no-git-tag", diff --git a/packages/cli/package.json b/packages/cli/package.json index 113567723..d2edce2b9 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -2,13 +2,7 @@ "name": "@kubb/cli", "version": "2.12.0", "description": "Generator cli", - "keywords": [ - "typescript", - "plugins", - "kubb", - "codegen", - "cli" - ], + "keywords": ["typescript", "plugins", "kubb", "codegen", "cli"], "repository": { "type": "git", "url": "git://github.com/kubb-project/kubb.git", @@ -31,13 +25,7 @@ "bin": { "kubb": "bin/kubb.cjs" }, - "files": [ - "src", - "dist", - "bin", - "!/**/**.test.**", - "!/**/__tests__/**" - ], + "files": ["src", "dist", "bin", "!/**/**.test.**", "!/**/__tests__/**"], "scripts": { "build": "tsup", "clean": "npx rimraf ./dist", diff --git a/packages/core/mocks/hellowWorld.js b/packages/core/mocks/hellowWorld.js index 38424110f..9d79514e4 100644 --- a/packages/core/mocks/hellowWorld.js +++ b/packages/core/mocks/hellowWorld.js @@ -1 +1 @@ -export const hallo = 'world' \ No newline at end of file +export const hallo = 'world' diff --git a/packages/core/package.json b/packages/core/package.json index cc9b7e30f..3505fef16 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -2,12 +2,7 @@ "name": "@kubb/core", "version": "2.12.0", "description": "Generator core", - "keywords": [ - "typescript", - "plugins", - "kubb", - "codegen" - ], + "keywords": ["typescript", "plugins", "kubb", "codegen"], "repository": { "type": "git", "url": "git://github.com/kubb-project/kubb.git", @@ -59,32 +54,14 @@ "types": "./dist/index.d.ts", "typesVersions": { "*": { - "utils": [ - "./dist/utils.d.ts" - ], - "transformers": [ - "./dist/transformers.d.ts" - ], - "logger": [ - "./dist/logger.d.ts" - ], - "fs": [ - "./dist/fs.d.ts" - ], - "mocks": [ - "./dist/mocks.d.ts" - ] + "utils": ["./dist/utils.d.ts"], + "transformers": ["./dist/transformers.d.ts"], + "logger": ["./dist/logger.d.ts"], + "fs": ["./dist/fs.d.ts"], + "mocks": ["./dist/mocks.d.ts"] } }, - "files": [ - "src", - "dist", - "*.d.ts", - "*.d.cts", - "schema.json", - "!/**/**.test.**", - "!/**/__tests__/**" - ], + "files": ["src", "dist", "*.d.ts", "*.d.cts", "schema.json", "!/**/**.test.**", "!/**/__tests__/**"], "scripts": { "build": "tsup", "clean": "npx rimraf ./dist", diff --git a/packages/kubb/package.json b/packages/kubb/package.json index 45bd806f6..a569b03a9 100644 --- a/packages/kubb/package.json +++ b/packages/kubb/package.json @@ -2,13 +2,7 @@ "name": "kubb", "version": "2.0.0-beta.2", "description": "OpenAPI to TypeScript, React-Query, Zod, Zodios, Faker.js, MSW and Axios.", - "keywords": [ - "typescript", - "plugins", - "kubb", - "codegen", - "cli" - ], + "keywords": ["typescript", "plugins", "kubb", "codegen", "cli"], "repository": { "type": "git", "url": "git://github.com/kubb-project/kubb.git", @@ -24,13 +18,7 @@ "bin": { "kubb": "bin/kubb.js" }, - "files": [ - "src", - "dist", - "bin", - "!/**/**.test.**", - "!/**/__tests__/**" - ], + "files": ["src", "dist", "bin", "!/**/**.test.**", "!/**/__tests__/**"], "scripts": { "build": "tsup", "clean": "npx rimraf ./dist", diff --git a/packages/parser/package.json b/packages/parser/package.json index e03a27e53..09e6bd78e 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -2,12 +2,7 @@ "name": "@kubb/parser", "version": "2.12.0", "description": "Generator parser", - "keywords": [ - "typescript", - "plugins", - "kubb", - "codegen" - ], + "keywords": ["typescript", "plugins", "kubb", "codegen"], "repository": { "type": "git", "url": "git://github.com/kubb-project/kubb.git", @@ -36,17 +31,10 @@ "types": "./dist/index.d.cts", "typesVersions": { "*": { - "factory": [ - "./dist/factory.d.ts" - ] + "factory": ["./dist/factory.d.ts"] } }, - "files": [ - "src", - "dist", - "!/**/**.test.**", - "!/**/__tests__/**" - ], + "files": ["src", "dist", "!/**/**.test.**", "!/**/__tests__/**"], "scripts": { "build": "tsup", "clean": "npx rimraf ./dist", diff --git a/packages/react/package.json b/packages/react/package.json index f51a833a5..5687e0404 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -2,12 +2,7 @@ "name": "@kubb/react", "version": "2.12.0", "description": "Generator react", - "keywords": [ - "typescript", - "plugins", - "kubb", - "codegen" - ], + "keywords": ["typescript", "plugins", "kubb", "codegen"], "repository": { "type": "git", "url": "git://github.com/kubb-project/kubb.git", @@ -51,22 +46,11 @@ "types": "./dist/index.d.ts", "typesVersions": { "*": { - "client": [ - "./dist/client.d.ts" - ], - "server": [ - "./dist/server.d.ts" - ] + "client": ["./dist/client.d.ts"], + "server": ["./dist/server.d.ts"] } }, - "files": [ - "src", - "dist", - "*.d.ts", - "*.d.cts", - "!/**/**.test.**", - "!/**/__tests__/**" - ], + "files": ["src", "dist", "*.d.ts", "*.d.cts", "!/**/**.test.**", "!/**/__tests__/**"], "scripts": { "build": "tsup", "clean": "npx rimraf ./dist", diff --git a/packages/swagger-client/package.json b/packages/swagger-client/package.json index ae9aa44e9..d328eb5e6 100644 --- a/packages/swagger-client/package.json +++ b/packages/swagger-client/package.json @@ -2,15 +2,7 @@ "name": "@kubb/swagger-client", "version": "2.12.0", "description": "Generator swagger-client", - "keywords": [ - "typescript", - "plugins", - "kubb", - "codegen", - "swagger", - "openapi", - "axios" - ], + "keywords": ["typescript", "plugins", "kubb", "codegen", "swagger", "openapi", "axios"], "repository": { "type": "git", "url": "git://github.com/kubb-project/kubb.git", @@ -49,20 +41,10 @@ "types": "./dist/index.d.ts", "typesVersions": { "*": { - "components": [ - "./dist/components.d.ts" - ] + "components": ["./dist/components.d.ts"] } }, - "files": [ - "src", - "dist", - "client.ts", - "*.d.ts", - "*.d.cts", - "!/**/**.test.**", - "!/**/__tests__/**" - ], + "files": ["src", "dist", "client.ts", "*.d.ts", "*.d.cts", "!/**/**.test.**", "!/**/__tests__/**"], "scripts": { "build": "tsup", "clean": "npx rimraf ./dist", diff --git a/packages/swagger-faker/package.json b/packages/swagger-faker/package.json index a5cce3e9a..212ace6f1 100644 --- a/packages/swagger-faker/package.json +++ b/packages/swagger-faker/package.json @@ -2,17 +2,7 @@ "name": "@kubb/swagger-faker", "version": "2.12.0", "description": "Generator swagger-faker", - "keywords": [ - "faker", - "faker.js", - "mock", - "mocking", - "plugins", - "kubb", - "codegen", - "swagger", - "openapi" - ], + "keywords": ["faker", "faker.js", "mock", "mocking", "plugins", "kubb", "codegen", "swagger", "openapi"], "repository": { "type": "git", "url": "git://github.com/kubb-project/kubb.git", @@ -41,17 +31,10 @@ "types": "./dist/index.d.ts", "typesVersions": { "*": { - "components": [ - "./dist/components.d.ts" - ] + "components": ["./dist/components.d.ts"] } }, - "files": [ - "src", - "dist", - "!/**/**.test.**", - "!/**/__tests__/**" - ], + "files": ["src", "dist", "!/**/**.test.**", "!/**/__tests__/**"], "scripts": { "build": "tsup", "clean": "npx rimraf ./dist", diff --git a/packages/swagger-faker/src/OperationGenerator.test.tsx b/packages/swagger-faker/src/OperationGenerator.test.tsx index ad58410af..88bf60ea2 100644 --- a/packages/swagger-faker/src/OperationGenerator.test.tsx +++ b/packages/swagger-faker/src/OperationGenerator.test.tsx @@ -7,6 +7,7 @@ import { OperationGenerator } from './OperationGenerator.tsx' import type { KubbFile } from '@kubb/core' import type { Plugin } from '@kubb/core' import type { GetOperationGeneratorOptions } from '@kubb/swagger' +import { fakerKeywordMapper } from './fakerParser.tsx' import type { PluginOptions } from './types.ts' describe('OperationGenerator', async () => { @@ -21,6 +22,7 @@ describe('OperationGenerator', async () => { seed: undefined, transformers: {}, unknownType: 'any', + mapper: {}, } const og = await new OperationGenerator(options, { @@ -53,6 +55,7 @@ describe('OperationGenerator', async () => { seed: [222], transformers: {}, unknownType: 'any', + mapper: {}, } const og = await new OperationGenerator(options, { @@ -85,6 +88,7 @@ describe('OperationGenerator', async () => { seed: undefined, transformers: {}, unknownType: 'any', + mapper: {}, } const og = await new OperationGenerator(options, { @@ -110,6 +114,7 @@ describe('OperationGenerator', async () => { seed: undefined, transformers: {}, unknownType: 'any', + mapper: {}, } const og = await new OperationGenerator(options, { diff --git a/packages/swagger-faker/src/SchemaGenerator.test.tsx b/packages/swagger-faker/src/SchemaGenerator.test.tsx index 606c1a8d0..bc2fb1c0b 100644 --- a/packages/swagger-faker/src/SchemaGenerator.test.tsx +++ b/packages/swagger-faker/src/SchemaGenerator.test.tsx @@ -7,6 +7,7 @@ import { SchemaGenerator } from './SchemaGenerator.tsx' import type { Plugin } from '@kubb/core' import type { SchemaObject } from '@kubb/swagger/oas' +import { fakerKeywordMapper } from './fakerParser.tsx' import type { PluginOptions } from './types' describe('Faker SchemaGenerator enums', async () => { @@ -18,6 +19,7 @@ describe('Faker SchemaGenerator enums', async () => { seed: 1, transformers: {}, unknownType: 'any', + mapper: {}, }, { oas, diff --git a/packages/swagger-faker/src/SchemaGenerator.tsx b/packages/swagger-faker/src/SchemaGenerator.tsx index 44b8e666b..6e28856ea 100644 --- a/packages/swagger-faker/src/SchemaGenerator.tsx +++ b/packages/swagger-faker/src/SchemaGenerator.tsx @@ -1,14 +1,14 @@ -import { createRoot, File, useFile, usePluginManager } from '@kubb/react' +import { File, createRoot, useFile, usePluginManager } from '@kubb/react' import { SchemaGenerator as Generator } from '@kubb/swagger' +import { pluginKey as swaggerTypeScriptPluginKey } from '@kubb/swagger-ts' import { Oas, Schema } from '@kubb/swagger/components' import { useSchema } from '@kubb/swagger/hooks' -import { pluginKey as swaggerTypeScriptPluginKey } from '@kubb/swagger-ts' -import { fakerParser } from './fakerParser.tsx' +import { type fakerKeywordMapper, fakerParser } from './fakerParser.tsx' import { pluginKey } from './plugin.ts' import type { AppContextProps } from '@kubb/react' -import type { Schema as SchemaType, SchemaGeneratorBuildOptions, SchemaGeneratorOptions, SchemaMethodResult } from '@kubb/swagger' +import type { SchemaGeneratorBuildOptions, SchemaGeneratorOptions, SchemaMethodResult, Schema as SchemaType } from '@kubb/swagger' import type { SchemaObject } from '@kubb/swagger/oas' import type { FileMeta, PluginOptions } from './types.ts' @@ -82,6 +82,7 @@ export class SchemaGenerator extends Generator 'Object' 1`] = ` export function Object(override: NonNullable> = {}) { return { - ...{"firstName": faker.string.alpha(),"age": faker.number.float(),"address": Object.assign({},faker.string.alpha(),faker.number.float())}, + ...{"firstName": faker.string.alpha(),"age": faker.number.float(),"address": Object.assign({}, faker.string.alpha(), faker.number.float())}, ...override } } @@ -49,18 +49,20 @@ export function Upload(override?: NonNullable>) { " `; -exports[`parseFakerMeta > 'and' 1`] = `"Object.assign({},faker.string.alpha(),faker.number.float())"`; +exports[`parseFakerMeta > 'and' 1`] = `"Object.assign({}, faker.string.alpha(), faker.number.float())"`; exports[`parseFakerMeta > 'any' 1`] = `"undefined"`; -exports[`parseFakerMeta > 'array' 1`] = `"faker.helpers.arrayElements([faker.helpers.arrayElement([faker.number.float(),faker.string.alpha()]) as any]) as any"`; +exports[`parseFakerMeta > 'array' 1`] = `"faker.helpers.arrayElements([faker.helpers.arrayElement([faker.number.float(), faker.string.alpha()])]) as any"`; -exports[`parseFakerMeta > 'arrayAdvanced' 1`] = `"faker.helpers.arrayElements([faker.number.float()]) as any"`; +exports[`parseFakerMeta > 'arrayAdvanced' 1`] = `"faker.helpers.arrayElements([faker.number.float({ min: 1, max: 10 })]) as any"`; exports[`parseFakerMeta > 'arrayEmpty' 1`] = `"faker.helpers.arrayElements([]) as any"`; exports[`parseFakerMeta > 'arrayRef' 1`] = `"faker.helpers.arrayElements([Pet()]) as any"`; +exports[`parseFakerMeta > 'arrayRegex' 1`] = `"faker.helpers.arrayElements([faker.helpers.fromRegExp(new RegExp('^[a-zA-Z0-9]{1,13}$')), faker.string.alpha()]) as any"`; + exports[`parseFakerMeta > 'blob' 1`] = `undefined`; exports[`parseFakerMeta > 'boolean' 1`] = `"faker.datatype.boolean()"`; @@ -91,7 +93,9 @@ exports[`parseFakerMeta > 'number' 1`] = `"faker.number.float()"`; exports[`parseFakerMeta > 'object' 1`] = `"{"firstName": faker.string.alpha(),"address": faker.string.alpha()}"`; -exports[`parseFakerMeta > 'objectAnd' 1`] = `"{"firstName": faker.string.alpha(),"age": faker.number.float(),"address": Object.assign({},faker.string.alpha(),faker.number.float())}"`; +exports[`parseFakerMeta > 'objectAnd' 1`] = `"{"firstName": faker.string.alpha(),"age": faker.number.float(),"address": Object.assign({}, faker.string.alpha(), faker.number.float())}"`; + +exports[`parseFakerMeta > 'objectArray' 1`] = `"{"ids": faker.helpers.arrayElements([faker.helpers.fromRegExp(new RegExp('^[a-zA-Z0-9]{1,13}$')), faker.string.alpha()]) as any}"`; exports[`parseFakerMeta > 'objectEmpty' 1`] = `"{}"`; @@ -103,12 +107,12 @@ exports[`parseFakerMeta > 'string' 1`] = `"faker.string.alpha()"`; exports[`parseFakerMeta > 'tuple' 1`] = `"faker.helpers.arrayElements([]) as any"`; -exports[`parseFakerMeta > 'tupleMulti' 1`] = `"faker.helpers.arrayElements([faker.string.alpha(),faker.number.float()]) as any"`; +exports[`parseFakerMeta > 'tupleMulti' 1`] = `"faker.helpers.arrayElements([faker.string.alpha(), faker.number.float()]) as any"`; exports[`parseFakerMeta > 'undefined' 1`] = `"undefined"`; -exports[`parseFakerMeta > 'union' 1`] = `"faker.helpers.arrayElement([faker.string.alpha(),faker.number.float()]) as any"`; +exports[`parseFakerMeta > 'union' 1`] = `"faker.helpers.arrayElement([faker.string.alpha(), faker.number.float()])"`; -exports[`parseFakerMeta > 'unionOne' 1`] = `"faker.helpers.arrayElement([faker.string.alpha()]) as any"`; +exports[`parseFakerMeta > 'unionOne' 1`] = `"faker.helpers.arrayElement([faker.string.alpha()])"`; -exports[`parseFakerMeta > 'unknown' 1`] = `"unknown()"`; +exports[`parseFakerMeta > 'unknown' 1`] = `"unknown"`; diff --git a/packages/swagger-faker/src/components/OperationSchema.test.tsx b/packages/swagger-faker/src/components/OperationSchema.test.tsx index 90531c99c..8834e513a 100644 --- a/packages/swagger-faker/src/components/OperationSchema.test.tsx +++ b/packages/swagger-faker/src/components/OperationSchema.test.tsx @@ -10,6 +10,7 @@ import { OperationSchema } from './OperationSchema.tsx' import type { Plugin, ResolveNameParams } from '@kubb/core' import type { AppContextProps } from '@kubb/react' import type { GetOperationGeneratorOptions } from '@kubb/swagger' +import { fakerKeywordMapper } from '../fakerParser.tsx' import type { PluginOptions } from '../types.ts' describe('', async () => { @@ -34,6 +35,7 @@ describe('', async () => { seed: undefined, transformers: {}, unknownType: 'any', + mapper: {}, } const plugin = { options } as Plugin diff --git a/packages/swagger-faker/src/components/Schema.test.tsx b/packages/swagger-faker/src/components/Schema.test.tsx index e40d8b1c1..b771a2267 100644 --- a/packages/swagger-faker/src/components/Schema.test.tsx +++ b/packages/swagger-faker/src/components/Schema.test.tsx @@ -10,6 +10,7 @@ import { OperationSchema } from './OperationSchema.tsx' import type { Plugin, ResolveNameParams } from '@kubb/core' import type { AppContextProps } from '@kubb/react' import type { GetOperationGeneratorOptions } from '@kubb/swagger' +import { fakerKeywordMapper } from '../fakerParser.tsx' import type { PluginOptions } from '../types.ts' describe('', async () => { @@ -34,6 +35,7 @@ describe('', async () => { seed: undefined, transformers: {}, unknownType: 'any', + mapper: {}, } const plugin = { options } as Plugin diff --git a/packages/swagger-faker/src/fakerParser.test.ts b/packages/swagger-faker/src/fakerParser.test.ts index fc156e0b2..99e213c9a 100644 --- a/packages/swagger-faker/src/fakerParser.test.ts +++ b/packages/swagger-faker/src/fakerParser.test.ts @@ -4,7 +4,7 @@ import { fakerParser, parseFakerMeta } from './fakerParser.tsx' describe('parseFakerMeta', () => { test.each(schemas.basic)('$name', ({ name, schema }) => { - const text = parseFakerMeta(schema, { name }) + const text = parseFakerMeta(undefined, schema, { name }) expect(text).toMatchSnapshot() }) }) diff --git a/packages/swagger-faker/src/fakerParser.tsx b/packages/swagger-faker/src/fakerParser.tsx index b2341c851..fa48e6a6b 100644 --- a/packages/swagger-faker/src/fakerParser.tsx +++ b/packages/swagger-faker/src/fakerParser.tsx @@ -1,39 +1,80 @@ import transformers, { createJSDocBlockText } from '@kubb/core/transformers' -import { isKeyword, schemaKeywords } from '@kubb/swagger' +import { SchemaGenerator, isKeyword, schemaKeywords } from '@kubb/swagger' import type { Schema, SchemaKeywordBase, SchemaMapper } from '@kubb/swagger' export const fakerKeywordMapper = { - any: 'undefined', - unknown: 'unknown', - number: 'faker.number.float', - integer: 'faker.number.int', - string: 'faker.string.alpha', - boolean: 'faker.datatype.boolean', - undefined: 'undefined', - null: 'null', - array: 'faker.helpers.arrayElements', - tuple: 'faker.helpers.arrayElements', - enum: 'faker.helpers.arrayElement', - union: 'faker.helpers.arrayElement', - date: 'faker.date.anytime', - datetime: 'faker.date.anytime().toISOString', - uuid: 'faker.string.uuid', - url: 'faker.internet.url', - and: 'Object.assign', - object: 'object', - ref: 'ref', - matches: 'faker.helpers.fromRegExp', - email: 'faker.internet.email', - firstName: 'faker.person.firstName', - lastName: 'faker.person.lastName', - password: 'faker.internet.password', - phone: 'faker.phone.number', + any: () => 'undefined', + unknown: () => 'unknown', + number: (min?: number, max?: number) => { + if (max !== undefined && min !== undefined) { + return `faker.number.float({ min: ${min}, max: ${max} })` + } + + if (min !== undefined) { + return `faker.number.float({ min: ${min} })` + } + + if (max !== undefined) { + return `faker.number.float({ max: ${max} })` + } + + return 'faker.number.float()' + }, + integer: (min?: number, max?: number) => { + if (max !== undefined && min !== undefined) { + return `faker.number.int({ min: ${min}, max: ${max} })` + } + + if (min !== undefined) { + return `faker.number.int({ min: ${min} })` + } + + if (max !== undefined) { + return `faker.number.int({ max: ${max} })` + } + + return 'faker.number.int()' + }, + string: (min?: number, max?: number) => { + if (max !== undefined && min !== undefined) { + return `faker.string.alpha({ length: { min: ${min}, max: ${max} } })` + } + + if (min !== undefined) { + return `faker.string.alpha({ length: { min: ${min} } })` + } + + if (max !== undefined) { + return `faker.string.alpha({ length: { max: ${max} } })` + } + + return 'faker.string.alpha()' + }, + boolean: () => 'faker.datatype.boolean()', + undefined: () => 'undefined', + null: () => 'null', + array: (items: string[] = []) => `faker.helpers.arrayElements([${items.join(', ')}]) as any`, + tuple: (items: string[] = []) => `faker.helpers.arrayElements([${items.join(', ')}]) as any`, + enum: (items: Array = []) => `faker.helpers.arrayElement([${items.join(', ')}])`, + union: (items: string[] = []) => `faker.helpers.arrayElement([${items.join(', ')}])`, + date: () => 'faker.date.anytime()', + datetime: () => 'faker.date.anytime().toISOString()', + uuid: () => 'faker.string.uuid()', + url: () => 'faker.internet.url()', + and: (items: string[] = []) => `Object.assign({}, ${items.join(', ')})`, + object: () => 'object', + ref: () => 'ref', + matches: (value = '') => `faker.helpers.fromRegExp(${value})`, + email: () => 'faker.internet.email()', + firstName: () => 'faker.person.firstName()', + lastName: () => 'faker.person.lastName()', + password: () => 'faker.internet.password()', + phone: () => 'faker.phone.number()', blob: undefined, default: undefined, describe: undefined, - lazy: undefined, - const: undefined, + const: (value?: string | number) => (value as string) ?? '', max: undefined, min: undefined, nullable: undefined, @@ -46,7 +87,7 @@ export const fakerKeywordMapper = { type: undefined, format: undefined, catchall: undefined, -} satisfies SchemaMapper +} satisfies SchemaMapper /** * @link based on https://github.com/cellular/oazapfts/blob/7ba226ebb15374e8483cc53e7532f1663179a22c/src/codegen/generate.ts#L398 @@ -67,7 +108,7 @@ function joinItems(items: string[]): string { case 1: return items[0]! default: - return `${fakerKeywordMapper.union}([${items.join(',')}])` + return fakerKeywordMapper.union(items) } } @@ -78,75 +119,70 @@ type ParserOptions = { seed?: number | number[] withOverride?: boolean - mapper?: typeof fakerKeywordMapper + mapper?: Record } -export function parseFakerMeta(item: Schema, options: ParserOptions): string | undefined { - const mapper = options.mapper || fakerKeywordMapper - const value = mapper[item.keyword as keyof typeof mapper] +export function parseFakerMeta(parent: Schema | undefined, current: Schema, options: ParserOptions): string | null | undefined { + const value = fakerKeywordMapper[current.keyword as keyof typeof fakerKeywordMapper] if (!value) { return undefined } - if (isKeyword(item, schemaKeywords.union)) { - return `${value}([${item.args - .map((orItem) => parseFakerMeta(orItem, { ...options, withOverride: false })) - .filter(Boolean) - .join(',')}]) as any` + if (isKeyword(current, schemaKeywords.union)) { + return fakerKeywordMapper.union(current.args.map((schema) => parseFakerMeta(current, schema, { ...options, withOverride: false })).filter(Boolean)) } - if (isKeyword(item, schemaKeywords.and)) { - return `${value}({},${item.args - .map((andItem) => parseFakerMeta(andItem, { ...options, withOverride: false })) - .filter(Boolean) - .join(',')})` + if (isKeyword(current, schemaKeywords.and)) { + return fakerKeywordMapper.and(current.args.map((schema) => parseFakerMeta(current, schema, { ...options, withOverride: false })).filter(Boolean)) } - if (isKeyword(item, schemaKeywords.array)) { - return `${value}([${item.args.items - .map((orItem) => parseFakerMeta(orItem, { ...options, withOverride: false })) - .filter(Boolean) - .join(',')}]) as any` + if (isKeyword(current, schemaKeywords.array)) { + return fakerKeywordMapper.array(current.args.items.map((schema) => parseFakerMeta(current, schema, { ...options, withOverride: false })).filter(Boolean)) } - if (isKeyword(item, schemaKeywords.enum)) { - return `${value}([${item.args.items - .map((item) => { - if (item.format === 'number') { - return item.name + if (isKeyword(current, schemaKeywords.enum)) { + return fakerKeywordMapper.enum( + current.args.items.map((schema) => { + if (schema.format === 'number') { + return schema.name } - return transformers.stringify(item.name) - }) - .join(', ')}])` + return transformers.stringify(schema.name) + }), + ) } - if (isKeyword(item, schemaKeywords.ref)) { - if (!item.args?.name) { - throw new Error(`Name not defined for keyword ${item.keyword}`) + if (isKeyword(current, schemaKeywords.ref)) { + if (!current.args?.name) { + throw new Error(`Name not defined for keyword ${current.keyword}`) } if (options.withOverride) { - return `${item.args.name}(override)` + return `${current.args.name}(override)` } - return `${item.args.name}()` + return `${current.args.name}()` } - if (isKeyword(item, schemaKeywords.object)) { - const argsObject = Object.entries(item.args?.properties || {}) + if (isKeyword(current, schemaKeywords.object)) { + const argsObject = Object.entries(current.args?.properties || {}) .filter((item) => { const schema = item[1] return schema && typeof schema.map === 'function' }) .map((item) => { const name = item[0] - const schema = item[1] + const schemas = item[1] + + // custom mapper(pluginOptions) + if (options.mapper?.[name]) { + return `"${name}": ${options.mapper?.[name]}` + } return `"${name}": ${joinItems( - schema + schemas .sort(schemaKeywordsorter) - .map((item) => parseFakerMeta(item, { ...options, withOverride: false })) + .map((schema) => parseFakerMeta(current, schema, { ...options, withOverride: false })) .filter(Boolean), )}` }) @@ -155,44 +191,81 @@ export function parseFakerMeta(item: Schema, options: ParserOptions): string | u return `{${argsObject}}` } - if (isKeyword(item, schemaKeywords.tuple)) { - return `${value}(${ - Array.isArray(item.args) - ? `[${item.args - .map((orItem) => parseFakerMeta(orItem, { ...options, withOverride: false })) - .filter(Boolean) - .join(',')}]` - : parseFakerMeta(item.args, { ...options, withOverride: false }) - }) as any` + if (isKeyword(current, schemaKeywords.tuple)) { + if (Array.isArray(current.args)) { + return fakerKeywordMapper.tuple(current.args.map((schema) => parseFakerMeta(current, schema, { ...options, withOverride: false })).filter(Boolean)) + } + + return parseFakerMeta(current, current.args, { ...options, withOverride: false }) + } + + if (isKeyword(current, schemaKeywords.const)) { + if (current.args.format === 'number' && current.args.name !== undefined) { + return fakerKeywordMapper.const(current.args.name?.toString()) + } + return fakerKeywordMapper.const(transformers.stringify(current.args.value)) + } + + if (isKeyword(current, schemaKeywords.matches)) { + if (current.args) { + return fakerKeywordMapper.matches(transformers.toRegExpString(current.args)) + } + } + + if (isKeyword(current, schemaKeywords.null) || isKeyword(current, schemaKeywords.undefined) || isKeyword(current, schemaKeywords.any)) { + return value() || '' } - if (isKeyword(item, schemaKeywords.const)) { - if (item.args.format === 'number') { - return item.args.name?.toString() + if (isKeyword(current, schemaKeywords.string)) { + if (parent) { + const minSchema = SchemaGenerator.find([parent], schemaKeywords.min) + const maxSchema = SchemaGenerator.find([parent], schemaKeywords.max) + + return fakerKeywordMapper.string(minSchema?.args, maxSchema?.args) } - return transformers.stringify(item.args.value) + + return fakerKeywordMapper.string() } - if (isKeyword(item, schemaKeywords.matches)) { - if (item.args) { - return `${value}(${transformers.toRegExpString(item.args)})` + if (isKeyword(current, schemaKeywords.number)) { + if (parent) { + const minSchema = SchemaGenerator.find([parent], schemaKeywords.min) + const maxSchema = SchemaGenerator.find([parent], schemaKeywords.max) + + return fakerKeywordMapper.number(minSchema?.args, maxSchema?.args) } + + return fakerKeywordMapper.number() } - if (isKeyword(item, schemaKeywords.null) || isKeyword(item, schemaKeywords.undefined) || isKeyword(item, schemaKeywords.any)) { - return value || '' + if (isKeyword(current, schemaKeywords.integer)) { + if (parent) { + const minSchema = SchemaGenerator.find([parent], schemaKeywords.min) + const maxSchema = SchemaGenerator.find([parent], schemaKeywords.max) + + return fakerKeywordMapper.integer(minSchema?.args, maxSchema?.args) + } + + return fakerKeywordMapper.integer() + } + + if (current.keyword in fakerKeywordMapper && 'args' in current) { + const value = fakerKeywordMapper[current.keyword as keyof typeof fakerKeywordMapper] as (typeof fakerKeywordMapper)['const'] + + const options = JSON.stringify((current as SchemaKeywordBase).args) + + return value(options) } - if (item.keyword in mapper) { - const options = JSON.stringify((item as SchemaKeywordBase).args) - return `${value}(${options ?? ''})` + if (current.keyword in fakerKeywordMapper) { + return value() } return undefined } export function fakerParser(schemas: Schema[], options: ParserOptions): string { - const fakerText = joinItems(schemas.map((item) => parseFakerMeta(item, { ...options, withOverride: true })).filter(Boolean)) + const fakerText = joinItems(schemas.map((schema) => parseFakerMeta(undefined, schema, { ...options, withOverride: true })).filter(Boolean)) let fakerDefaultOverride: '' | '[]' | '{}' = '' let fakerTextWithOverride = fakerText @@ -205,7 +278,7 @@ export function fakerParser(schemas: Schema[], options: ParserOptions): string { }` } - if (fakerText.startsWith(fakerKeywordMapper.array)) { + if (fakerText.startsWith('faker.helpers.arrayElements')) { fakerDefaultOverride = '[]' fakerTextWithOverride = `[ ...${fakerText}, diff --git a/packages/swagger-faker/src/plugin.ts b/packages/swagger-faker/src/plugin.ts index 4cc2709e3..da0eeddef 100644 --- a/packages/swagger-faker/src/plugin.ts +++ b/packages/swagger-faker/src/plugin.ts @@ -1,11 +1,12 @@ import path from 'node:path' +import { fakerKeywordMapper } from './fakerParser' -import { createPlugin, FileManager, PluginManager } from '@kubb/core' +import { FileManager, PluginManager, createPlugin } from '@kubb/core' import { camelCase } from '@kubb/core/transformers' import { renderTemplate } from '@kubb/core/utils' import { pluginName as swaggerPluginName } from '@kubb/swagger' -import { getGroupedByTagFiles } from '@kubb/swagger/utils' import { pluginName as swaggerTypeScriptPluginName } from '@kubb/swagger-ts' +import { getGroupedByTagFiles } from '@kubb/swagger/utils' import { OperationGenerator } from './OperationGenerator.tsx' import { SchemaGenerator } from './SchemaGenerator.tsx' @@ -18,7 +19,18 @@ export const pluginName = 'swagger-faker' satisfies PluginOptions['name'] export const pluginKey: PluginOptions['key'] = [pluginName] satisfies PluginOptions['key'] export const definePlugin = createPlugin((options) => { - const { output = { path: 'mocks' }, seed, group, exclude = [], include, override = [], transformers = {}, dateType = 'string', unknownType = 'any' } = options + const { + output = { path: 'mocks' }, + seed, + group, + exclude = [], + include, + override = [], + transformers = {}, + mapper = {}, + dateType = 'string', + unknownType = 'any', + } = options const template = group?.output ? group.output : `${output.path}/{{tag}}Controller` return { @@ -28,6 +40,7 @@ export const definePlugin = createPlugin((options) => { dateType, seed, unknownType, + mapper, }, pre: [swaggerPluginName, swaggerTypeScriptPluginName], resolvePath(baseName, pathMode, options) { diff --git a/packages/swagger-faker/src/types.ts b/packages/swagger-faker/src/types.ts index 1facf7930..7fc7bb9ae 100644 --- a/packages/swagger-faker/src/types.ts +++ b/packages/swagger-faker/src/types.ts @@ -1,6 +1,7 @@ import type { KubbFile, Plugin, PluginFactoryOptions, ResolveNameParams } from '@kubb/core' -import type { Exclude, Include, Override, ResolvePathOptions, Schema } from '@kubb/swagger' +import type { Exclude, Include, Override, ResolvePathOptions, Schema, SchemaMapper } from '@kubb/swagger' import type { OasTypes } from '@kubb/swagger/oas' +import type { fakerKeywordMapper } from './fakerParser' export type Options = { output?: { @@ -58,7 +59,7 @@ export type Options = { /** * Array containing override parameters to override `options` based on tags/operations/methods/paths. */ - override?: Array> + override?: Array> /** * Choose to use `date` or `datetime` as JavaScript `Date` instead of `string`. * @default 'string' @@ -81,6 +82,7 @@ export type Options = { */ schema?: (schema: OasTypes.SchemaObject | undefined, baseName?: string) => Schema[] | undefined } + mapper?: Record /** * The use of Seed is intended to allow for consistent values in a test. */ @@ -92,6 +94,7 @@ type ResolvedOptions = { unknownType: NonNullable transformers: NonNullable seed: NonNullable | undefined + mapper: Record } export type FileMeta = { diff --git a/packages/swagger-msw/package.json b/packages/swagger-msw/package.json index 56780403b..f534b4250 100644 --- a/packages/swagger-msw/package.json +++ b/packages/swagger-msw/package.json @@ -2,18 +2,7 @@ "name": "@kubb/swagger-msw", "version": "2.12.0", "description": "Generator swagger-msw", - "keywords": [ - "faker", - "faker.js", - "msw", - "mock", - "mocking", - "plugins", - "kubb", - "codegen", - "swagger", - "openapi" - ], + "keywords": ["faker", "faker.js", "msw", "mock", "mocking", "plugins", "kubb", "codegen", "swagger", "openapi"], "repository": { "type": "git", "url": "git://github.com/kubb-project/kubb.git", @@ -42,17 +31,10 @@ "types": "./dist/index.d.ts", "typesVersions": { "*": { - "components": [ - "./dist/components.d.ts" - ] + "components": ["./dist/components.d.ts"] } }, - "files": [ - "src", - "dist", - "!/**/**.test.**", - "!/**/__tests__/**" - ], + "files": ["src", "dist", "!/**/**.test.**", "!/**/__tests__/**"], "scripts": { "build": "tsup", "clean": "npx rimraf ./dist", diff --git a/packages/swagger-swr/package.json b/packages/swagger-swr/package.json index a1ae22ba1..b3d74dd05 100644 --- a/packages/swagger-swr/package.json +++ b/packages/swagger-swr/package.json @@ -2,19 +2,7 @@ "name": "@kubb/swagger-swr", "version": "2.12.0", "description": "Generator swagger-swr", - "keywords": [ - "typescript", - "plugins", - "kubb", - "codegen", - "swagger", - "openapi", - "swr", - "vercel", - "nextjs", - "next", - "axios" - ], + "keywords": ["typescript", "plugins", "kubb", "codegen", "swagger", "openapi", "swr", "vercel", "nextjs", "next", "axios"], "repository": { "type": "git", "url": "git://github.com/kubb-project/kubb.git", @@ -43,17 +31,10 @@ "types": "./dist/index.d.ts", "typesVersions": { "*": { - "components": [ - "./dist/components.d.ts" - ] + "components": ["./dist/components.d.ts"] } }, - "files": [ - "src", - "dist", - "!/**/**.test.**", - "!/**/__tests__/**" - ], + "files": ["src", "dist", "!/**/**.test.**", "!/**/__tests__/**"], "scripts": { "build": "tsup", "clean": "rimraf ./dist", diff --git a/packages/swagger-tanstack-query/package.json b/packages/swagger-tanstack-query/package.json index 93c91651b..65e715aa2 100644 --- a/packages/swagger-tanstack-query/package.json +++ b/packages/swagger-tanstack-query/package.json @@ -2,18 +2,7 @@ "name": "@kubb/swagger-tanstack-query", "version": "2.12.0", "description": "Generator swagger-tanstack-query", - "keywords": [ - "typescript", - "plugins", - "kubb", - "codegen", - "swagger", - "openapi", - "tanstack", - "react-query", - "@tanstack", - "axios" - ], + "keywords": ["typescript", "plugins", "kubb", "codegen", "swagger", "openapi", "tanstack", "react-query", "@tanstack", "axios"], "repository": { "type": "git", "url": "git://github.com/kubb-project/kubb.git", @@ -42,17 +31,10 @@ "types": "./dist/index.d.ts", "typesVersions": { "*": { - "components": [ - "./dist/components.d.ts" - ] + "components": ["./dist/components.d.ts"] } }, - "files": [ - "src", - "dist", - "!/**/**.test.**", - "!/**/__tests__/**" - ], + "files": ["src", "dist", "!/**/**.test.**", "!/**/__tests__/**"], "scripts": { "build": "tsup", "clean": "npx rimraf ./dist", diff --git a/packages/swagger-ts/package.json b/packages/swagger-ts/package.json index 3df36963b..667343316 100644 --- a/packages/swagger-ts/package.json +++ b/packages/swagger-ts/package.json @@ -2,14 +2,7 @@ "name": "@kubb/swagger-ts", "version": "2.12.0", "description": "Generator swagger-ts", - "keywords": [ - "typescript", - "plugins", - "kubb", - "codegen", - "swagger", - "openapi" - ], + "keywords": ["typescript", "plugins", "kubb", "codegen", "swagger", "openapi"], "repository": { "type": "git", "url": "git://github.com/kubb-project/kubb.git", @@ -41,20 +34,11 @@ "types": "./dist/index.d.ts", "typesVersions": { "*": { - "components": [ - "./dist/components.d.ts" - ], - "oas": [ - "./dist/oas.d.ts" - ] + "components": ["./dist/components.d.ts"], + "oas": ["./dist/oas.d.ts"] } }, - "files": [ - "src", - "dist", - "!/**/**.test.**", - "!/**/__tests__/**" - ], + "files": ["src", "dist", "!/**/**.test.**", "!/**/__tests__/**"], "scripts": { "build": "tsup", "clean": "npx rimraf ./dist", diff --git a/packages/swagger-ts/src/__snapshots__/typeParser.test.ts.snap b/packages/swagger-ts/src/__snapshots__/typeParser.test.ts.snap index dcf34b1f6..919ca9fbe 100644 --- a/packages/swagger-ts/src/__snapshots__/typeParser.test.ts.snap +++ b/packages/swagger-ts/src/__snapshots__/typeParser.test.ts.snap @@ -31,6 +31,11 @@ exports[`parseTypeMeta > 'arrayRef' 1`] = ` " `; +exports[`parseTypeMeta > 'arrayRegex' 1`] = ` +"string[] +" +`; + exports[`parseTypeMeta > 'blob' 1`] = ` "Blob " @@ -113,6 +118,13 @@ exports[`parseTypeMeta > 'objectAnd' 1`] = ` " `; +exports[`parseTypeMeta > 'objectArray' 1`] = ` +"{ + ids: string[]; +} +" +`; + exports[`parseTypeMeta > 'objectEmpty' 1`] = ` "{} " diff --git a/packages/swagger-ts/src/typeParser.test.ts b/packages/swagger-ts/src/typeParser.test.ts index 11d15d409..2fa58c399 100644 --- a/packages/swagger-ts/src/typeParser.test.ts +++ b/packages/swagger-ts/src/typeParser.test.ts @@ -5,7 +5,7 @@ import { parseTypeMeta, typeParser } from './typeParser.ts' describe('parseTypeMeta', () => { test.each(schemas.basic)('$name', ({ schema, name }) => { - const parsed = parseTypeMeta(schema, { + const parsed = parseTypeMeta(undefined, schema, { name, optionalType: 'questionToken', enumType: 'asConst', diff --git a/packages/swagger-ts/src/typeParser.ts b/packages/swagger-ts/src/typeParser.ts index 29c4e9b2f..930d34923 100644 --- a/packages/swagger-ts/src/typeParser.ts +++ b/packages/swagger-ts/src/typeParser.ts @@ -1,7 +1,7 @@ import transformers from '@kubb/core/transformers' import { print } from '@kubb/parser' import * as factory from '@kubb/parser/factory' -import { isKeyword, SchemaGenerator, schemaKeywords } from '@kubb/swagger' +import { SchemaGenerator, isKeyword, schemaKeywords } from '@kubb/swagger' import type { ts } from '@kubb/parser' import type { Schema, SchemaKeywordMapper, SchemaMapper } from '@kubb/swagger' @@ -18,7 +18,6 @@ export const typeKeywordMapper = { return factory.createTypeLiteralNode(nodes) }, - lazy: undefined, string: () => factory.keywordTypeNodes.string, boolean: () => factory.keywordTypeNodes.boolean, undefined: () => factory.keywordTypeNodes.undefined, @@ -107,7 +106,7 @@ export const typeKeywordMapper = { type: undefined, format: undefined, catchall: undefined, -} satisfies SchemaMapper<(ctx?: any) => ts.Node | null | undefined> +} satisfies SchemaMapper type ParserOptions = { name: string @@ -122,61 +121,50 @@ type ParserOptions = { */ enumType: 'enum' | 'asConst' | 'asPascalConst' | 'constEnum' | 'literal' keysToOmit?: string[] - mapper?: typeof typeKeywordMapper + mapper?: SchemaMapper } -export function parseTypeMeta(item: Schema, options: ParserOptions): ts.Node | null | undefined { - const mapper = options.mapper || typeKeywordMapper - const value = mapper[item.keyword as keyof typeof mapper] +export function parseTypeMeta(parent: Schema | undefined, current: Schema, options: ParserOptions): ts.Node | null | undefined { + const value = typeKeywordMapper[current.keyword as keyof typeof typeKeywordMapper] if (!value) { return undefined } - if (isKeyword(item, schemaKeywords.union)) { - const value = mapper[item.keyword as keyof typeof mapper] as (typeof typeKeywordMapper)['union'] - return value(item.args.map((orItem) => parseTypeMeta(orItem, options)).filter(Boolean) as ts.TypeNode[]) + if (isKeyword(current, schemaKeywords.union)) { + return typeKeywordMapper.union(current.args.map((schema) => parseTypeMeta(current, schema, options)).filter(Boolean) as ts.TypeNode[]) } - if (isKeyword(item, schemaKeywords.and)) { - const value = mapper[item.keyword as keyof typeof mapper] as (typeof typeKeywordMapper)['and'] - return value(item.args.map((orItem) => parseTypeMeta(orItem, options)).filter(Boolean) as ts.TypeNode[]) + if (isKeyword(current, schemaKeywords.and)) { + return typeKeywordMapper.and(current.args.map((schema) => parseTypeMeta(current, schema, options)).filter(Boolean) as ts.TypeNode[]) } - if (isKeyword(item, schemaKeywords.array)) { - const value = mapper[item.keyword as keyof typeof mapper] as (typeof typeKeywordMapper)['array'] - return value(item.args.items.map((orItem) => parseTypeMeta(orItem, options)).filter(Boolean) as ts.TypeNode[]) + if (isKeyword(current, schemaKeywords.array)) { + return typeKeywordMapper.array(current.args.items.map((schema) => parseTypeMeta(current, schema, options)).filter(Boolean) as ts.TypeNode[]) } - if (isKeyword(item, schemaKeywords.enum)) { - const value = mapper[item.keyword as keyof typeof mapper] as (typeof typeKeywordMapper)['enum'] - return value(item.args.typeName) + if (isKeyword(current, schemaKeywords.enum)) { + return typeKeywordMapper.enum(current.args.typeName) } - if (isKeyword(item, schemaKeywords.ref)) { - const value = mapper[item.keyword as keyof typeof mapper] as (typeof typeKeywordMapper)['ref'] - return value(item.args.name) + if (isKeyword(current, schemaKeywords.ref)) { + return typeKeywordMapper.ref(current.args.name) } - if (isKeyword(item, schemaKeywords.blob)) { + if (isKeyword(current, schemaKeywords.blob)) { return value() } - if (isKeyword(item, schemaKeywords.tuple)) { - const value = mapper[item.keyword as keyof typeof mapper] as (typeof typeKeywordMapper)['tuple'] - return value(item.args.map((tupleItem) => parseTypeMeta(tupleItem, options)).filter(Boolean) as ts.TypeNode[]) + if (isKeyword(current, schemaKeywords.tuple)) { + return typeKeywordMapper.tuple(current.args.map((schema) => parseTypeMeta(current, schema, options)).filter(Boolean) as ts.TypeNode[]) } - if (isKeyword(item, schemaKeywords.const)) { - const value = mapper[item.keyword as keyof typeof mapper] as (typeof typeKeywordMapper)['const'] - - return value(item.args.name, item.args.format) + if (isKeyword(current, schemaKeywords.const)) { + return typeKeywordMapper.const(current.args.name, current.args.format) } - if (isKeyword(item, schemaKeywords.object)) { - const value = mapper[item.keyword as keyof typeof mapper] as (typeof typeKeywordMapper)['object'] - - const properties = Object.entries(item.args?.properties || {}) + if (isKeyword(current, schemaKeywords.object)) { + const properties = Object.entries(current.args?.properties || {}) .filter((item) => { const schemas = item[1] return schemas && typeof schemas.map === 'function' @@ -185,18 +173,18 @@ export function parseTypeMeta(item: Schema, options: ParserOptions): ts.Node | n const name = item[0] const schemas = item[1] - const isNullish = schemas.some((item) => item.keyword === schemaKeywords.nullish) - const isNullable = schemas.some((item) => item.keyword === schemaKeywords.nullable) - const isOptional = schemas.some((item) => item.keyword === schemaKeywords.optional) - const isReadonly = schemas.some((item) => item.keyword === schemaKeywords.readOnly) - const describeSchema = schemas.find((item) => item.keyword === schemaKeywords.describe) as SchemaKeywordMapper['describe'] | undefined - const deprecatedSchema = schemas.find((item) => item.keyword === schemaKeywords.deprecated) as SchemaKeywordMapper['deprecated'] | undefined - const defaultSchema = schemas.find((item) => item.keyword === schemaKeywords.default) as SchemaKeywordMapper['default'] | undefined - const exampleSchema = schemas.find((item) => item.keyword === schemaKeywords.example) as SchemaKeywordMapper['example'] | undefined - const typeSchema = schemas.find((item) => item.keyword === schemaKeywords.type) as SchemaKeywordMapper['type'] | undefined - const formatSchema = schemas.find((item) => item.keyword === schemaKeywords.format) as SchemaKeywordMapper['format'] | undefined + const isNullish = schemas.some((schema) => schema.keyword === schemaKeywords.nullish) + const isNullable = schemas.some((schema) => schema.keyword === schemaKeywords.nullable) + const isOptional = schemas.some((schema) => schema.keyword === schemaKeywords.optional) + const isReadonly = schemas.some((schema) => schema.keyword === schemaKeywords.readOnly) + const describeSchema = schemas.find((schema) => schema.keyword === schemaKeywords.describe) as SchemaKeywordMapper['describe'] | undefined + const deprecatedSchema = schemas.find((schema) => schema.keyword === schemaKeywords.deprecated) as SchemaKeywordMapper['deprecated'] | undefined + const defaultSchema = schemas.find((schema) => schema.keyword === schemaKeywords.default) as SchemaKeywordMapper['default'] | undefined + const exampleSchema = schemas.find((schema) => schema.keyword === schemaKeywords.example) as SchemaKeywordMapper['example'] | undefined + const typeSchema = schemas.find((schema) => schema.keyword === schemaKeywords.type) as SchemaKeywordMapper['type'] | undefined + const formatSchema = schemas.find((schema) => schema.keyword === schemaKeywords.format) as SchemaKeywordMapper['format'] | undefined - let type = schemas.map((item) => parseTypeMeta(item, options)).filter(Boolean)[0] as ts.TypeNode + let type = schemas.map((schema) => parseTypeMeta(current, schema, options)).filter(Boolean)[0] as ts.TypeNode if (isNullable) { type = factory.createUnionDeclaration({ @@ -235,19 +223,19 @@ export function parseTypeMeta(item: Schema, options: ParserOptions): ts.Node | n }) }) - const additionalProperties = item.args?.additionalProperties?.length + const additionalProperties = current.args?.additionalProperties?.length ? factory.createIndexSignature( - item.args.additionalProperties - .map((schema) => parseTypeMeta(schema, options)) + current.args.additionalProperties + .map((schema) => parseTypeMeta(current, schema, options)) .filter(Boolean) .at(0) as ts.TypeNode, ) : undefined - return value([...properties, additionalProperties].filter(Boolean)) + return typeKeywordMapper.object([...properties, additionalProperties].filter(Boolean)) } - if (item.keyword in mapper) { + if (current.keyword in typeKeywordMapper) { return value() } @@ -268,7 +256,7 @@ export function typeParser(schemas: Schema[], options: ParserOptions): string { let type = (schemas - .map((schema) => parseTypeMeta(schema, options)) + .map((schema) => parseTypeMeta(undefined, schema, options)) .filter(Boolean) .at(0) as ts.TypeNode) || typeKeywordMapper.undefined() diff --git a/packages/swagger-ts/src/types.ts b/packages/swagger-ts/src/types.ts index fa77757c0..9f65e4aa1 100644 --- a/packages/swagger-ts/src/types.ts +++ b/packages/swagger-ts/src/types.ts @@ -51,7 +51,7 @@ export type Options = { /** * Array containing override parameters to override `options` based on tags/operations/methods/paths. */ - override?: Array> + override?: Array> /** * Choose to use `enum` or `as const` for enums * @default 'asConst' diff --git a/packages/swagger-zod/package.json b/packages/swagger-zod/package.json index a177dd757..482a60da7 100644 --- a/packages/swagger-zod/package.json +++ b/packages/swagger-zod/package.json @@ -2,14 +2,7 @@ "name": "@kubb/swagger-zod", "version": "2.12.0", "description": "Generator swagger-zod", - "keywords": [ - "zod", - "plugins", - "kubb", - "codegen", - "swagger", - "openapi" - ], + "keywords": ["zod", "plugins", "kubb", "codegen", "swagger", "openapi"], "repository": { "type": "git", "url": "git://github.com/kubb-project/kubb.git", @@ -38,17 +31,10 @@ "types": "./dist/index.d.ts", "typesVersions": { "*": { - "components": [ - "./dist/components.d.ts" - ] + "components": ["./dist/components.d.ts"] } }, - "files": [ - "src", - "dist", - "!/**/**.test.**", - "!/**/__tests__/**" - ], + "files": ["src", "dist", "!/**/**.test.**", "!/**/__tests__/**"], "scripts": { "build": "tsup", "clean": "npx rimraf ./dist", diff --git a/packages/swagger-zod/src/OperationGenerator.test.tsx b/packages/swagger-zod/src/OperationGenerator.test.tsx index ca2898433..6a1be0ed6 100644 --- a/packages/swagger-zod/src/OperationGenerator.test.tsx +++ b/packages/swagger-zod/src/OperationGenerator.test.tsx @@ -9,6 +9,7 @@ import type { GetOperationGeneratorOptions } from '@kubb/swagger' import type { KubbFile } from 'packages/core/dist/index' import { Operations } from './components/Operations.tsx' import type { PluginOptions } from './types.ts' +import { zodKeywordMapper } from './zodParser.tsx' describe('OperationGenerator', async () => { const oas = await OasManager.parseFromConfig({ @@ -28,6 +29,7 @@ describe('OperationGenerator', async () => { templates: { operations: Operations.templates, }, + mapper: {}, } const og = await new OperationGenerator(options, { @@ -66,6 +68,7 @@ describe('OperationGenerator', async () => { templates: { operations: Operations.templates, }, + mapper: {}, } const og = await new OperationGenerator(options, { @@ -97,6 +100,7 @@ describe('OperationGenerator', async () => { templates: { operations: Operations.templates, }, + mapper: {}, } const og = await new OperationGenerator(options, { @@ -128,6 +132,7 @@ describe('OperationGenerator', async () => { templates: { operations: Operations.templates, }, + mapper: {}, } const og = await new OperationGenerator(options, { diff --git a/packages/swagger-zod/src/SchemaGenerator.test.tsx b/packages/swagger-zod/src/SchemaGenerator.test.tsx index a464c506e..f74177257 100644 --- a/packages/swagger-zod/src/SchemaGenerator.test.tsx +++ b/packages/swagger-zod/src/SchemaGenerator.test.tsx @@ -9,6 +9,7 @@ import type { Plugin } from '@kubb/core' import type { SchemaObject } from '@kubb/swagger/oas' import { Operations } from './components/Operations.tsx' import type { PluginOptions } from './types.ts' +import { zodKeywordMapper } from './zodParser.tsx' describe('Zod SchemaGenerator PetStore', async () => { const petStorePath = path.resolve(__dirname, '../mocks/petStore.yaml') @@ -27,6 +28,7 @@ describe('Zod SchemaGenerator PetStore', async () => { templates: { operations: Operations.templates, }, + mapper: {}, }, { oas, @@ -56,6 +58,7 @@ describe('Zod SchemaGenerator PetStore', async () => { templates: { operations: Operations.templates, }, + mapper: {}, }, { oas, @@ -85,6 +88,7 @@ describe('Zod SchemaGenerator PetStore', async () => { templates: { operations: Operations.templates, }, + mapper: {}, }, { oas, @@ -114,6 +118,7 @@ describe('Zod SchemaGenerator PetStore', async () => { templates: { operations: Operations.templates, }, + mapper: {}, }, { oas, @@ -143,6 +148,7 @@ describe('Zod SchemaGenerator PetStore', async () => { templates: { operations: Operations.templates, }, + mapper: {}, }, { oas, @@ -175,6 +181,7 @@ describe('ZodGenerator constCases', async () => { templates: { operations: Operations.templates, }, + mapper: {}, }, { oas, @@ -261,6 +268,7 @@ describe('Zod SchemaGenerator lazy', async () => { templates: { operations: Operations.templates, }, + mapper: {}, }, { oas, @@ -293,6 +301,7 @@ describe('Zod SchemaGenerator enums', async () => { templates: { operations: Operations.templates, }, + mapper: {}, }, { oas, @@ -335,6 +344,7 @@ describe('Zod SchemaGenerator recursive', async () => { templates: { operations: Operations.templates, }, + mapper: {}, }, { oas, @@ -367,6 +377,7 @@ describe('Zod SchemaGenerator anyof', async () => { templates: { operations: Operations.templates, }, + mapper: {}, }, { oas, diff --git a/packages/swagger-zod/src/SchemaGenerator.tsx b/packages/swagger-zod/src/SchemaGenerator.tsx index 10882df37..470a657d7 100644 --- a/packages/swagger-zod/src/SchemaGenerator.tsx +++ b/packages/swagger-zod/src/SchemaGenerator.tsx @@ -1,14 +1,14 @@ -import { createRoot, File, useFile, usePlugin, usePluginManager } from '@kubb/react' +import { File, createRoot, useFile, usePlugin, usePluginManager } from '@kubb/react' import { SchemaGenerator as Generator } from '@kubb/swagger' +import { pluginKey as swaggerTypeScriptPluginKey } from '@kubb/swagger-ts' import { Oas, Schema } from '@kubb/swagger/components' import { useSchema } from '@kubb/swagger/hooks' -import { pluginKey as swaggerTypeScriptPluginKey } from '@kubb/swagger-ts' import { pluginKey } from './plugin.ts' -import { zodParser } from './zodParser.tsx' +import { type zodKeywordMapper, zodParser } from './zodParser.tsx' import type { AppContextProps } from '@kubb/react' -import type { Schema as SchemaType, SchemaGeneratorBuildOptions, SchemaMethodResult } from '@kubb/swagger' +import type { SchemaGeneratorBuildOptions, SchemaMethodResult, Schema as SchemaType } from '@kubb/swagger' import type { SchemaObject } from '@kubb/swagger/oas' import type { FileMeta, PluginOptions } from './types.ts' @@ -87,6 +87,7 @@ export class SchemaGenerator extends Generator generate schema for Pet 1`] = ` [ " -export const Pet = z.object({"id": z.number(),"name": z.string(),"tag": z.string().min(5).max(100).optional()}) +export const Pet = z.object({"id": z.number(),"name": z.string(),"tag": z.string().optional()}) ", ] `; diff --git a/packages/swagger-zod/src/__snapshots__/zodParser.test.ts.snap b/packages/swagger-zod/src/__snapshots__/zodParser.test.ts.snap index 1e81d892e..8c4e087f3 100644 --- a/packages/swagger-zod/src/__snapshots__/zodParser.test.ts.snap +++ b/packages/swagger-zod/src/__snapshots__/zodParser.test.ts.snap @@ -6,12 +6,14 @@ exports[`parseZodMeta > 'any' 1`] = `"z.any()"`; exports[`parseZodMeta > 'array' 1`] = `"z.array(z.union([z.string(), z.number()]))"`; -exports[`parseZodMeta > 'arrayAdvanced' 1`] = `"z.array(z.number().min(1)).min(3).max(10)"`; +exports[`parseZodMeta > 'arrayAdvanced' 1`] = `"z.array(z.number().min(1).max(10)).min(3).max(10)"`; exports[`parseZodMeta > 'arrayEmpty' 1`] = `"z.array()"`; exports[`parseZodMeta > 'arrayRef' 1`] = `"z.array(z.lazy(() => Pet))"`; +exports[`parseZodMeta > 'arrayRegex' 1`] = `"z.array(z.string().regex(new RegExp('^[a-zA-Z0-9]{1,13}$'))).min(3).max(10)"`; + exports[`parseZodMeta > 'blob' 1`] = `undefined`; exports[`parseZodMeta > 'boolean' 1`] = `"z.boolean()"`; @@ -32,21 +34,23 @@ exports[`parseZodMeta > 'matches' 1`] = `".regex(new RegExp('^[A-Z]{2}$'))"`; exports[`parseZodMeta > 'matchesReg' 1`] = `".regex(new RegExp('node_modules'))"`; -exports[`parseZodMeta > 'max' 1`] = `".max(2)"`; +exports[`parseZodMeta > 'max' 1`] = `undefined`; -exports[`parseZodMeta > 'min' 1`] = `".min(2)"`; +exports[`parseZodMeta > 'min' 1`] = `undefined`; exports[`parseZodMeta > 'nullable' 1`] = `".nullable()"`; exports[`parseZodMeta > 'number' 1`] = `"z.number()"`; -exports[`parseZodMeta > 'object' 1`] = `"z.object({"firstName": z.string().min(2),"address": z.string().describe("Your address").nullable()})"`; +exports[`parseZodMeta > 'object' 1`] = `"z.object({"firstName": z.string(),"address": z.string().describe("Your address").nullable()})"`; + +exports[`parseZodMeta > 'objectAnd' 1`] = `"z.object({"firstName": z.string().default(test),"age": z.number().default(2),"address": z.string().and(z.number()).describe("Your address").nullable()})"`; -exports[`parseZodMeta > 'objectAnd' 1`] = `"z.object({"firstName": z.string().min(2).default(test),"age": z.number().min(2).default(2),"address": z.string().and(z.number()).describe("Your address").nullable()})"`; +exports[`parseZodMeta > 'objectArray' 1`] = `"z.object({"ids": z.array(z.string().regex(new RegExp('^[a-zA-Z0-9]{1,13}$'))).min(3).max(10)})"`; exports[`parseZodMeta > 'objectEmpty' 1`] = `"z.object({})"`; -exports[`parseZodMeta > 'objectOptional' 1`] = `"z.object({"firstName": z.string().min(2).optional(),"address": z.string().describe("Your address").nullable()})"`; +exports[`parseZodMeta > 'objectOptional' 1`] = `"z.object({"firstName": z.string().optional(),"address": z.string().describe("Your address").nullable()})"`; exports[`parseZodMeta > 'ref' 1`] = `"z.lazy(() => Pet)"`; @@ -66,7 +70,7 @@ exports[`parseZodMeta > 'unknown' 1`] = `"z.unknown()"`; exports[`zodParser > 'Object' 1`] = ` " -export const Object = z.object({"firstName": z.string().min(2).default(test),"age": z.number().min(2).default(2),"address": z.string().and(z.number()).describe("Your address").nullable()}).describe("Your address").nullable() +export const Object = z.object({"firstName": z.string().default(test),"age": z.number().default(2),"address": z.string().and(z.number()).describe("Your address").nullable()}).describe("Your address").nullable() " `; diff --git a/packages/swagger-zod/src/components/OperationSchema.test.tsx b/packages/swagger-zod/src/components/OperationSchema.test.tsx index 5b1dbe249..168b2957b 100644 --- a/packages/swagger-zod/src/components/OperationSchema.test.tsx +++ b/packages/swagger-zod/src/components/OperationSchema.test.tsx @@ -10,6 +10,7 @@ import type { Plugin } from '@kubb/core' import type { AppContextProps } from '@kubb/react' import type { GetOperationGeneratorOptions } from '@kubb/swagger' import type { PluginOptions } from '../types.ts' +import { zodKeywordMapper } from '../zodParser.tsx' import { Operations } from './Operations.tsx' describe('', async () => { @@ -30,6 +31,7 @@ describe('', async () => { templates: { operations: Operations.templates, }, + mapper: {}, } const plugin = { options } as Plugin diff --git a/packages/swagger-zod/src/components/Operations.test.tsx b/packages/swagger-zod/src/components/Operations.test.tsx index 068c70004..ec0625b12 100644 --- a/packages/swagger-zod/src/components/Operations.test.tsx +++ b/packages/swagger-zod/src/components/Operations.test.tsx @@ -10,6 +10,7 @@ import type { Plugin } from '@kubb/core' import type { AppContextProps } from '@kubb/react' import type { GetOperationGeneratorOptions } from '@kubb/swagger' import type { PluginOptions } from '../types.ts' +import { zodKeywordMapper } from '../zodParser.tsx' describe('', async () => { const oas = await OasManager.parseFromConfig({ @@ -29,6 +30,7 @@ describe('', async () => { templates: { operations: Operations.templates, }, + mapper: {}, } const plugin = { options } as Plugin const og = await new OperationGenerator(options, { diff --git a/packages/swagger-zod/src/plugin.ts b/packages/swagger-zod/src/plugin.ts index adeca4d6f..8e18d9bf2 100644 --- a/packages/swagger-zod/src/plugin.ts +++ b/packages/swagger-zod/src/plugin.ts @@ -14,6 +14,7 @@ import type { Plugin } from '@kubb/core' import type { PluginOptions as SwaggerPluginOptions } from '@kubb/swagger' import { Operations } from './components/Operations.tsx' import type { PluginOptions } from './types.ts' +import { zodKeywordMapper } from './zodParser.tsx' export const pluginName = 'swagger-zod' satisfies PluginOptions['name'] export const pluginKey: PluginOptions['key'] = [pluginName] satisfies PluginOptions['key'] @@ -29,6 +30,7 @@ export const definePlugin = createPlugin((options) => { dateType = 'string', unknownType = 'any', typed = false, + mapper = {}, templates, } = options const template = group?.output ? group.output : `${output.path}/{{tag}}Controller` @@ -43,6 +45,7 @@ export const definePlugin = createPlugin((options) => { typed, dateType, unknownType, + mapper, templates: { operations: Operations.templates, ...templates, diff --git a/packages/swagger-zod/src/types.ts b/packages/swagger-zod/src/types.ts index 008c5d815..db2191589 100644 --- a/packages/swagger-zod/src/types.ts +++ b/packages/swagger-zod/src/types.ts @@ -1,6 +1,7 @@ import type { KubbFile, Plugin, PluginFactoryOptions, ResolveNameParams } from '@kubb/core' -import type { Exclude, Include, Override, ResolvePathOptions } from '@kubb/swagger' +import type { Exclude, Include, Override, ResolvePathOptions, SchemaMapper } from '@kubb/swagger' import type { Operations } from './components/Operations' +import type { zodKeywordMapper } from './zodParser' type Templates = { operations?: typeof Operations.templates | false @@ -61,13 +62,14 @@ export type Options = { /** * Array containing override parameters to override `options` based on tags/operations/methods/paths. */ - override?: Array> + override?: Array> transformers?: { /** * Customize the names based on the type that is provided by the plugin. */ name?: (name: ResolveNameParams['name'], type?: ResolveNameParams['type']) => string } + mapper?: Record /** * Make it possible to override one of the templates */ @@ -97,6 +99,7 @@ type ResolvedOptions = { unknownType: NonNullable typed: NonNullable templates: NonNullable + mapper: Record } export type FileMeta = { diff --git a/packages/swagger-zod/src/zodParser.test.ts b/packages/swagger-zod/src/zodParser.test.ts index b93751435..60984fde0 100644 --- a/packages/swagger-zod/src/zodParser.test.ts +++ b/packages/swagger-zod/src/zodParser.test.ts @@ -3,7 +3,7 @@ import { parseZodMeta, zodParser } from './zodParser.tsx' describe('parseZodMeta', () => { test.each(schemas.basic)('$name', ({ name, schema }) => { - const text = parseZodMeta(schema, { name }) + const text = parseZodMeta(undefined, schema, { name }) expect(text).toMatchSnapshot() }) }) diff --git a/packages/swagger-zod/src/zodParser.tsx b/packages/swagger-zod/src/zodParser.tsx index 347047acc..6995147f5 100644 --- a/packages/swagger-zod/src/zodParser.tsx +++ b/packages/swagger-zod/src/zodParser.tsx @@ -1,52 +1,61 @@ import transformers, { createJSDocBlockText } from '@kubb/core/transformers' -import { isKeyword, schemaKeywords } from '@kubb/swagger' +import { SchemaGenerator, isKeyword, schemaKeywords } from '@kubb/swagger' import type { Schema, SchemaKeywordBase, SchemaMapper } from '@kubb/swagger' export const zodKeywordMapper = { - any: 'z.any', - unknown: 'z.unknown', - number: 'z.number', - integer: 'z.number', - object: 'z.object', - lazy: 'z.lazy', - string: 'z.string', - boolean: 'z.boolean', - undefined: 'z.undefined', - nullable: '.nullable', - null: 'z.null', - nullish: '.nullish', - array: 'z.array', - tuple: 'z.tuple', - enum: 'z.enum', - union: 'z.union', - const: 'z.literal', - datetime: 'z.string().datetime', - date: 'z.date', - uuid: '.uuid', - url: '.url', - strict: '.strict', - default: '.default', - and: '.and', - describe: '.describe', - min: '.min', - max: '.max', - optional: '.optional', - matches: '.regex', - email: '.email', + any: () => 'z.any()', + unknown: () => 'z.unknown()', + number: (min?: number, max?: number) => { + return ['z.number()', min !== undefined ? `.min(${min})` : undefined, max !== undefined ? `.max(${max})` : undefined].filter(Boolean).join('') + }, + integer: (min?: number, max?: number) => { + return ['z.number()', min !== undefined ? `.min(${min})` : undefined, max !== undefined ? `.max(${max})` : undefined].filter(Boolean).join('') + }, + object: (value?: string) => `z.object({${value}})`, + string: (min?: number, max?: number) => { + return ['z.string()', min !== undefined ? `.min(${min})` : undefined, max !== undefined ? `.max(${max})` : undefined].filter(Boolean).join('') + }, + boolean: () => 'z.boolean()', + undefined: () => 'z.undefined()', + nullable: () => '.nullable()', + null: () => 'z.null()', + nullish: () => '.nullish()', + array: (items: string[] = [], min?: number, max?: number) => { + return [`z.array(${items?.join('')})`, min !== undefined ? `.min(${min})` : undefined, max !== undefined ? `.max(${max})` : undefined] + .filter(Boolean) + .join('') + }, + tuple: (items: string[] = []) => `z.tuple([${items?.join(', ')}])`, + enum: (items: string[] = []) => `z.enum([${items?.join(', ')}])`, + union: (items: string[] = []) => `z.union([${items?.join(', ')}])`, + const: (value?: string | number) => `z.literal(${value ?? ''})`, + datetime: () => 'z.string().datetime()', + date: () => 'z.date()', + uuid: () => '.uuid()', + url: () => '.url()', + strict: () => '.strict()', + default: (value?: string | number | true) => `.default(${value ?? ''})`, + and: (items: string[] = []) => items?.map((item) => `.and(${item})`).join(''), + describe: (value = '') => `.describe(${value})`, + min: (value?: number) => `.min(${value ?? ''})`, + max: (value?: number) => `.max(${value ?? ''})`, + optional: () => '.optional()', + matches: (value = '') => `.regex(${value})`, + email: () => '.email()', firstName: undefined, lastName: undefined, password: undefined, phone: undefined, readOnly: undefined, - ref: 'ref', + ref: (value?: string) => (value ? `z.lazy(() => ${value})` : undefined), blob: undefined, deprecated: undefined, example: undefined, type: undefined, format: undefined, - catchall: '.catchall', -} satisfies SchemaMapper + catchall: (value?: string) => (value ? `.catchall(${value})` : undefined), +} satisfies SchemaMapper /** * @link based on https://github.com/cellular/oazapfts/blob/7ba226ebb15374e8483cc53e7532f1663179a22c/src/codegen/generate.ts#L398 @@ -87,156 +96,189 @@ type ParserOptions = { description?: string keysToOmit?: string[] - mapper?: typeof zodKeywordMapper + mapper?: Record } -export function parseZodMeta(item: Schema, options: ParserOptions): string | undefined { - const mapper = options.mapper || zodKeywordMapper - const value = mapper[item.keyword as keyof typeof mapper] +export function parseZodMeta(parent: Schema | undefined, current: Schema, options: ParserOptions): string | undefined { + const value = zodKeywordMapper[current.keyword as keyof typeof zodKeywordMapper] if (!value) { return undefined } - if (isKeyword(item, schemaKeywords.union)) { + if (isKeyword(current, schemaKeywords.union)) { // zod union type needs at least 2 items - if (Array.isArray(item.args) && item.args.length === 1) { - return parseZodMeta(item.args[0] as Schema, options) + if (Array.isArray(current.args) && current.args.length === 1) { + return parseZodMeta(parent, current.args[0] as Schema, options) } - if (Array.isArray(item.args) && !item.args.length) { + if (Array.isArray(current.args) && !current.args.length) { return '' } - return `${value}([${sort(item.args) - .map((unionItem) => parseZodMeta(unionItem, options)) - .filter(Boolean) - .join(', ')}])` + return zodKeywordMapper.union( + sort(current.args) + .map((schema) => parseZodMeta(current, schema, options)) + .filter(Boolean), + ) } - if (isKeyword(item, schemaKeywords.and)) { - return sort(item.args) - .filter((item: Schema) => { - return ![schemaKeywords.optional, schemaKeywords.describe].includes(item.keyword as typeof schemaKeywords.describe) + if (isKeyword(current, schemaKeywords.and)) { + const items = sort(current.args) + .filter((schema: Schema) => { + return ![schemaKeywords.optional, schemaKeywords.describe].includes(schema.keyword as typeof schemaKeywords.describe) }) - .map((item: Schema) => parseZodMeta(item, options)) + .map((schema: Schema) => parseZodMeta(current, schema, options)) .filter(Boolean) - .map((item, index) => (index === 0 ? item : `${value}(${item})`)) - .join('') + + return `${items.slice(0, 1)}${zodKeywordMapper.and(items.slice(1))}` } - if (isKeyword(item, schemaKeywords.array)) { - return [ - `${value}(${sort(item.args.items) - .map((arrayItem) => parseZodMeta(arrayItem, options)) - .filter(Boolean) - .join('')})`, - item.args.min ? `${mapper.min}(${item.args.min})` : undefined, - item.args.max ? `${mapper.max}(${item.args.max})` : undefined, - ] - .filter(Boolean) - .join('') + if (isKeyword(current, schemaKeywords.array)) { + return zodKeywordMapper.array( + sort(current.args.items) + .map((schemas) => parseZodMeta(current, schemas, options)) + .filter(Boolean), + current.args.min, + current.args.max, + ) } - if (isKeyword(item, schemaKeywords.enum)) { - if (item.args.asConst) { - return `${zodKeywordMapper.union}([${item.args.items - .map((item) => { - return parseZodMeta( - { - keyword: schemaKeywords.const, - args: item, - }, - options, - ) - }) - .join(', ')}])` + if (isKeyword(current, schemaKeywords.enum)) { + if (current.args.asConst) { + return zodKeywordMapper.union( + current.args.items + .map((schema) => { + return parseZodMeta( + current, + { + keyword: schemaKeywords.const, + args: schema, + }, + options, + ) + }) + .filter(Boolean), + ) } - return `${value}([${item.args.items - .map((item) => { - if (item.format === 'number') { - return transformers.stringify(item.value) + return zodKeywordMapper.enum( + current.args.items.map((schema) => { + if (schema.format === 'number') { + return transformers.stringify(schema.value) } - return transformers.stringify(item.value) - }) - .join(', ')}])` + return transformers.stringify(schema.value) + }), + ) } - if (isKeyword(item, schemaKeywords.ref)) { - return `${mapper.lazy}(() => ${item.args?.name})` + if (isKeyword(current, schemaKeywords.ref)) { + return zodKeywordMapper.ref(current.args?.name) } - if (isKeyword(item, schemaKeywords.object)) { - const properties = Object.entries(item.args?.properties || {}) + if (isKeyword(current, schemaKeywords.object)) { + const properties = Object.entries(current.args?.properties || {}) .filter((item) => { const schema = item[1] return schema && typeof schema.map === 'function' }) .map((item) => { const name = item[0] - const schema = item[1] + const schemas = item[1] - return `"${name}": ${sort(schema) - .map((item) => parseZodMeta(item, options)) + // custom mapper(pluginOptions) + if (options.mapper?.[name]) { + return `"${name}": ${options.mapper?.[name]}` + } + + return `"${name}": ${sort(schemas) + .map((schema) => parseZodMeta(current, schema, options)) .filter(Boolean) .join('')}` }) .join(',') - const additionalProperties = item.args?.additionalProperties?.length - ? item.args.additionalProperties - .map((schema) => parseZodMeta(schema, options)) + const additionalProperties = current.args?.additionalProperties?.length + ? current.args.additionalProperties + .map((schema) => parseZodMeta(current, schema, options)) .filter(Boolean) .at(0) : undefined const text = [ - `${value}({${properties}})`, - item.args?.strict ? `${mapper.strict}()` : undefined, - additionalProperties ? `${mapper.catchall}(${additionalProperties})` : undefined, + zodKeywordMapper.object(properties), + current.args?.strict ? zodKeywordMapper.strict() : undefined, + additionalProperties ? zodKeywordMapper.catchall(additionalProperties) : undefined, ].filter(Boolean) return text.join('') } - if (isKeyword(item, schemaKeywords.tuple)) { - return `${value}([${sort(item.args) - .map((arrayItem) => parseZodMeta(arrayItem, options)) - .filter(Boolean) - .join(', ')}])` + if (isKeyword(current, schemaKeywords.tuple)) { + return zodKeywordMapper.tuple( + sort(current.args) + .map((schema) => parseZodMeta(current, schema, options)) + .filter(Boolean), + ) } - if (isKeyword(item, schemaKeywords.const)) { - if (item.args.format === 'number') { - return `${value}(${transformers.toNumber(item.args.value)})` + if (isKeyword(current, schemaKeywords.const)) { + if (current.args.format === 'number') { + return zodKeywordMapper.const(transformers.toNumber(current.args.value)) } - return `${value}(${transformers.stringify(item.args.value)})` + return zodKeywordMapper.const(transformers.stringify(current.args.value)) } - if (isKeyword(item, schemaKeywords.matches)) { - if (item.args) { - return `${value}(${transformers.toRegExpString(item.args)})` + if (isKeyword(current, schemaKeywords.matches)) { + if (current.args) { + return zodKeywordMapper.matches(transformers.toRegExpString(current.args)) } } - if (isKeyword(item, schemaKeywords.default)) { - if (item.args) { - return `${value}(${item.args})` + if (isKeyword(current, schemaKeywords.default)) { + if (current.args) { + return zodKeywordMapper.default(current.args) } } - if (isKeyword(item, schemaKeywords.describe)) { - if (item.args) { - return `${value}(${transformers.stringify(item.args.toString())})` + if (isKeyword(current, schemaKeywords.describe)) { + if (current.args) { + return zodKeywordMapper.describe(transformers.stringify(current.args.toString())) } } - if (item.keyword in mapper && 'args' in item) { - return `${value}(${(item as SchemaKeywordBase).args as string})` + if (isKeyword(current, schemaKeywords.string)) { + if (parent) { + const minSchema = SchemaGenerator.find([parent], schemaKeywords.min) + const maxSchema = SchemaGenerator.find([parent], schemaKeywords.max) + + return zodKeywordMapper.string(minSchema?.args, maxSchema?.args) + } + + return zodKeywordMapper.string() + } + + if (isKeyword(current, schemaKeywords.number) || isKeyword(current, schemaKeywords.integer)) { + if (parent) { + const minSchema = SchemaGenerator.find([parent], schemaKeywords.min) + const maxSchema = SchemaGenerator.find([parent], schemaKeywords.max) + + return zodKeywordMapper.number(minSchema?.args, maxSchema?.args) + } + return zodKeywordMapper.number() + } + + if (isKeyword(current, schemaKeywords.min) || isKeyword(current, schemaKeywords.max)) { + return undefined + } + + if (current.keyword in zodKeywordMapper && 'args' in current) { + const value = zodKeywordMapper[current.keyword as keyof typeof zodKeywordMapper] as (typeof zodKeywordMapper)['const'] + + return value((current as SchemaKeywordBase).args as any) } - if (item.keyword in mapper) { - return `${value}()` + if (current.keyword in zodKeywordMapper) { + return value() } return undefined @@ -255,7 +297,7 @@ export function zodParser(schemas: Schema[], options: ParserOptions): string { const constName = `${JSDoc}\nexport const ${options.name}` const typeName = options.typeName ? ` as z.ZodType<${options.typeName}>` : '' const output = sortedSchemas - .map((item) => parseZodMeta(item, options)) + .map((item) => parseZodMeta(undefined, item, options)) .filter(Boolean) .join('') diff --git a/packages/swagger-zodios/package.json b/packages/swagger-zodios/package.json index 448a42c05..ff37cbde7 100644 --- a/packages/swagger-zodios/package.json +++ b/packages/swagger-zodios/package.json @@ -2,15 +2,7 @@ "name": "@kubb/swagger-zodios", "version": "2.12.0", "description": "Generator swagger-zodios", - "keywords": [ - "zod", - "zodios", - "plugins", - "kubb", - "codegen", - "swagger", - "openapi" - ], + "keywords": ["zod", "zodios", "plugins", "kubb", "codegen", "swagger", "openapi"], "repository": { "type": "git", "url": "git://github.com/kubb-project/kubb.git", @@ -39,17 +31,10 @@ "types": "./dist/index.d.ts", "typesVersions": { "*": { - "components": [ - "./dist/components.d.ts" - ] + "components": ["./dist/components.d.ts"] } }, - "files": [ - "src", - "dist", - "!/**/**.test.**", - "!/**/__tests__/**" - ], + "files": ["src", "dist", "!/**/**.test.**", "!/**/__tests__/**"], "scripts": { "build": "tsup", "clean": "npx rimraf ./dist", diff --git a/packages/swagger/mocks/schemas.ts b/packages/swagger/mocks/schemas.ts index 83b0696e7..c478e60ac 100644 --- a/packages/swagger/mocks/schemas.ts +++ b/packages/swagger/mocks/schemas.ts @@ -1,4 +1,4 @@ -import { schemaKeywords, type Schema } from '../src/SchemaMapper' +import { type Schema, schemaKeywords } from '../src/SchemaMapper' const basic: Array<{ name: string; schema: Schema }> = [ { @@ -166,7 +166,18 @@ const basic: Array<{ name: string; schema: Schema }> = [ schema: { keyword: schemaKeywords.array, args: { - items: [{ keyword: schemaKeywords.min, args: 1 }, { keyword: schemaKeywords.number }], + items: [{ keyword: schemaKeywords.min, args: 1 }, { keyword: schemaKeywords.max, args: 10 }, { keyword: schemaKeywords.number }], + min: 3, + max: 10, + }, + }, + }, + { + name: 'arrayRegex', + schema: { + keyword: schemaKeywords.array, + args: { + items: [{ keyword: schemaKeywords.matches, args: '^[a-zA-Z0-9]{1,13}$' }, { keyword: schemaKeywords.string }], min: 3, max: 10, }, @@ -234,6 +245,27 @@ const basic: Array<{ name: string; schema: Schema }> = [ }, }, }, + { + name: 'objectArray', + schema: { + keyword: schemaKeywords.object, + args: { + properties: { + ids: [ + { + keyword: schemaKeywords.array, + args: { + items: [{ keyword: schemaKeywords.matches, args: '^[a-zA-Z0-9]{1,13}$' }, { keyword: schemaKeywords.string }], + min: 3, + max: 10, + }, + }, + ], + }, + additionalProperties: [], + }, + }, + }, { name: 'objectAnd', schema: { @@ -256,7 +288,7 @@ const basic: Array<{ name: string; schema: Schema }> = [ { keyword: schemaKeywords.default, args: 2 }, { keyword: schemaKeywords.min, - args: 2, + args: 3, }, { keyword: schemaKeywords.number, diff --git a/packages/swagger/package.json b/packages/swagger/package.json index c8005bbc0..db72f17aa 100644 --- a/packages/swagger/package.json +++ b/packages/swagger/package.json @@ -2,14 +2,7 @@ "name": "@kubb/swagger", "version": "2.12.0", "description": "Generator swagger", - "keywords": [ - "typescript", - "plugins", - "kubb", - "codegen", - "swagger", - "openapi" - ], + "keywords": ["typescript", "plugins", "kubb", "codegen", "swagger", "openapi"], "repository": { "type": "git", "url": "git://github.com/kubb-project/kubb.git", @@ -53,26 +46,13 @@ "types": "./dist/index.d.ts", "typesVersions": { "*": { - "utils": [ - "./dist/utils.d.ts" - ], - "hooks": [ - "./dist/hooks.d.ts" - ], - "oas": [ - "./dist/oas.d.ts" - ], - "components": [ - "./dist/components.d.ts" - ] + "utils": ["./dist/utils.d.ts"], + "hooks": ["./dist/hooks.d.ts"], + "oas": ["./dist/oas.d.ts"], + "components": ["./dist/components.d.ts"] } }, - "files": [ - "src", - "dist", - "!/**/**.test.**", - "!/**/__tests__/**" - ], + "files": ["src", "dist", "!/**/**.test.**", "!/**/__tests__/**"], "scripts": { "build": "tsup", "clean": "npx rimraf ./dist", diff --git a/packages/swagger/src/SchemaGenerator.ts b/packages/swagger/src/SchemaGenerator.ts index cbdd69ba2..17caf9ec3 100644 --- a/packages/swagger/src/SchemaGenerator.ts +++ b/packages/swagger/src/SchemaGenerator.ts @@ -2,14 +2,14 @@ import { Generator } from '@kubb/core' import transformers, { pascalCase } from '@kubb/core/transformers' import { getUniqueName } from '@kubb/core/utils' +import { isKeyword, schemaKeywords } from './SchemaMapper.ts' import { getSchemaFactory } from './utils/getSchemaFactory.ts' import { getSchemas } from './utils/getSchemas.ts' import { isReference } from './utils/isReference.ts' -import { isKeyword, schemaKeywords } from './SchemaMapper.ts' import type { KubbFile, Plugin, PluginFactoryOptions, PluginManager, ResolveNameParams } from '@kubb/core' -import type { Oas, OpenAPIV3, SchemaObject } from './oas/index.ts' import type { Schema, SchemaKeywordMapper, SchemaMapper } from './SchemaMapper.ts' +import type { Oas, OpenAPIV3, SchemaObject } from './oas/index.ts' import type { ContentType, OperationSchema, Refs } from './types.ts' export type SchemaMethodResult = Promise | Array> | null> @@ -33,7 +33,7 @@ export type SchemaGeneratorOptions = { enumType?: 'enum' | 'asConst' | 'asPascalConst' | 'constEnum' | 'literal' enumSuffix?: string usedEnumNames?: Record - mapper?: SchemaMapper + mapper?: Record typed?: boolean transformers: { /** @@ -79,6 +79,10 @@ export abstract class SchemaGenerator< return SchemaGenerator.deepSearch(schemas, keyword) } + find(schemas: Schema[] | undefined, keyword: T): SchemaKeywordMapper[T] | undefined { + return SchemaGenerator.find(schemas, keyword) + } + static deepSearch(schemas: Schema[] | undefined, keyword: T): SchemaKeywordMapper[T][] { const foundItems: SchemaKeywordMapper[T][] = [] @@ -135,6 +139,58 @@ export abstract class SchemaGenerator< return foundItems } + static find(schemas: Schema[] | undefined, keyword: T): SchemaKeywordMapper[T] | undefined { + let foundItem: SchemaKeywordMapper[T] | undefined = undefined + + schemas?.forEach((schema) => { + if (!foundItem && schema.keyword === keyword) { + foundItem = schema as SchemaKeywordMapper[T] + } + + if (schema.keyword === schemaKeywords.array) { + const subItem = schema as SchemaKeywordMapper['array'] + + subItem.args.items.forEach((entrySchema) => { + if (!foundItem) { + foundItem = SchemaGenerator.find([entrySchema], keyword) + } + }) + } + + if (schema.keyword === schemaKeywords.and) { + const subItem = schema as SchemaKeywordMapper['and'] + + subItem.args.forEach((entrySchema) => { + if (!foundItem) { + foundItem = SchemaGenerator.find([entrySchema], keyword) + } + }) + } + + if (schema.keyword === schemaKeywords.tuple) { + const subItem = schema as SchemaKeywordMapper['tuple'] + + subItem.args.forEach((entrySchema) => { + if (!foundItem) { + foundItem = SchemaGenerator.find([entrySchema], keyword) + } + }) + } + + if (schema.keyword === schemaKeywords.union) { + const subItem = schema as SchemaKeywordMapper['union'] + + subItem.args.forEach((entrySchema) => { + if (!foundItem) { + foundItem = SchemaGenerator.find([entrySchema], keyword) + } + }) + } + }) + + return foundItem + } + get #unknownReturn() { if (this.options.unknownType === 'any') { return schemaKeywords.any @@ -259,6 +315,9 @@ export abstract class SchemaGenerator< } const baseItems: Schema[] = [] + const min = schema.minimum ?? schema.minLength ?? schema.minItems ?? undefined + const max = schema.maximum ?? schema.maxLength ?? schema.maxItems ?? undefined + const nullable = schema.nullable ?? schema['x-nullable'] ?? false if (schema.default !== undefined && !Array.isArray(schema.default)) { if (typeof schema.default === 'string') { @@ -289,12 +348,18 @@ export abstract class SchemaGenerator< }) } + if (max !== undefined) { + baseItems.unshift({ keyword: schemaKeywords.max, args: max }) + } + + if (min !== undefined) { + baseItems.unshift({ keyword: schemaKeywords.min, args: min }) + } + if (schema.format) { baseItems.push({ keyword: schemaKeywords.format, args: schema.format }) } - const nullable = schema.nullable ?? schema['x-nullable'] ?? false - if (nullable) { baseItems.push({ keyword: schemaKeywords.nullable }) } @@ -543,19 +608,6 @@ export abstract class SchemaGenerator< ].filter(Boolean) } - if ([schemaKeywords.number as string, schemaKeywords.integer as string, schemaKeywords.string as string].includes(schema.type)) { - const min = schema.minimum ?? schema.minLength ?? schema.minItems ?? undefined - const max = schema.maximum ?? schema.maxLength ?? schema.maxItems ?? undefined - - if (max !== undefined) { - baseItems.unshift({ keyword: schemaKeywords.max, args: max }) - } - - if (min !== undefined) { - baseItems.unshift({ keyword: schemaKeywords.min, args: min }) - } - } - if (schema.pattern) { baseItems.unshift({ keyword: schemaKeywords.matches, diff --git a/packages/swagger/src/SchemaMapper.ts b/packages/swagger/src/SchemaMapper.ts index 7951f043e..a83ea98f4 100644 --- a/packages/swagger/src/SchemaMapper.ts +++ b/packages/swagger/src/SchemaMapper.ts @@ -52,13 +52,12 @@ export type SchemaKeywordMapper = { keyword: 'ref' args: { name: string; path: KubbFile.OptionalPath; isTypeOnly?: boolean } } - lazy: { keyword: 'lazy' } matches: { keyword: 'matches'; args?: string } boolean: { keyword: 'boolean' } default: { keyword: 'default'; args: string | number | boolean } - string: { keyword: 'string'; args?: { min?: number; max?: number } } - integer: { keyword: 'integer'; args?: { min?: number; max?: number } } - number: { keyword: 'number'; args?: { min?: number; max?: number } } + string: { keyword: 'string' } + integer: { keyword: 'integer' } + number: { keyword: 'number' } max: { keyword: 'max'; args: number } min: { keyword: 'min'; args: number } describe: { keyword: 'describe'; args: string } @@ -88,7 +87,6 @@ export const schemaKeywords = { integer: 'integer', string: 'string', boolean: 'boolean', - lazy: 'lazy', undefined: 'undefined', nullable: 'nullable', null: 'null', @@ -132,8 +130,8 @@ export const schemaKeywords = { export type SchemaKeyword = keyof SchemaKeywordMapper -export type SchemaMapper = { - [K in keyof SchemaKeywordMapper]: T | undefined +export type SchemaMapper = { + [K in keyof SchemaKeywordMapper]: (() => T | undefined) | undefined } export type SchemaKeywordBase = { diff --git a/packages/swagger/src/components/Schema.tsx b/packages/swagger/src/components/Schema.tsx index 3a2cdbe14..ba98a839e 100644 --- a/packages/swagger/src/components/Schema.tsx +++ b/packages/swagger/src/components/Schema.tsx @@ -1,14 +1,14 @@ -import { createContext, Editor, File, useFile, usePlugin, usePluginManager } from '@kubb/react' +import { Editor, File, createContext, useFile, usePlugin, usePluginManager } from '@kubb/react' -import { useSchema } from '../hooks/useSchema.ts' import { schemaKeywords } from '../SchemaMapper.ts' +import { useSchema } from '../hooks/useSchema.ts' import type { KubbFile } from '@kubb/core' import type { KubbNode } from '@kubb/react' import type { ReactNode } from 'react' -import type { SchemaObject } from '../oas/index.ts' import type { SchemaGenerator, SchemaGeneratorBuildOptions } from '../SchemaGenerator.ts' import type { Schema as SchemaType } from '../SchemaMapper.ts' +import type { SchemaObject } from '../oas/index.ts' import type { PluginOptions } from '../types.ts' export type SchemaContextProps = { @@ -21,7 +21,7 @@ export type SchemaContextProps = { type Props = { name: string object?: SchemaObject - generator: SchemaGenerator + generator: SchemaGenerator children?: KubbNode } diff --git a/packages/types/package.json b/packages/types/package.json index fc069e843..6d61928fa 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -2,12 +2,7 @@ "name": "@kubb/types", "version": "2.12.0", "description": "Generator types", - "keywords": [ - "typescript", - "plugins", - "kubb", - "codegen" - ], + "keywords": ["typescript", "plugins", "kubb", "codegen"], "repository": { "type": "git", "url": "git://github.com/kubb-project/kubb.git", @@ -29,14 +24,7 @@ "main": "dist/index.cjs", "module": "dist/index.js", "types": "./dist/index.d.ts", - "files": [ - "src", - "dist", - "*.d.ts", - "*.d.cts", - "!/**/**.test.**", - "!/**/__tests__/**" - ], + "files": ["src", "dist", "*.d.ts", "*.d.cts", "!/**/**.test.**", "!/**/__tests__/**"], "scripts": { "build": "tsup", "clean": "npx rimraf ./dist", diff --git a/packages/unplugin/package.json b/packages/unplugin/package.json index 4e49fa40b..fdc7733fb 100644 --- a/packages/unplugin/package.json +++ b/packages/unplugin/package.json @@ -2,20 +2,7 @@ "name": "unplugin-kubb", "version": "0.1.24", "description": "Unplugin for Kubb", - "keywords": [ - "unplugin", - "vite", - "webpack", - "rollup", - "transform", - "astro", - "kubb", - "swagger", - "OpenAPI", - "rspack", - "nuxt", - "esbuild" - ], + "keywords": ["unplugin", "vite", "webpack", "rollup", "transform", "astro", "kubb", "swagger", "OpenAPI", "rspack", "nuxt", "esbuild"], "repository": { "type": "git", "url": "git://github.com/kubb-project/kubb.git", @@ -77,18 +64,10 @@ "main": "dist/index.cjs", "module": "dist/index.js", "types": "dist/index.d.ts", - "files": [ - "src", - "dist", - "!/**/**.test.**", - "!/**/__tests__/**" - ], + "files": ["src", "dist", "!/**/**.test.**", "!/**/__tests__/**"], "typesVersions": { "*": { - "*": [ - "./dist/*", - "./*" - ] + "*": ["./dist/*", "./*"] } }, "scripts": {