Skip to content

Commit 2ae37e1

Browse files
authored
Preprocessing - x-protobuf-type override origin type (opensearch-project#297)
1 parent ffdb1f3 commit 2ae37e1

5 files changed

Lines changed: 65 additions & 41 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
1212
- Preprocessing - Add filter to not convert additionalProperties when only one key allowed ([#292](https://github.com/opensearch-project/opensearch-protobufs/pull/292))
1313
- Add HybridQuery protos ([#294](https://github.com/opensearch-project/opensearch-protobufs/pull/294))
1414
- Preprocessing - Consolidate global parameters into GlobalParams schema ([#295](https://github.com/opensearch-project/opensearch-protobufs/pull/295))
15+
- Preprocessing - x-protobuf-type override origin type ([#297](https://github.com/opensearch-project/opensearch-protobufs/pull/297))
1516

1617
### Changed
1718
- Update preprocessing for x-protobuf-excluded ([#266](https://github.com/opensearch-project/opensearch-protobufs/pull/266))

tools/proto-convert/src/GlobalParamWrapper.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,13 @@ export class GlobalParameterConsolidator {
4747
const propertyObj: any = {
4848
...param
4949
};
50+
delete propertyObj.schema;
51+
if (param.schema) {
52+
Object.assign(propertyObj, param.schema);
53+
}
5054

5155
properties[paramName] = propertyObj;
5256
addedParams.add(paramName);
53-
console.log(`Found global parameter: ${paramKey}`);
5457
}
5558
}
5659
}
Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { OpenAPIV3 } from 'openapi-types';
22
import { traverse } from './utils/OpenApiTraverser';
3+
import { resolveRef } from './utils/helper';
34
import Logger from './utils/logger';
45

56
/**
67
* VendorExtensionProcessor class:
78
* Handles processing of vendor extensions in OpenAPI specifications.
89
*/
910
export 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
}

tools/proto-convert/src/config/protobuf-generator-config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ typeMappings:
1616
object: "ObjectMap"
1717
AnyType: "ObjectMap"
1818
number: "GeneralNumber"
19+
bytes: "bytes"
1920
openapiGeneratorIgnoreList:
2021
- "README.md"

tools/proto-convert/src/utils/OpenApiTraverser.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,14 @@ export function traverse(
4747
if (components.requestBodies) {
4848
for (const requestName in components.requestBodies) {
4949
const request = components.requestBodies[requestName];
50-
if (!('$ref' in request) && request.content?.['application/json']?.schema) {
51-
const schema = request.content['application/json'].schema;
52-
if (!('$ref' in schema)) {
53-
visitors.onRequestSchema?.(schema, requestName);
54-
traverseSchema(schema, visitors);
50+
if (!('$ref' in request)) {
51+
for (const contentType in request.content || {}) {
52+
const content = (request.content as any)?.[contentType];
53+
if (content?.schema && !('$ref' in content.schema)) {
54+
const schema = content.schema;
55+
visitors.onRequestSchema?.(schema, requestName);
56+
traverseSchema(schema as OpenAPIV3.SchemaObject, visitors);
57+
}
5558
}
5659
}
5760
}

0 commit comments

Comments
 (0)