@@ -3,15 +3,25 @@ import { toPascal } from '@devup-api/utils'
33import type { OpenAPIV3_1 } from 'openapi-types'
44import { convertCase } from './convert-case'
55import {
6+ areAllPropertiesOptional ,
67 extractParameters ,
78 extractRequestBody ,
89 formatTypeValue ,
910} from './generate-schema'
11+ import { wrapInterfaceKeyGuard } from './wrap-interface-key-guard'
1012
11- interface EndpointDefinition {
12- params ?: Record < string , unknown >
13+ export type ParameterDefinition = Omit <
14+ OpenAPIV3_1 . ParameterObject ,
15+ 'schema'
16+ > & {
17+ type : unknown
18+ default ?: unknown
19+ }
20+
21+ export interface EndpointDefinition {
22+ params ?: Record < string , ParameterDefinition >
1323 body ?: unknown
14- query ?: Record < string , unknown >
24+ query ?: Record < string , ParameterDefinition >
1525}
1626
1727export function generateInterface (
@@ -52,13 +62,13 @@ export function generateInterface(
5262 )
5363
5464 // Apply case conversion to parameter names
55- const convertedPathParams : Record < string , unknown > = { }
65+ const convertedPathParams : Record < string , ParameterDefinition > = { }
5666 for ( const [ key , value ] of Object . entries ( pathParams ) ) {
5767 const convertedKey = convertCase ( key , convertCaseType )
5868 convertedPathParams [ convertedKey ] = value
5969 }
6070
61- const convertedQueryParams : Record < string , unknown > = { }
71+ const convertedQueryParams : Record < string , ParameterDefinition > = { }
6272 for ( const [ key , value ] of Object . entries ( queryParams ) ) {
6373 const convertedKey = convertCase ( key , convertCaseType )
6474 convertedQueryParams [ convertedKey ] = value
@@ -78,32 +88,19 @@ export function generateInterface(
7888 }
7989
8090 // Generate path key (normalize path by replacing {param} with converted param and removing slashes)
81- const normalizedPath = path
82- . replace ( / \{ ( [ ^ } ] + ) \} / g, ( _ , param ) => {
83- // Convert param name based on case type
84- return convertCase ( param , convertCaseType )
85- } )
86- . replace ( / ^ \/ / , '' )
87- . replace ( / \/ / g, '' )
88- const pathKey = convertCase ( normalizedPath , convertCaseType )
91+ const normalizedPath = path . replace ( / \{ ( [ ^ } ] + ) \} / g, ( _ , param ) => {
92+ // Convert param name based on case type
93+ return `{${ convertCase ( param , convertCaseType ) } }`
94+ } )
8995
96+ endpoints [ method ] [ normalizedPath ] = endpoint
9097 if ( operation . operationId ) {
9198 // If operationId exists, create both operationId and path keys
9299 const operationIdKey = convertCase (
93100 operation . operationId ,
94101 convertCaseType ,
95102 )
96103 endpoints [ method ] [ operationIdKey ] = endpoint
97-
98- // Add path key if different from operationId key
99- if ( pathKey && pathKey !== operationIdKey ) {
100- endpoints [ method ] [ pathKey ] = endpoint
101- }
102- } else {
103- // If operationId doesn't exist, only use path key
104- if ( pathKey ) {
105- endpoints [ method ] [ pathKey ] = endpoint
106- }
107104 }
108105 }
109106 }
@@ -114,16 +111,27 @@ export function generateInterface(
114111 . flatMap ( ( [ method , value ] ) => {
115112 const entries = Object . entries ( value )
116113 if ( entries . length > 0 ) {
114+ const interfaceEntries = entries
115+ . map ( ( [ key , endpointValue ] ) => {
116+ const formattedValue = formatTypeValue ( endpointValue , 2 )
117+ // Check if all properties in endpointValue are optional
118+ const allOptional =
119+ typeof endpointValue === 'object' &&
120+ endpointValue !== null &&
121+ ! Array . isArray ( endpointValue ) &&
122+ areAllPropertiesOptional ( endpointValue as Record < string , unknown > )
123+ const optionalMarker = allOptional ? '?' : ''
124+ return ` ${ wrapInterfaceKeyGuard ( key ) } ${ optionalMarker } : ${ formattedValue } `
125+ } )
126+ . join ( ';\n' )
127+
117128 return [
118- `interface Devup${ toPascal ( method ) } ApiStruct{${ entries
119- . map ( ( [ key , value ] ) => {
120- return `${ key } :${ formatTypeValue ( value ) } `
121- } )
122- . join ( ';' ) } }`,
129+ ` interface Devup${ toPascal ( method ) } ApiStruct {\n${ interfaceEntries } ;\n }` ,
123130 ]
124131 }
125132 return [ ]
126133 } )
127- . flat ( )
128- return `import "@devup-api/fetch";declare module "@devup-api/fetch"{${ interfaceContent . join ( '' ) } }`
134+ . join ( '\n' )
135+
136+ return `import "@devup-api/fetch";\n\ndeclare module "@devup-api/fetch" {\n${ interfaceContent } \n}`
129137}
0 commit comments