11import { OpenAPIV3 } from 'openapi-types' ;
22import { traverse } from './utils/OpenApiTraverser' ;
3+ import { resolveRef } from './utils/helper' ;
34import Logger from './utils/logger' ;
45
56/**
67 * VendorExtensionProcessor class:
78 * Handles processing of vendor extensions in OpenAPI specifications.
89 */
910export class VendorExtensionProcessor {
10- private static readonly GRPC_REMOVED_EXTENSION = 'x-protobuf-excluded' ;
11+ private static readonly PROTOBUF_EXCLUDED_EXTENSION = 'x-protobuf-excluded' ;
12+ private static readonly PROTOBUF_TYPE_EXTENSION = 'x-protobuf-type' ;
1113
1214 private root : OpenAPIV3 . Document ;
1315 private logger : Logger ;
@@ -22,62 +24,50 @@ export class VendorExtensionProcessor {
2224 * Direct path-level handling + traverse for schemas only
2325 */
2426 public process ( ) : OpenAPIV3 . Document {
25- this . logger . info ( `Processing vendor extensions (${ VendorExtensionProcessor . GRPC_REMOVED_EXTENSION } )...` ) ;
2627
27- this . removeGrpcRemovedFromPaths ( ) ;
28+ this . removeProtobufExcludedFromPaths ( ) ;
2829 traverse ( this . root , {
2930 onSchema : ( schema : any , name : string ) => {
3031 if ( '$ref' in schema ) return ;
31- this . removeGrpcRemovedProperties ( schema ) ;
32+ this . removeProtobufExcludedProperties ( schema ) ;
33+ this . applyTypeOverride ( schema ) ;
3234 } ,
3335 onResponseSchema : ( schema : any , name : string ) => {
34- this . removeGrpcRemovedProperties ( schema ) ;
36+ this . removeProtobufExcludedProperties ( schema ) ;
37+ this . applyTypeOverride ( schema ) ;
3538 } ,
3639 onRequestSchema : ( schema : any , name : string ) => {
37- this . removeGrpcRemovedProperties ( schema ) ;
40+ this . removeProtobufExcludedProperties ( schema ) ;
41+ this . applyTypeOverride ( schema ) ;
42+ } ,
43+ onSchemaProperty : ( schema : any , name : string ) => {
44+ this . applyTypeOverride ( schema ) ;
3845 }
3946 } ) ;
4047
4148 return this . root ;
4249 }
4350
44- private hasGrpcRemoved ( item : any ) : boolean {
51+ private hasProtobufExcluded ( item : any ) : boolean {
4552 if ( ! item || typeof item !== 'object' ) return false ;
4653
47- if ( VendorExtensionProcessor . GRPC_REMOVED_EXTENSION in item && ! ! item [ VendorExtensionProcessor . GRPC_REMOVED_EXTENSION ] ) {
54+ if ( VendorExtensionProcessor . PROTOBUF_EXCLUDED_EXTENSION in item && ! ! item [ VendorExtensionProcessor . PROTOBUF_EXCLUDED_EXTENSION ] ) {
4855 return true ;
4956 }
5057 if ( '$ref' in item && typeof item . $ref === 'string' ) {
51- const resolved = this . resolveRef ( item . $ref ) ;
52- if ( resolved && VendorExtensionProcessor . GRPC_REMOVED_EXTENSION in resolved && ! ! resolved [ VendorExtensionProcessor . GRPC_REMOVED_EXTENSION ] ) {
58+ const resolved = resolveRef ( item . $ref , this . root ) ;
59+ if ( resolved && VendorExtensionProcessor . PROTOBUF_EXCLUDED_EXTENSION in resolved && ! ! resolved [ VendorExtensionProcessor . PROTOBUF_EXCLUDED_EXTENSION ] ) {
5360 return true ;
5461 }
5562 }
5663
5764 return false ;
5865 }
5966
60- /**
61- * Resolve a $ref string to the actual object
62- */
63- private resolveRef ( ref : string ) : any {
64- if ( ! ref . startsWith ( '#/' ) ) return null ;
65-
66- const parts = ref . substring ( 2 ) . split ( '/' ) ;
67- let current : any = this . root ;
68-
69- for ( const part of parts ) {
70- if ( ! current || typeof current !== 'object' ) return null ;
71- current = current [ part ] ;
72- }
73-
74- return current ;
75- }
76-
7767 /**
7868 * Remove x-protobuf-excluded items from path-level elements directly
7969 */
80- private removeGrpcRemovedFromPaths ( ) : void {
70+ private removeProtobufExcludedFromPaths ( ) : void {
8171 if ( ! this . root . paths ) return ;
8272
8373 for ( const pathKey in this . root . paths ) {
@@ -95,37 +85,63 @@ export class VendorExtensionProcessor {
9585 // Remove parameters with x-protobuf-excluded
9686 if ( Array . isArray ( operation . parameters ) ) {
9787 const originalLength = operation . parameters . length ;
98- operation . parameters = operation . parameters . filter ( ( p : any ) => ! this . hasGrpcRemoved ( p ) ) ;
88+ operation . parameters = operation . parameters . filter ( ( p : any ) => ! this . hasProtobufExcluded ( p ) ) ;
9989 const removedCount = originalLength - operation . parameters . length ;
10090 if ( removedCount > 0 ) {
101- this . logger . info ( `Removed ${ removedCount } parameter(s) from ${ method . toUpperCase ( ) } ${ pathKey } (${ VendorExtensionProcessor . GRPC_REMOVED_EXTENSION } )` ) ;
91+ this . logger . info ( `Removed ${ removedCount } parameter(s) from ${ method . toUpperCase ( ) } ${ pathKey } (${ VendorExtensionProcessor . PROTOBUF_EXCLUDED_EXTENSION } )` ) ;
10292 }
10393 }
10494
10595 // Remove responses with x-protobuf-excluded
10696 if ( operation . responses ) {
10797 for ( const status in operation . responses ) {
108- if ( this . hasGrpcRemoved ( operation . responses [ status ] ) ) {
98+ if ( this . hasProtobufExcluded ( operation . responses [ status ] ) ) {
10999 delete operation . responses [ status ] ;
110- this . logger . info ( `Removed response ${ status } from ${ method . toUpperCase ( ) } ${ pathKey } (${ VendorExtensionProcessor . GRPC_REMOVED_EXTENSION } )` ) ;
100+ this . logger . info ( `Removed response ${ status } from ${ method . toUpperCase ( ) } ${ pathKey } (${ VendorExtensionProcessor . PROTOBUF_EXCLUDED_EXTENSION } )` ) ;
111101 }
112102 }
113103 }
114104 }
115105 }
116106 }
117107
118- private removeGrpcRemovedProperties ( schema : OpenAPIV3 . SchemaObject ) : void {
108+ private removeProtobufExcludedProperties ( schema : OpenAPIV3 . SchemaObject ) : void {
119109 if ( ! schema ?. properties ) return ;
120110
121111 for ( const prop in schema . properties ) {
122112 const propSchema = schema . properties [ prop ] ;
123113 if ( propSchema && typeof propSchema === 'object' && ! ( '$ref' in propSchema ) ) {
124- if ( this . hasGrpcRemoved ( propSchema ) ) {
114+ if ( this . hasProtobufExcluded ( propSchema ) ) {
125115 delete schema . properties [ prop ] ;
126- this . logger . info ( `Removed schema property ${ prop } (${ VendorExtensionProcessor . GRPC_REMOVED_EXTENSION } )` ) ;
116+ this . logger . info ( `Removed schema property ${ prop } (${ VendorExtensionProcessor . PROTOBUF_EXCLUDED_EXTENSION } )` ) ;
127117 }
128118 }
129119 }
130120 }
121+
122+ /**
123+ * Apply type override to a schema if it has x-protobuf-type
124+ */
125+ private applyTypeOverride ( schema : any ) : void {
126+ if ( ! schema ) return ;
127+
128+ if ( VendorExtensionProcessor . PROTOBUF_TYPE_EXTENSION in schema ) {
129+ const protoType = schema [ VendorExtensionProcessor . PROTOBUF_TYPE_EXTENSION ] ;
130+
131+ // Clear structural properties that might conflict
132+ if ( '$ref' in schema ) {
133+ delete schema . $ref ;
134+ }
135+ if ( 'properties' in schema ) {
136+ delete schema . properties ;
137+ }
138+ if ( 'additionalProperties' in schema ) {
139+ delete schema . additionalProperties ;
140+ }
141+
142+ schema . type = protoType ;
143+ delete schema [ VendorExtensionProcessor . PROTOBUF_TYPE_EXTENSION ] ;
144+ this . logger . info ( `Applied ${ VendorExtensionProcessor . PROTOBUF_TYPE_EXTENSION } : ${ protoType } ` ) ;
145+ }
146+ }
131147}
0 commit comments