Skip to content

Commit defd975

Browse files
lucy66hwkarenyrx
andauthored
Proto Convert Tool Handle vendor extension <x-protobuf-excluded> (opensearch-project#192)
* Handle grpc related vender extension Signed-off-by: xil <fridalu66@gmail.com> * changelog Signed-off-by: xil <fridalu66@gmail.com> * rename x-grpc-removed to x-protobuf-excluded Signed-off-by: xil <fridalu66@gmail.com> * rename x-protobuf-excluded in changelog Signed-off-by: Karen X <karenxyr@gmail.com> --------- Signed-off-by: xil <fridalu66@gmail.com> Signed-off-by: lucy66hw <fridalu66@gmail.com> Signed-off-by: Karen X <karenxyr@gmail.com> Co-authored-by: Karen X <karenxyr@gmail.com>
1 parent 317f5c9 commit defd975

5 files changed

Lines changed: 108 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
66
### Added
77
- Proto Convertion tooling support null value ([#189](https://github.com/opensearch-project/opensearch-protobufs/pull/189))
88
- Add `geo_distance` and `geo_bounding_box` to QueryContainer. ([#188](https://github.com/opensearch-project/opensearch-protobufs/pull/188))
9+
- proto Conversion Tooling support vendor extension `x-protobuf-excluded` ([#192](https://github.com/opensearch-project/opensearch-protobufs/pull/192))
910

1011
### Changed
1112
- update `score` protobuf type ([#179](https://github.com/opensearch-project/opensearch-protobufs/pull/179))

tools/proto-convert/src/PreProcessing.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Sanitizer } from './Sanitizer';
55
import Logger from './utils/logger';
66
import * as path from 'path';
77
import {SchemaModifier} from "./SchemaModifier";
8+
import {VendorExtensionProcessor} from "./VendorExtensionProcessor";
89
import type {OpenAPIV3} from "openapi-types";
910

1011
let config_filtered_path: string[] | undefined;
@@ -48,7 +49,8 @@ try {
4849
const original_spec = read_yaml(opts.input)
4950
const filtered_spec = new Filter().filter_spec(original_spec, opts.filtered_path);
5051
const sanitized_spec = new Sanitizer().sanitize(filtered_spec);
51-
const schema_modified_spec = new SchemaModifier(sanitized_spec).modify();
52+
const vendor_processed_spec = new VendorExtensionProcessor(sanitized_spec, logger).process();
53+
const schema_modified_spec = new SchemaModifier(vendor_processed_spec, logger).modify();
5254
write_yaml(opts.output, schema_modified_spec);
5355

5456
} catch (err) {

tools/proto-convert/src/Sanitizer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export class Sanitizer {
7272
onRequestSchema: (schema) => this.sanitize_schema(schema),
7373
onResponseSchema: (schema) => this.sanitize_schema(schema),
7474
onParameter: (param, _paramName) => {
75-
if (param.name.startsWith('_')) {
75+
if (!('$ref' in param) && param.name && param.name.startsWith('_')) {
7676
param.name = `underscore${param.name}`;
7777
}
7878
}

tools/proto-convert/src/SchemaModifier.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export class SchemaModifier {
6262
if (schema.oneOf) {
6363
const enumValues: string[] = [];
6464
let hasStringWithConst = false;
65-
65+
6666
// check if have string with const
6767
for (const item of schema.oneOf) {
6868
if (item && !('$ref' in item) && item.type === 'string' && 'const' in item) {
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import { OpenAPIV3 } from 'openapi-types';
2+
import { traverse } from './utils/OpenApiTraverser';
3+
import Logger from './utils/logger';
4+
5+
/**
6+
* VendorExtensionProcessor class:
7+
* Handles processing of vendor extensions in OpenAPI specifications.
8+
*/
9+
export class VendorExtensionProcessor {
10+
private static readonly GRPC_REMOVED_EXTENSION = 'x-protobuf-excluded';
11+
12+
private root: OpenAPIV3.Document;
13+
private logger: Logger;
14+
15+
constructor(root: OpenAPIV3.Document, logger: Logger = new Logger()) {
16+
this.root = root;
17+
this.logger = logger;
18+
}
19+
20+
/**
21+
* Process the spec by pruning anything marked with x-protobuf-excluded
22+
* Direct path-level handling + traverse for schemas only
23+
*/
24+
public process(): OpenAPIV3.Document {
25+
this.logger.info(`Processing vendor extensions (${VendorExtensionProcessor.GRPC_REMOVED_EXTENSION})...`);
26+
27+
this.removeGrpcRemovedFromPaths();
28+
traverse(this.root, {
29+
onSchema: (schema: any, name: string) => {
30+
if ('$ref' in schema) return;
31+
this.removeGrpcRemovedProperties(schema);
32+
},
33+
onResponseSchema: (schema: any, name: string) => {
34+
this.removeGrpcRemovedProperties(schema);
35+
},
36+
onRequestSchema: (schema: any, name: string) => {
37+
this.removeGrpcRemovedProperties(schema);
38+
}
39+
});
40+
41+
return this.root;
42+
}
43+
44+
private hasGrpcRemoved(item: any): boolean {
45+
return item && typeof item === 'object' && VendorExtensionProcessor.GRPC_REMOVED_EXTENSION in item && item[VendorExtensionProcessor.GRPC_REMOVED_EXTENSION] === true;
46+
}
47+
48+
/**
49+
* Remove x-protobuf-excluded items from path-level elements directly
50+
*/
51+
private removeGrpcRemovedFromPaths(): void {
52+
if (!this.root.paths) return;
53+
54+
for (const pathKey in this.root.paths) {
55+
const pathItem = this.root.paths[pathKey];
56+
if (!pathItem || typeof pathItem !== 'object' || '$ref' in pathItem) continue;
57+
58+
// Handle operations
59+
for (const method in pathItem) {
60+
if (method === 'parameters' || method === '$ref' || method === 'summary' ||
61+
method === 'description' || method === 'servers') continue;
62+
63+
const operation = (pathItem as any)[method];
64+
if (!operation || typeof operation !== 'object') continue;
65+
66+
// Remove parameters with x-protobuf-excluded
67+
if (Array.isArray(operation.parameters)) {
68+
const originalLength = operation.parameters.length;
69+
operation.parameters = operation.parameters.filter((p: any) => !this.hasGrpcRemoved(p));
70+
const removedCount = originalLength - operation.parameters.length;
71+
if (removedCount > 0) {
72+
this.logger.info(`Removed ${removedCount} parameter(s) from ${method.toUpperCase()} ${pathKey} (${VendorExtensionProcessor.GRPC_REMOVED_EXTENSION})`);
73+
}
74+
}
75+
76+
// Remove responses with x-protobuf-excluded
77+
if (operation.responses) {
78+
for (const status in operation.responses) {
79+
if (this.hasGrpcRemoved(operation.responses[status])) {
80+
delete operation.responses[status];
81+
this.logger.info(`Removed response ${status} from ${method.toUpperCase()} ${pathKey} (${VendorExtensionProcessor.GRPC_REMOVED_EXTENSION})`);
82+
}
83+
}
84+
}
85+
}
86+
}
87+
}
88+
89+
private removeGrpcRemovedProperties(schema: OpenAPIV3.SchemaObject): void {
90+
if (!schema?.properties) return;
91+
92+
for (const prop in schema.properties) {
93+
const propSchema = schema.properties[prop];
94+
if (propSchema && typeof propSchema === 'object' && !('$ref' in propSchema)) {
95+
if (this.hasGrpcRemoved(propSchema)) {
96+
delete schema.properties[prop];
97+
this.logger.info(`Removed schema property ${prop} (${VendorExtensionProcessor.GRPC_REMOVED_EXTENSION})`);
98+
}
99+
}
100+
}
101+
}
102+
}

0 commit comments

Comments
 (0)