diff --git a/.changeset/cool-days-scream.md b/.changeset/cool-days-scream.md new file mode 100644 index 000000000..89af7a0c8 --- /dev/null +++ b/.changeset/cool-days-scream.md @@ -0,0 +1,5 @@ +--- +'@hey-api/openapi-ts': patch +--- + +fix: add support for long integers diff --git a/.changeset/nasty-comics-smoke.md b/.changeset/nasty-comics-smoke.md index 97201bd0b..e36d53bdd 100644 --- a/.changeset/nasty-comics-smoke.md +++ b/.changeset/nasty-comics-smoke.md @@ -2,4 +2,4 @@ '@hey-api/openapi-ts': patch --- -fix: preserve leading indicators in enum keys +fix: preserve leading separators in enum keys diff --git a/packages/openapi-ts/src/ir/schema.ts b/packages/openapi-ts/src/ir/schema.ts index a96becd90..f3db925c4 100644 --- a/packages/openapi-ts/src/ir/schema.ts +++ b/packages/openapi-ts/src/ir/schema.ts @@ -26,6 +26,7 @@ export const deduplicateSchema = ({ // no `type` might still include `$ref` or `const` !item.type || item.type === 'boolean' || + item.type === 'integer' || item.type === 'null' || item.type === 'number' || item.type === 'string' || diff --git a/packages/openapi-ts/src/ir/types.d.ts b/packages/openapi-ts/src/ir/types.d.ts index b95d5018a..501f5fbf7 100644 --- a/packages/openapi-ts/src/ir/types.d.ts +++ b/packages/openapi-ts/src/ir/types.d.ts @@ -174,6 +174,7 @@ interface IRSchemaObject | 'array' | 'boolean' | 'enum' + | 'integer' | 'never' | 'null' | 'number' diff --git a/packages/openapi-ts/src/openApi/2.0.x/parser/schema.ts b/packages/openapi-ts/src/openApi/2.0.x/parser/schema.ts index e01d87a23..19e95e885 100644 --- a/packages/openapi-ts/src/openApi/2.0.x/parser/schema.ts +++ b/packages/openapi-ts/src/openApi/2.0.x/parser/schema.ts @@ -163,11 +163,12 @@ const parseBoolean = ({ const parseNumber = ({ irSchema = {}, + schema, }: SchemaContext & { irSchema?: IR.SchemaObject; - schema: SchemaObject; + schema: SchemaWithRequired; }): IR.SchemaObject => { - irSchema.type = 'number'; + irSchema.type = schema.type; return irSchema; }; diff --git a/packages/openapi-ts/src/openApi/3.0.x/parser/schema.ts b/packages/openapi-ts/src/openApi/3.0.x/parser/schema.ts index cabb492a3..7b7db8979 100644 --- a/packages/openapi-ts/src/openApi/3.0.x/parser/schema.ts +++ b/packages/openapi-ts/src/openApi/3.0.x/parser/schema.ts @@ -170,11 +170,12 @@ const parseBoolean = ({ const parseNumber = ({ irSchema = {}, + schema, }: SchemaContext & { irSchema?: IR.SchemaObject; - schema: SchemaObject; + schema: SchemaWithRequired; }): IR.SchemaObject => { - irSchema.type = 'number'; + irSchema.type = schema.type; return irSchema; }; diff --git a/packages/openapi-ts/src/openApi/3.1.x/parser/schema.ts b/packages/openapi-ts/src/openApi/3.1.x/parser/schema.ts index 16e5aa202..e9084f013 100644 --- a/packages/openapi-ts/src/openApi/3.1.x/parser/schema.ts +++ b/packages/openapi-ts/src/openApi/3.1.x/parser/schema.ts @@ -223,11 +223,14 @@ const parseNull = ({ const parseNumber = ({ irSchema = {}, + schema, }: SchemaContext & { irSchema?: IR.SchemaObject; - schema: SchemaObject; + schema: Omit & { + type: SchemaType; + }; }): IR.SchemaObject => { - irSchema.type = 'number'; + irSchema.type = schema.type; return irSchema; }; diff --git a/packages/openapi-ts/src/plugins/@hey-api/transformers/config.ts b/packages/openapi-ts/src/plugins/@hey-api/transformers/config.ts index 3ec63394d..e8351f1e6 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/transformers/config.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/transformers/config.ts @@ -8,6 +8,7 @@ export const defaultConfig: Plugin.Config = { _handler: handler, _handlerLegacy: handlerLegacy, _tags: ['transformer'], + bigInt: true, dates: true, name: '@hey-api/transformers', output: 'transformers', diff --git a/packages/openapi-ts/src/plugins/@hey-api/transformers/plugin.ts b/packages/openapi-ts/src/plugins/@hey-api/transformers/plugin.ts index f1598b1c0..75bfeb5c2 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/transformers/plugin.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/transformers/plugin.ts @@ -16,6 +16,75 @@ interface OperationIRRef { id: string; } +const bigIntExpressions = ({ + dataExpression, +}: { + dataExpression?: ts.Expression | string; +}): Array => { + const bigIntCallExpression = + dataExpression !== undefined + ? compiler.callExpression({ + functionName: 'BigInt', + parameters: [ + compiler.callExpression({ + functionName: compiler.propertyAccessExpression({ + expression: dataExpression, + name: 'toString', + }), + }), + ], + }) + : undefined; + + if (bigIntCallExpression) { + if (typeof dataExpression === 'string') { + return [bigIntCallExpression]; + } + + if (dataExpression) { + return [ + compiler.assignment({ + left: dataExpression, + right: bigIntCallExpression, + }), + ]; + } + } + + return []; +}; + +const dateExpressions = ({ + dataExpression, +}: { + dataExpression?: ts.Expression | string; +}): Array => { + const identifierDate = compiler.identifier({ text: 'Date' }); + + if (typeof dataExpression === 'string') { + return [ + compiler.newExpression({ + argumentsArray: [compiler.identifier({ text: dataExpression })], + expression: identifierDate, + }), + ]; + } + + if (dataExpression) { + return [ + compiler.assignment({ + left: dataExpression, + right: compiler.newExpression({ + argumentsArray: [dataExpression], + expression: identifierDate, + }), + }), + ]; + } + + return []; +}; + export const operationTransformerIrRef = ({ id, type, @@ -147,7 +216,7 @@ const processSchemaType = ({ parameters: [ { name: dataVariableName, - // TODO: parser - add types, generate types without transformed dates + // TODO: parser - add types, generate types without transforms type: compiler.keywordTypeNode({ keyword: 'any' }), }, ], @@ -293,30 +362,11 @@ const processSchemaType = ({ schema.type === 'string' && (schema.format === 'date' || schema.format === 'date-time') ) { - const identifierDate = compiler.identifier({ text: 'Date' }); - - if (typeof dataExpression === 'string') { - return [ - compiler.newExpression({ - argumentsArray: [compiler.identifier({ text: dataExpression })], - expression: identifierDate, - }), - ]; - } - - if (dataExpression) { - return [ - compiler.assignment({ - left: dataExpression, - right: compiler.newExpression({ - argumentsArray: [dataExpression], - expression: identifierDate, - }), - }), - ]; - } + return dateExpressions({ dataExpression }); + } - return []; + if (plugin.bigInt && schema.type === 'integer' && schema.format === 'int64') { + return bigIntExpressions({ dataExpression }); } if (schema.items) { @@ -447,7 +497,7 @@ export const handler: Plugin.Handler = ({ context, plugin }) => { parameters: [ { name: dataVariableName, - // TODO: parser - add types, generate types without transformed dates + // TODO: parser - add types, generate types without transforms type: compiler.keywordTypeNode({ keyword: 'any' }), }, ], diff --git a/packages/openapi-ts/src/plugins/@hey-api/transformers/types.d.ts b/packages/openapi-ts/src/plugins/@hey-api/transformers/types.d.ts index abece4756..cc7a949ec 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/transformers/types.d.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/transformers/types.d.ts @@ -1,13 +1,23 @@ import type { Plugin } from '../../types'; export interface Config extends Plugin.Name<'@hey-api/transformers'> { + /** + * **This feature works only with the [experimental parser](https://heyapi.dev/openapi-ts/configuration#parser)** + * + * Convert long integers into BigInt values? + * + * @default true + */ + bigInt?: boolean; /** * Convert date strings into Date objects? + * * @default true */ dates?: boolean; /** * Name of the generated file. + * * @default 'transformers' */ output?: string; diff --git a/packages/openapi-ts/src/plugins/@hey-api/typescript/plugin.ts b/packages/openapi-ts/src/plugins/@hey-api/typescript/plugin.ts index 819067e2b..74fea6051 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/typescript/plugin.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/typescript/plugin.ts @@ -402,11 +402,12 @@ const enumTypeToIdentifier = ({ }; const numberTypeToIdentifier = ({ + context, schema, }: { context: IR.Context; namespace: Array; - schema: SchemaWithType<'number'>; + schema: SchemaWithType<'integer' | 'number'>; }) => { if (schema.const !== undefined) { return compiler.literalTypeNode({ @@ -414,6 +415,13 @@ const numberTypeToIdentifier = ({ }); } + if (schema.type === 'integer' && schema.format === 'int64') { + // TODO: parser - add ability to skip type transformers + if (context.config.plugins['@hey-api/transformers']?.bigInt) { + return compiler.typeReferenceNode({ typeName: 'BigInt' }); + } + } + return compiler.keywordTypeNode({ keyword: 'number', }); @@ -605,6 +613,13 @@ const schemaTypeToIdentifier = ({ plugin, schema: schema as SchemaWithType<'enum'>, }); + case 'integer': + case 'number': + return numberTypeToIdentifier({ + context, + namespace, + schema: schema as SchemaWithType<'integer' | 'number'>, + }); case 'never': return compiler.keywordTypeNode({ keyword: 'never', @@ -613,12 +628,6 @@ const schemaTypeToIdentifier = ({ return compiler.literalTypeNode({ literal: compiler.null(), }); - case 'number': - return numberTypeToIdentifier({ - context, - namespace, - schema: schema as SchemaWithType<'number'>, - }); case 'object': return objectTypeToIdentifier({ context, diff --git a/packages/openapi-ts/src/plugins/zod/plugin.ts b/packages/openapi-ts/src/plugins/zod/plugin.ts index 1838d365c..282b9d2c5 100644 --- a/packages/openapi-ts/src/plugins/zod/plugin.ts +++ b/packages/openapi-ts/src/plugins/zod/plugin.ts @@ -241,15 +241,28 @@ const numberTypeToZodSchema = ({ schema, }: { context: IR.Context; - schema: SchemaWithType<'number'>; + schema: SchemaWithType<'integer' | 'number'>; }) => { + const isBigInt = schema.type === 'integer' && schema.format === 'int64'; + let numberExpression = compiler.callExpression({ functionName: compiler.propertyAccessExpression({ expression: zIdentifier, - name: compiler.identifier({ text: schema.type }), + name: isBigInt + ? compiler.identifier({ text: 'bigint' }) + : compiler.identifier({ text: 'number' }), }), }); + if (!isBigInt && schema.type === 'integer') { + numberExpression = compiler.callExpression({ + functionName: compiler.propertyAccessExpression({ + expression: numberExpression, + name: compiler.identifier({ text: 'int' }), + }), + }); + } + if (schema.const !== undefined) { // TODO: parser - add constant // return compiler.literalTypeNode({ @@ -584,6 +597,12 @@ const schemaTypeToZodSchema = ({ context, schema: schema as SchemaWithType<'enum'>, }); + case 'integer': + case 'number': + return numberTypeToZodSchema({ + context, + schema: schema as SchemaWithType<'integer' | 'number'>, + }); case 'never': return neverTypeToZodSchema({ context, @@ -594,11 +613,6 @@ const schemaTypeToZodSchema = ({ context, schema: schema as SchemaWithType<'null'>, }); - case 'number': - return numberTypeToZodSchema({ - context, - schema: schema as SchemaWithType<'number'>, - }); case 'object': return objectTypeToZodSchema({ context, diff --git a/packages/openapi-ts/test/2.0.x.test.ts b/packages/openapi-ts/test/2.0.x.test.ts index 769c2b9b0..75de573de 100644 --- a/packages/openapi-ts/test/2.0.x.test.ts +++ b/packages/openapi-ts/test/2.0.x.test.ts @@ -11,11 +11,11 @@ import { getFilePaths } from './utils'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const VERSION = '2.0.x'; +const version = '2.0.x'; -const outputDir = path.join(__dirname, 'generated', VERSION); +const outputDir = path.join(__dirname, 'generated', version); -describe(`OpenAPI ${VERSION}`, () => { +describe(`OpenAPI ${version}`, () => { const createConfig = (userConfig: UserConfig): UserConfig => ({ client: '@hey-api/client-fetch', experimentalParser: true, @@ -24,7 +24,7 @@ describe(`OpenAPI ${VERSION}`, () => { input: path.join( __dirname, 'spec', - VERSION, + version, typeof userConfig.input === 'string' ? userConfig.input : '', ), output: path.join( @@ -273,7 +273,7 @@ describe(`OpenAPI ${VERSION}`, () => { path.join( __dirname, '__snapshots__', - VERSION, + version, filePath.slice(outputDir.length + 1), ), ); diff --git a/packages/openapi-ts/test/3.0.x.test.ts b/packages/openapi-ts/test/3.0.x.test.ts index ab61638ee..09bc9d866 100644 --- a/packages/openapi-ts/test/3.0.x.test.ts +++ b/packages/openapi-ts/test/3.0.x.test.ts @@ -11,11 +11,11 @@ import { getFilePaths } from './utils'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const VERSION = '3.0.x'; +const version = '3.0.x'; -const outputDir = path.join(__dirname, 'generated', VERSION); +const outputDir = path.join(__dirname, 'generated', version); -describe(`OpenAPI ${VERSION}`, () => { +describe(`OpenAPI ${version}`, () => { const createConfig = (userConfig: UserConfig): UserConfig => ({ client: '@hey-api/client-fetch', experimentalParser: true, @@ -24,7 +24,7 @@ describe(`OpenAPI ${VERSION}`, () => { input: path.join( __dirname, 'spec', - VERSION, + version, typeof userConfig.input === 'string' ? userConfig.input : '', ), output: path.join( @@ -514,7 +514,7 @@ describe(`OpenAPI ${VERSION}`, () => { path.join( __dirname, '__snapshots__', - VERSION, + version, filePath.slice(outputDir.length + 1), ), ); diff --git a/packages/openapi-ts/test/3.1.x.test.ts b/packages/openapi-ts/test/3.1.x.test.ts index 3c860f5fb..b102cb1cd 100644 --- a/packages/openapi-ts/test/3.1.x.test.ts +++ b/packages/openapi-ts/test/3.1.x.test.ts @@ -11,11 +11,11 @@ import { getFilePaths } from './utils'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const VERSION = '3.1.x'; +const version = '3.1.x'; -const outputDir = path.join(__dirname, 'generated', VERSION); +const outputDir = path.join(__dirname, 'generated', version); -describe(`OpenAPI ${VERSION}`, () => { +describe(`OpenAPI ${version}`, () => { const createConfig = (userConfig: UserConfig): UserConfig => ({ client: '@hey-api/client-fetch', experimentalParser: true, @@ -24,7 +24,7 @@ describe(`OpenAPI ${VERSION}`, () => { input: path.join( __dirname, 'spec', - VERSION, + version, typeof userConfig.input === 'string' ? userConfig.input : '', ), output: path.join( @@ -575,7 +575,7 @@ describe(`OpenAPI ${VERSION}`, () => { path.join( __dirname, '__snapshots__', - VERSION, + version, filePath.slice(outputDir.length + 1), ), ); diff --git a/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format/index.ts b/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format/index.ts new file mode 100644 index 000000000..e64537d21 --- /dev/null +++ b/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts +export * from './types.gen'; +export * from './sdk.gen'; \ No newline at end of file diff --git a/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format/sdk.gen.ts b/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format/sdk.gen.ts new file mode 100644 index 000000000..d0cf1c7c8 --- /dev/null +++ b/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format/sdk.gen.ts @@ -0,0 +1,19 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { createClient, createConfig, type Options } from '@hey-api/client-fetch'; +import type { PostFooData, PostFooResponse } from './types.gen'; +import { postFooResponseTransformer } from './transformers.gen'; +import { zPostFooResponse } from './zod.gen'; + +export const client = createClient(createConfig()); + +export const postFoo = (options?: Options) => { + return (options?.client ?? client).post({ + ...options, + responseTransformer: postFooResponseTransformer, + responseValidator: async (data) => { + return await zPostFooResponse.parseAsync(data); + }, + url: '/foo' + }); +}; \ No newline at end of file diff --git a/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format/transformers.gen.ts b/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format/transformers.gen.ts new file mode 100644 index 000000000..419690a91 --- /dev/null +++ b/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format/transformers.gen.ts @@ -0,0 +1,13 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { PostFooResponse } from './types.gen'; + +const fooSchemaResponseTransformer = (data: any) => { + data.foo = BigInt(data.foo.toString()); + return data; +}; + +export const postFooResponseTransformer = async (data: any): Promise => { + data = fooSchemaResponseTransformer(data); + return data; +}; \ No newline at end of file diff --git a/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format/types.gen.ts b/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format/types.gen.ts new file mode 100644 index 000000000..7955b8949 --- /dev/null +++ b/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format/types.gen.ts @@ -0,0 +1,28 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type Foo = { + bar?: number; + foo: BigInt; + id: string; +}; + +export type Bar = { + foo: number; + [key: string]: number; +}; + +export type PostFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type PostFooResponses = { + /** + * OK + */ + 200: Foo; +}; + +export type PostFooResponse = PostFooResponses[keyof PostFooResponses]; \ No newline at end of file diff --git a/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format/zod.gen.ts b/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format/zod.gen.ts new file mode 100644 index 000000000..30bdf8629 --- /dev/null +++ b/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format/zod.gen.ts @@ -0,0 +1,15 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { z } from 'zod'; + +export const zFoo = z.object({ + bar: z.number().int().optional(), + foo: z.bigint(), + id: z.string() +}); + +export const zBar = z.object({ + foo: z.number().int() +}); + +export const zPostFooResponse = zFoo; \ No newline at end of file diff --git a/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/zod/default/zod.gen.ts b/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/zod/default/zod.gen.ts index 8b0ee8eed..64f8926c5 100644 --- a/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/zod/default/zod.gen.ts +++ b/packages/openapi-ts/test/__snapshots__/2.0.x/plugins/zod/default/zod.gen.ts @@ -2,21 +2,21 @@ import { z } from 'zod'; -export const zCommentWithBreaks = z.number(); +export const zCommentWithBreaks = z.number().int(); -export const zCommentWithBackticks = z.number(); +export const zCommentWithBackticks = z.number().int(); -export const zCommentWithBackticksAndQuotes = z.number(); +export const zCommentWithBackticksAndQuotes = z.number().int(); -export const zCommentWithSlashes = z.number(); +export const zCommentWithSlashes = z.number().int(); -export const zCommentWithExpressionPlaceholders = z.number(); +export const zCommentWithExpressionPlaceholders = z.number().int(); -export const zCommentWithQuotes = z.number(); +export const zCommentWithQuotes = z.number().int(); -export const zCommentWithReservedCharacters = z.number(); +export const zCommentWithReservedCharacters = z.number().int(); -export const zSimpleInteger = z.number(); +export const zSimpleInteger = z.number().int(); export const zSimpleBoolean = z.boolean(); @@ -47,7 +47,7 @@ export const zEnumFromDescription = z.number(); export const zEnumWithExtensions = z.unknown(); -export const zArrayWithNumbers = z.array(z.number()); +export const zArrayWithNumbers = z.array(z.number().int()); export const zArrayWithBooleans = z.array(z.boolean()); @@ -79,7 +79,7 @@ export const zDictionaryWithProperties = z.object({}); export const zDate = z.string(); export const zModelWithInteger = z.object({ - prop: z.number().optional() + prop: z.number().int().optional() }); export const zModelWithBoolean = z.object({ @@ -124,7 +124,7 @@ export const zModelWithEnum = z.object({ }); export const zModelWithEnumFromDescription = z.object({ - test: z.number().optional() + test: z.number().int().optional() }); export const zModelWithNestedEnums = z.object({ @@ -135,7 +135,7 @@ export const zModelWithNestedEnums = z.object({ 'Warning', 'Error' ])).optional(), - arrayWithDescription: z.array(z.number()).optional() + arrayWithDescription: z.array(z.number().int()).optional() }); export const zModelWithReference = z.object({ @@ -150,7 +150,7 @@ export const zModelWithReference = z.object({ default: z.string().optional(), try: z.string().optional(), '@namespace.string': z.string().readonly().optional(), - '@namespace.integer': z.number().readonly().optional() + '@namespace.integer': z.number().int().readonly().optional() }).optional() }); @@ -181,7 +181,7 @@ export const zModelWithProperties = z.object({ default: z.string().optional(), try: z.string().optional(), '@namespace.string': z.string().readonly().optional(), - '@namespace.integer': z.number().readonly().optional() + '@namespace.integer': z.number().int().readonly().optional() }); export const zModelWithNestedProperties = z.object({ @@ -236,18 +236,18 @@ export const zModelWithPattern = z.object({ export const zParameterActivityParams = z.object({ description: z.string().optional(), - graduate_id: z.number().optional(), - organization_id: z.number().optional(), - parent_activity: z.number().optional(), - post_id: z.number().optional() + graduate_id: z.number().int().optional(), + organization_id: z.number().int().optional(), + parent_activity: z.number().int().optional(), + post_id: z.number().int().optional() }); export const zResponsePostActivityResponse = z.object({ description: z.string().optional(), - graduate_id: z.number().optional(), - organization_id: z.number().optional(), - parent_activity_id: z.number().optional(), - post_id: z.number().optional() + graduate_id: z.number().int().optional(), + organization_id: z.number().int().optional(), + parent_activity_id: z.number().int().optional(), + post_id: z.number().int().optional() }); export const zFailureFailure = z.object({ @@ -268,7 +268,7 @@ export const zCallWithDuplicateResponsesResponse = zModelWithString; export const zCallWithResponsesResponse = z.union([ z.object({ '@namespace.string': z.string().readonly().optional(), - '@namespace.integer': z.number().readonly().optional(), + '@namespace.integer': z.number().int().readonly().optional(), value: z.array(zModelWithString).readonly().optional() }), zModelThatExtends, diff --git a/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format/index.ts b/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format/index.ts new file mode 100644 index 000000000..e64537d21 --- /dev/null +++ b/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts +export * from './types.gen'; +export * from './sdk.gen'; \ No newline at end of file diff --git a/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format/sdk.gen.ts b/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format/sdk.gen.ts new file mode 100644 index 000000000..d0cf1c7c8 --- /dev/null +++ b/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format/sdk.gen.ts @@ -0,0 +1,19 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { createClient, createConfig, type Options } from '@hey-api/client-fetch'; +import type { PostFooData, PostFooResponse } from './types.gen'; +import { postFooResponseTransformer } from './transformers.gen'; +import { zPostFooResponse } from './zod.gen'; + +export const client = createClient(createConfig()); + +export const postFoo = (options?: Options) => { + return (options?.client ?? client).post({ + ...options, + responseTransformer: postFooResponseTransformer, + responseValidator: async (data) => { + return await zPostFooResponse.parseAsync(data); + }, + url: '/foo' + }); +}; \ No newline at end of file diff --git a/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format/transformers.gen.ts b/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format/transformers.gen.ts new file mode 100644 index 000000000..419690a91 --- /dev/null +++ b/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format/transformers.gen.ts @@ -0,0 +1,13 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { PostFooResponse } from './types.gen'; + +const fooSchemaResponseTransformer = (data: any) => { + data.foo = BigInt(data.foo.toString()); + return data; +}; + +export const postFooResponseTransformer = async (data: any): Promise => { + data = fooSchemaResponseTransformer(data); + return data; +}; \ No newline at end of file diff --git a/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format/types.gen.ts b/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format/types.gen.ts new file mode 100644 index 000000000..7955b8949 --- /dev/null +++ b/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format/types.gen.ts @@ -0,0 +1,28 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type Foo = { + bar?: number; + foo: BigInt; + id: string; +}; + +export type Bar = { + foo: number; + [key: string]: number; +}; + +export type PostFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type PostFooResponses = { + /** + * OK + */ + 200: Foo; +}; + +export type PostFooResponse = PostFooResponses[keyof PostFooResponses]; \ No newline at end of file diff --git a/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format/zod.gen.ts b/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format/zod.gen.ts new file mode 100644 index 000000000..30bdf8629 --- /dev/null +++ b/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format/zod.gen.ts @@ -0,0 +1,15 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { z } from 'zod'; + +export const zFoo = z.object({ + bar: z.number().int().optional(), + foo: z.bigint(), + id: z.string() +}); + +export const zBar = z.object({ + foo: z.number().int() +}); + +export const zPostFooResponse = zFoo; \ No newline at end of file diff --git a/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/zod/default/zod.gen.ts b/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/zod/default/zod.gen.ts index a5a37e0e2..605aa5c84 100644 --- a/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/zod/default/zod.gen.ts +++ b/packages/openapi-ts/test/__snapshots__/3.0.x/plugins/zod/default/zod.gen.ts @@ -4,23 +4,23 @@ import { z } from 'zod'; export const z400 = z.string(); -export const zCamelCaseCommentWithBreaks = z.number(); +export const zCamelCaseCommentWithBreaks = z.number().int(); -export const zCommentWithBreaks = z.number(); +export const zCommentWithBreaks = z.number().int(); -export const zCommentWithBackticks = z.number(); +export const zCommentWithBackticks = z.number().int(); -export const zCommentWithBackticksAndQuotes = z.number(); +export const zCommentWithBackticksAndQuotes = z.number().int(); -export const zCommentWithSlashes = z.number(); +export const zCommentWithSlashes = z.number().int(); -export const zCommentWithExpressionPlaceholders = z.number(); +export const zCommentWithExpressionPlaceholders = z.number().int(); -export const zCommentWithQuotes = z.number(); +export const zCommentWithQuotes = z.number().int(); -export const zCommentWithReservedCharacters = z.number(); +export const zCommentWithReservedCharacters = z.number().int(); -export const zSimpleInteger = z.number(); +export const zSimpleInteger = z.number().int(); export const zSimpleBoolean = z.boolean(); @@ -63,7 +63,7 @@ export const zEnumWithExtensions = z.unknown(); export const zEnumWithXEnumNames = z.unknown(); -export const zArrayWithNumbers = z.array(z.number()); +export const zArrayWithNumbers = z.array(z.number().int()); export const zArrayWithBooleans = z.array(z.boolean()); @@ -108,7 +108,7 @@ export const zDictionaryWithDictionary = z.object({}); export const zDictionaryWithProperties = z.object({}); export const zModelWithInteger = z.object({ - prop: z.number().optional() + prop: z.number().int().optional() }); export const zModelWithBoolean = z.object({ @@ -175,7 +175,7 @@ export const zModelWithEnumWithHyphen = z.object({ }); export const zModelWithEnumFromDescription = z.object({ - test: z.number().optional() + test: z.number().int().optional() }); export const zModelWithNestedEnums = z.object({ @@ -186,7 +186,7 @@ export const zModelWithNestedEnums = z.object({ 'Warning', 'Error' ])).optional(), - arrayWithDescription: z.array(z.number()).optional(), + arrayWithDescription: z.array(z.number().int()).optional(), 'foo_bar-enum': z.enum([ 'Success', 'Warning', @@ -211,7 +211,7 @@ export const zModelWithReference = z.object({ default: z.string().optional(), try: z.string().optional(), '@namespace.string': z.string().readonly().optional(), - '@namespace.integer': z.number().readonly().optional() + '@namespace.integer': z.number().int().readonly().optional() }).optional() }); @@ -260,7 +260,7 @@ export const zCompositionWithOneOfAnonymous = z.object({ propA: z.string().optional() }), z.string(), - z.number() + z.number().int() ]).optional() }); @@ -298,7 +298,7 @@ export const zCompositionWithAnyOfAnonymous = z.object({ propA: z.string().optional() }), z.string(), - z.number() + z.number().int() ]).optional() }); @@ -411,7 +411,7 @@ export const zModelWithProperties = z.object({ default: z.string().optional(), try: z.string().optional(), '@namespace.string': z.string().readonly().optional(), - '@namespace.integer': z.number().readonly().optional() + '@namespace.integer': z.number().int().readonly().optional() }); export const zModelWithNestedProperties = z.object({ @@ -482,8 +482,8 @@ export const zDefault = z.object({ }); export const zPageable = z.object({ - page: z.number().gte(0).optional().default(0), - size: z.number().gte(1).optional(), + page: z.number().int().gte(0).optional().default(0), + size: z.number().int().gte(1).optional(), sort: z.array(z.string()).optional() }); @@ -524,10 +524,10 @@ export const zCompositionWithOneOfAndProperties = z.intersection(z.union([ }) ]), z.object({ baz: z.union([ - z.number().gte(0), + z.number().int().gte(0), z.null() ]), - qux: z.number().gte(0) + qux: z.number().int().gte(0) })); export const zNullableObject = z.union([ @@ -628,10 +628,10 @@ export const zModelWithOneOfAndProperties = z.intersection(z.union([ zNonAsciiStringæøåÆøÅöôêÊ字符串 ]), z.object({ baz: z.union([ - z.number().gte(0), + z.number().int().gte(0), z.null() ]), - qux: z.number().gte(0) + qux: z.number().int().gte(0) })); export const zParameterSimpleParameterUnused = z.string(); @@ -689,7 +689,7 @@ export const zAdditionalPropertiesUnknownIssue3 = z.intersection(z.string(), z.o })); export const zAdditionalPropertiesIntegerIssue = z.object({ - value: z.number() + value: z.number().int() }); export const zOneOfAllOfIssue = z.union([ @@ -775,7 +775,7 @@ export const zCallWithDuplicateResponsesResponse = z.union([ export const zCallWithResponsesResponse = z.union([ z.object({ '@namespace.string': z.string().readonly().optional(), - '@namespace.integer': z.number().readonly().optional(), + '@namespace.integer': z.number().int().readonly().optional(), value: z.array(zModelWithString).readonly().optional() }), zModelThatExtends, diff --git a/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format/index.ts b/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format/index.ts new file mode 100644 index 000000000..e64537d21 --- /dev/null +++ b/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts +export * from './types.gen'; +export * from './sdk.gen'; \ No newline at end of file diff --git a/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format/sdk.gen.ts b/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format/sdk.gen.ts new file mode 100644 index 000000000..d0cf1c7c8 --- /dev/null +++ b/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format/sdk.gen.ts @@ -0,0 +1,19 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { createClient, createConfig, type Options } from '@hey-api/client-fetch'; +import type { PostFooData, PostFooResponse } from './types.gen'; +import { postFooResponseTransformer } from './transformers.gen'; +import { zPostFooResponse } from './zod.gen'; + +export const client = createClient(createConfig()); + +export const postFoo = (options?: Options) => { + return (options?.client ?? client).post({ + ...options, + responseTransformer: postFooResponseTransformer, + responseValidator: async (data) => { + return await zPostFooResponse.parseAsync(data); + }, + url: '/foo' + }); +}; \ No newline at end of file diff --git a/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format/transformers.gen.ts b/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format/transformers.gen.ts new file mode 100644 index 000000000..419690a91 --- /dev/null +++ b/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format/transformers.gen.ts @@ -0,0 +1,13 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { PostFooResponse } from './types.gen'; + +const fooSchemaResponseTransformer = (data: any) => { + data.foo = BigInt(data.foo.toString()); + return data; +}; + +export const postFooResponseTransformer = async (data: any): Promise => { + data = fooSchemaResponseTransformer(data); + return data; +}; \ No newline at end of file diff --git a/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format/types.gen.ts b/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format/types.gen.ts new file mode 100644 index 000000000..7955b8949 --- /dev/null +++ b/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format/types.gen.ts @@ -0,0 +1,28 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type Foo = { + bar?: number; + foo: BigInt; + id: string; +}; + +export type Bar = { + foo: number; + [key: string]: number; +}; + +export type PostFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type PostFooResponses = { + /** + * OK + */ + 200: Foo; +}; + +export type PostFooResponse = PostFooResponses[keyof PostFooResponses]; \ No newline at end of file diff --git a/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format/zod.gen.ts b/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format/zod.gen.ts new file mode 100644 index 000000000..30bdf8629 --- /dev/null +++ b/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format/zod.gen.ts @@ -0,0 +1,15 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { z } from 'zod'; + +export const zFoo = z.object({ + bar: z.number().int().optional(), + foo: z.bigint(), + id: z.string() +}); + +export const zBar = z.object({ + foo: z.number().int() +}); + +export const zPostFooResponse = zFoo; \ No newline at end of file diff --git a/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/zod/default/zod.gen.ts b/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/zod/default/zod.gen.ts index 3c35b83f3..9d65e14b1 100644 --- a/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/zod/default/zod.gen.ts +++ b/packages/openapi-ts/test/__snapshots__/3.1.x/plugins/zod/default/zod.gen.ts @@ -4,23 +4,23 @@ import { z } from 'zod'; export const z400 = z.string(); -export const zCamelCaseCommentWithBreaks = z.number(); +export const zCamelCaseCommentWithBreaks = z.number().int(); -export const zCommentWithBreaks = z.number(); +export const zCommentWithBreaks = z.number().int(); -export const zCommentWithBackticks = z.number(); +export const zCommentWithBackticks = z.number().int(); -export const zCommentWithBackticksAndQuotes = z.number(); +export const zCommentWithBackticksAndQuotes = z.number().int(); -export const zCommentWithSlashes = z.number(); +export const zCommentWithSlashes = z.number().int(); -export const zCommentWithExpressionPlaceholders = z.number(); +export const zCommentWithExpressionPlaceholders = z.number().int(); -export const zCommentWithQuotes = z.number(); +export const zCommentWithQuotes = z.number().int(); -export const zCommentWithReservedCharacters = z.number(); +export const zCommentWithReservedCharacters = z.number().int(); -export const zSimpleInteger = z.number(); +export const zSimpleInteger = z.number().int(); export const zSimpleBoolean = z.boolean(); @@ -63,7 +63,7 @@ export const zEnumWithExtensions = z.unknown(); export const zEnumWithXEnumNames = z.unknown(); -export const zArrayWithNumbers = z.array(z.number()); +export const zArrayWithNumbers = z.array(z.number().int()); export const zArrayWithBooleans = z.array(z.boolean()); @@ -111,7 +111,7 @@ export const zDictionaryWithDictionary = z.object({}); export const zDictionaryWithProperties = z.object({}); export const zModelWithInteger = z.object({ - prop: z.number().optional() + prop: z.number().int().optional() }); export const zModelWithBoolean = z.object({ @@ -178,7 +178,7 @@ export const zModelWithEnumWithHyphen = z.object({ }); export const zModelWithEnumFromDescription = z.object({ - test: z.number().optional() + test: z.number().int().optional() }); export const zModelWithNestedEnums = z.object({ @@ -189,7 +189,7 @@ export const zModelWithNestedEnums = z.object({ 'Warning', 'Error' ])).optional(), - arrayWithDescription: z.array(z.number()).optional(), + arrayWithDescription: z.array(z.number().int()).optional(), 'foo_bar-enum': z.enum([ 'Success', 'Warning', @@ -214,7 +214,7 @@ export const zModelWithReference = z.object({ default: z.string().optional(), try: z.string().optional(), '@namespace.string': z.string().readonly().optional(), - '@namespace.integer': z.number().readonly().optional() + '@namespace.integer': z.number().int().readonly().optional() }).optional() }); @@ -263,7 +263,7 @@ export const zCompositionWithOneOfAnonymous = z.object({ propA: z.string().optional() }), z.string(), - z.number() + z.number().int() ]).optional() }); @@ -301,7 +301,7 @@ export const zCompositionWithAnyOfAnonymous = z.object({ propA: z.string().optional() }), z.string(), - z.number() + z.number().int() ]).optional() }); @@ -406,7 +406,7 @@ export const zModelWithProperties = z.object({ default: z.string().optional(), try: z.string().optional(), '@namespace.string': z.string().readonly().optional(), - '@namespace.integer': z.number().readonly().optional() + '@namespace.integer': z.number().int().readonly().optional() }); export const zModelWithNestedProperties = z.object({ @@ -477,8 +477,8 @@ export const zDefault = z.object({ }); export const zPageable = z.object({ - page: z.number().gte(0).optional().default(0), - size: z.number().gte(1).optional(), + page: z.number().int().gte(0).optional().default(0), + size: z.number().int().gte(1).optional(), sort: z.array(z.string()).optional() }); @@ -515,10 +515,10 @@ export const zCompositionWithOneOfAndProperties = z.intersection(z.union([ }) ]), z.object({ baz: z.union([ - z.number().gte(0), + z.number().int().gte(0), z.null() ]), - qux: z.number().gte(0) + qux: z.number().int().gte(0) })); export const zNullableObject = z.union([ @@ -619,10 +619,10 @@ export const zModelWithOneOfAndProperties = z.intersection(z.union([ zNonAsciiStringæøåÆøÅöôêÊ字符串 ]), z.object({ baz: z.union([ - z.number().gte(0), + z.number().int().gte(0), z.null() ]), - qux: z.number().gte(0) + qux: z.number().int().gte(0) })); export const zParameterSimpleParameterUnused = z.string(); @@ -680,7 +680,7 @@ export const zAdditionalPropertiesUnknownIssue3 = z.intersection(z.string(), z.o })); export const zAdditionalPropertiesIntegerIssue = z.object({ - value: z.number() + value: z.number().int() }); export const zOneOfAllOfIssue = z.union([ @@ -766,7 +766,7 @@ export const zCallWithDuplicateResponsesResponse = z.union([ export const zCallWithResponsesResponse = z.union([ z.object({ '@namespace.string': z.string().readonly().optional(), - '@namespace.integer': z.number().readonly().optional(), + '@namespace.integer': z.number().int().readonly().optional(), value: z.array(zModelWithString).readonly().optional() }), zModelThatExtends, diff --git a/packages/openapi-ts/test/openapi-ts.config.ts b/packages/openapi-ts/test/openapi-ts.config.ts index 977f3e9c2..9146775d0 100644 --- a/packages/openapi-ts/test/openapi-ts.config.ts +++ b/packages/openapi-ts/test/openapi-ts.config.ts @@ -12,7 +12,7 @@ export default defineConfig({ // exclude: '^#/components/schemas/ModelWithCircularReference$', // include: // '^(#/components/schemas/import|#/paths/api/v{api-version}/simple/options)$', - path: './packages/openapi-ts/test/spec/2.0.x/security-basic.json', + path: './packages/openapi-ts/test/spec/2.0.x/type-format.yaml', // path: './test/spec/v3-transforms.json', // path: 'https://mongodb-mms-prod-build-server.s3.amazonaws.com/openapi/2caffd88277a4e27c95dcefc7e3b6a63a3b03297-v2-2023-11-15.json', // path: 'https://raw.githubusercontent.com/swagger-api/swagger-petstore/master/src/main/resources/openapi.yaml', @@ -50,7 +50,7 @@ export default defineConfig({ // @ts-ignore { dates: true, - // name: '@hey-api/transformers', + name: '@hey-api/transformers', }, // @ts-ignore { @@ -73,7 +73,7 @@ export default defineConfig({ }, // @ts-ignore { - // name: 'zod', + name: 'zod', }, ], // useOptions: false, diff --git a/packages/openapi-ts/test/plugins.test.ts b/packages/openapi-ts/test/plugins.test.ts index 64d6bdcca..2967fc168 100644 --- a/packages/openapi-ts/test/plugins.test.ts +++ b/packages/openapi-ts/test/plugins.test.ts @@ -27,8 +27,13 @@ for (const version of versions) { ): UserConfig => ({ client: '@hey-api/client-fetch', experimentalParser: true, - input: path.join(__dirname, 'spec', version, 'full.json'), ...userConfig, + input: path.join( + __dirname, + 'spec', + version, + typeof userConfig.input === 'string' ? userConfig.input : 'full.json', + ), output: path.join( outputDir, typeof userConfig.plugins[0] === 'string' @@ -229,6 +234,22 @@ for (const version of versions) { }), description: 'generate Zod schemas with Zod plugin', }, + { + config: createConfig({ + input: 'type-format.yaml', + output: 'type-format', + plugins: [ + '@hey-api/transformers', + 'zod', + { + name: '@hey-api/sdk', + transformer: true, + validator: true, + }, + ], + }), + description: 'handles various schema types and formats', + }, ]; it.each(scenarios)('$description', async ({ config }) => { diff --git a/packages/openapi-ts/test/spec/2.0.x/type-format.yaml b/packages/openapi-ts/test/spec/2.0.x/type-format.yaml new file mode 100644 index 000000000..0062f52f6 --- /dev/null +++ b/packages/openapi-ts/test/spec/2.0.x/type-format.yaml @@ -0,0 +1,37 @@ +swagger: '2.0' +info: + title: OpenAPI 2.0 type format example + version: '1' +paths: + /foo: + post: + produces: + - application/json + responses: + '200': + description: OK + schema: + $ref: '#/definitions/Foo' +definitions: + Foo: + type: object + properties: + bar: + type: integer + foo: + format: int64 + type: integer + id: + type: string + required: + - id + - foo + Bar: + type: object + required: + - foo + properties: + foo: + type: integer + additionalProperties: + type: integer diff --git a/packages/openapi-ts/test/spec/3.0.x/type-format.yaml b/packages/openapi-ts/test/spec/3.0.x/type-format.yaml new file mode 100644 index 000000000..9226a0eb4 --- /dev/null +++ b/packages/openapi-ts/test/spec/3.0.x/type-format.yaml @@ -0,0 +1,38 @@ +openapi: 3.0.4 +info: + title: OpenAPI 3.0.4 type format example + version: 1 +paths: + /foo: + post: + responses: + '200': + description: OK + content: + 'application/json': + schema: + $ref: '#/components/schemas/Foo' +components: + schemas: + Foo: + type: object + properties: + bar: + type: integer + foo: + format: int64 + type: integer + id: + type: string + required: + - id + - foo + Bar: + type: object + required: + - foo + properties: + foo: + type: integer + additionalProperties: + type: integer diff --git a/packages/openapi-ts/test/spec/3.1.x/type-format.yaml b/packages/openapi-ts/test/spec/3.1.x/type-format.yaml new file mode 100644 index 000000000..625fad0c3 --- /dev/null +++ b/packages/openapi-ts/test/spec/3.1.x/type-format.yaml @@ -0,0 +1,38 @@ +openapi: 3.1.1 +info: + title: OpenAPI 3.1.1 type format example + version: 1 +paths: + /foo: + post: + responses: + '200': + description: OK + content: + 'application/json': + schema: + $ref: '#/components/schemas/Foo' +components: + schemas: + Foo: + type: object + properties: + bar: + type: integer + foo: + format: int64 + type: integer + id: + type: string + required: + - id + - foo + Bar: + type: object + required: + - foo + properties: + foo: + type: integer + additionalProperties: + type: integer