1- import type { StatementInterface } from '@genapi/shared'
1+ import type { ApiPipeline , StatementInterface } from '@genapi/shared'
22import type { Definitions , Schema } from 'openapi-specification-types'
33import { inject } from '@genapi/shared'
44import { parseSchemaType } from '../parses'
@@ -9,17 +9,33 @@ export interface DefinitionTransformOptions {
99}
1010
1111export function transformDefinitions ( definitions : Definitions ) {
12- const { interfaces } = inject ( )
12+ const { interfaces, configRead } = inject ( )
13+ const config = ( configRead ?. config || { } ) as ApiPipeline . Config
14+ const transformDef = config . transform ?. definition
15+ const patchDefinitions = config . patch ?. definitions || { }
1316
1417 for ( const [ name , definition ] of Object . entries ( definitions ) ) {
1518 const { properties = { } } = definition
1619
20+ const interfaceName = varName ( name )
21+
1722 interfaces . push ( {
1823 export : true ,
19- name : varName ( name ) ,
24+ name : interfaceName ,
2025 properties : Object . keys ( properties ) . map ( name => defToFields ( name , properties [ name ] ) ) ,
2126 } )
2227
28+ // Build a structural type string for this definition so `transform.definition`
29+ // and `patch.definitions` can operate on it.
30+ const baseType = buildDefinitionType ( interfaceName , properties )
31+ applyDefinitionTransformsAndPatches ( {
32+ baseName : interfaceName ,
33+ baseType,
34+ configRead,
35+ transformDef,
36+ patchDefinitions,
37+ } )
38+
2339 function defToFields ( name : string , propertie : Schema ) {
2440 const required = Array . isArray ( definition ?. required ) ? definition . required . includes ( name ) : undefined
2541 const description = propertie . description ? `@description ${ propertie . description } ` : undefined
@@ -32,3 +48,90 @@ export function transformDefinitions(definitions: Definitions) {
3248 }
3349 }
3450}
51+
52+ function buildDefinitionType ( interfaceName : string , properties : Definitions [ string ] [ 'properties' ] = { } ) {
53+ const entries = Object . entries ( properties )
54+ if ( entries . length === 0 )
55+ return 'any'
56+
57+ const fields = entries . map ( ( [ propName , schema ] ) => {
58+ const type = parseSchemaType ( schema as Schema )
59+ return `${ varFiled ( propName ) } : ${ type } `
60+ } )
61+
62+ return `{ ${ fields . join ( ', ' ) } }`
63+ }
64+
65+ interface DefinitionPatchContext {
66+ baseName : string
67+ baseType : string
68+ configRead : ApiPipeline . ConfigRead
69+ transformDef ?: ( name : string , type : string ) => ApiPipeline . Definition
70+ patchDefinitions : Record < string , ApiPipeline . Definition >
71+ }
72+
73+ /**
74+ * Applies `config.transform.definition` (global) and `config.patch.definitions` (static)
75+ * to a single Swagger/OpenAPI definition.
76+ *
77+ * Semantics:
78+ * - Rename only: `'UserDto': 'User'` → `export type User = UserDto`
79+ * - Rename + override type:
80+ * `'SessionDto': { name: 'Session', type: '{ name: string }' }`
81+ * → `export type Session = { name: string }`
82+ *
83+ * The original interface (e.g. `UserDto`) is preserved so existing references
84+ * from schemas remain valid; patches add friendly alias types on top.
85+ */
86+ function applyDefinitionTransformsAndPatches ( ctx : DefinitionPatchContext ) {
87+ const {
88+ baseName,
89+ baseType,
90+ configRead,
91+ transformDef,
92+ patchDefinitions,
93+ } = ctx
94+
95+ let aliasName = baseName
96+ let aliasType = baseType
97+
98+ function applyPatch ( patch ?: ApiPipeline . Definition ) {
99+ if ( ! patch )
100+ return
101+
102+ if ( typeof patch === 'string' ) {
103+ aliasName = patch
104+ return
105+ }
106+
107+ if ( patch . name )
108+ aliasName = patch . name
109+ if ( patch . type )
110+ aliasType = patch . type
111+ }
112+
113+ // Global transform first.
114+ if ( transformDef ) {
115+ const patch = transformDef ( baseName , baseType )
116+ applyPatch ( patch )
117+ }
118+
119+ // Then static patch; allow matching by original or transformed name.
120+ const staticPatch = patchDefinitions [ baseName ] ?? patchDefinitions [ aliasName ]
121+ applyPatch ( staticPatch )
122+
123+ const hasNameChange = aliasName !== baseName
124+ const hasTypeChange = aliasType !== baseType
125+
126+ if ( ! hasNameChange && ! hasTypeChange )
127+ return
128+
129+ const aliasValue = hasTypeChange ? aliasType : baseName
130+
131+ configRead . graphs . typings = configRead . graphs . typings || [ ]
132+ configRead . graphs . typings . push ( {
133+ export : true ,
134+ name : aliasName ,
135+ value : aliasValue ,
136+ } )
137+ }
0 commit comments