Skip to content

Commit 81a6586

Browse files
committed
feat: enhance parser with configuration reading and definition renaming support, improve type handling in transformDefinitions and parseSchemaType functions
1 parent 56b9086 commit 81a6586

6 files changed

Lines changed: 565 additions & 29 deletions

File tree

packages/parser/src/create-parser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export function createParser(pathHandler: PathHandler) {
3434
const interfaces: StatementInterface[] = []
3535
const functions: StatementFunction[] = []
3636

37-
provide({ interfaces, functions })
37+
provide({ interfaces, functions, configRead })
3838
transformBaseURL(source)
3939
if (source.definitions)
4040
transformDefinitions(source.definitions)

packages/parser/src/parses/schema.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,23 @@ function schemaRequired(schema: SchemaLike, field?: string): boolean {
2121
* @param propertie
2222
*/
2323
export function parseSchemaType(propertie: SchemaWithAllOf): string {
24-
const { interfaces = [] } = inject()
24+
const { interfaces = [], configRead } = inject()
2525

2626
if (!propertie)
2727
return 'any'
28-
if (propertie.originalRef)
29-
return varName(propertie.originalRef)
28+
if (propertie.originalRef) {
29+
const originalName = varName(propertie.originalRef)
30+
// Check if this definition was renamed
31+
const nameMapping = (configRead?.config as any)?.__definitionNameMapping
32+
return nameMapping?.[originalName] ?? originalName
33+
}
3034

31-
if (propertie.$ref)
32-
return varName(useRefMap(propertie.$ref))
35+
if (propertie.$ref) {
36+
const originalName = varName(useRefMap(propertie.$ref))
37+
// Check if this definition was renamed
38+
const nameMapping = (configRead?.config as any)?.__definitionNameMapping
39+
return nameMapping?.[originalName] ?? originalName
40+
}
3341

3442
// Handle allOf: merge multiple schemas, typically used for generic response types
3543
if (propertie.allOf) {

packages/parser/src/transform/definitions.ts

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,41 @@ export function transformDefinitions(definitions: Definitions) {
1414
const transformDef = config.transform?.definition
1515
const patchDefinitions = config.patch?.definitions || {}
1616

17+
// Map from original interface name to renamed interface name
18+
// Used by parseSchemaType to resolve $ref to renamed interfaces
19+
const nameMapping: Record<string, string> = {}
20+
1721
for (const [name, definition] of Object.entries(definitions)) {
1822
const { properties = {} } = definition
1923

2024
const interfaceName = varName(name)
2125

22-
interfaces.push({
23-
export: true,
24-
name: interfaceName,
25-
properties: Object.keys(properties).map(name => defToFields(name, properties[name])),
26-
})
27-
2826
// Build a structural type string for this definition so `transform.definition`
2927
// and `patch.definitions` can operate on it.
3028
const baseType = buildDefinitionType(interfaceName, properties)
31-
applyDefinitionTransformsAndPatches({
29+
const patchResult = applyDefinitionTransformsAndPatches({
3230
baseName: interfaceName,
3331
baseType,
3432
configRead,
3533
transformDef,
3634
patchDefinitions,
3735
})
3836

37+
// If patch only renames (no type override), use the new name for the interface
38+
// Otherwise, keep original name and create type alias
39+
const finalInterfaceName = patchResult.shouldRename ? patchResult.aliasName : interfaceName
40+
41+
// Store mapping for parseSchemaType to use
42+
if (finalInterfaceName !== interfaceName) {
43+
nameMapping[interfaceName] = finalInterfaceName
44+
}
45+
46+
interfaces.push({
47+
export: true,
48+
name: finalInterfaceName,
49+
properties: Object.keys(properties).map(name => defToFields(name, properties[name])),
50+
})
51+
3952
function defToFields(name: string, propertie: Schema) {
4053
const required = Array.isArray(definition?.required) ? definition.required.includes(name) : undefined
4154
const description = propertie.description ? `@description ${propertie.description}` : undefined
@@ -47,6 +60,11 @@ export function transformDefinitions(definitions: Definitions) {
4760
}
4861
}
4962
}
63+
64+
// Store name mapping in config for parseSchemaType to use
65+
if (configRead?.config) {
66+
(configRead.config as any).__definitionNameMapping = nameMapping
67+
}
5068
}
5169

5270
function buildDefinitionType(interfaceName: string, properties: Definitions[string]['properties'] = {}) {
@@ -75,13 +93,14 @@ interface DefinitionPatchContext {
7593
* to a single Swagger/OpenAPI definition.
7694
*
7795
* Semantics:
78-
* - Rename only: `'UserDto': 'User'` → `export type User = UserDto`
96+
* - Rename only (string or name only): `'Order': 'OrderDTO'` → interface renamed to `OrderDTO`
7997
* - Rename + override type:
8098
* `'SessionDto': { name: 'Session', type: '{ name: string }' }`
81-
* → `export type Session = { name: string }`
99+
* → interface stays `SessionDto`, creates `export type Session = { name: string }`
82100
*
83-
* The original interface (e.g. `UserDto`) is preserved so existing references
84-
* from schemas remain valid; patches add friendly alias types on top.
101+
* When only renaming, the interface itself is renamed so all references automatically
102+
* use the new name. When type is overridden, the original interface is preserved
103+
* and a type alias is created.
85104
*/
86105
function applyDefinitionTransformsAndPatches(ctx: DefinitionPatchContext) {
87106
const {
@@ -94,6 +113,7 @@ function applyDefinitionTransformsAndPatches(ctx: DefinitionPatchContext) {
94113

95114
let aliasName = baseName
96115
let aliasType = baseType
116+
let hasTypeOverride = false
97117

98118
function applyPatch(patch?: ApiPipeline.Definition) {
99119
if (!patch)
@@ -106,8 +126,10 @@ function applyDefinitionTransformsAndPatches(ctx: DefinitionPatchContext) {
106126

107127
if (patch.name)
108128
aliasName = patch.name
109-
if (patch.type)
129+
if (patch.type) {
110130
aliasType = patch.type
131+
hasTypeOverride = true
132+
}
111133
}
112134

113135
// Global transform first.
@@ -124,14 +146,22 @@ function applyDefinitionTransformsAndPatches(ctx: DefinitionPatchContext) {
124146
const hasTypeChange = aliasType !== baseType
125147

126148
if (!hasNameChange && !hasTypeChange)
127-
return
149+
return { aliasName: baseName, shouldRename: false }
128150

129-
const aliasValue = hasTypeChange ? aliasType : baseName
151+
// If only renaming (no type override), rename the interface itself
152+
// Otherwise, create a type alias
153+
const shouldRename = hasNameChange && !hasTypeOverride
130154

131-
configRead.graphs.typings = configRead.graphs.typings || []
132-
configRead.graphs.typings.push({
133-
export: true,
134-
name: aliasName,
135-
value: aliasValue,
136-
})
155+
if (!shouldRename) {
156+
// Create type alias when type is overridden
157+
const aliasValue = hasTypeChange ? aliasType : baseName
158+
configRead.graphs.typings = configRead.graphs.typings || []
159+
configRead.graphs.typings.push({
160+
export: true,
161+
name: aliasName,
162+
value: aliasValue,
163+
})
164+
}
165+
166+
return { aliasName, shouldRename }
137167
}

0 commit comments

Comments
 (0)