Skip to content

Commit effbbc4

Browse files
authored
fix: Improve descriptor extension interoperability (#2232)
1 parent 366030b commit effbbc4

11 files changed

Lines changed: 1818 additions & 1496 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ protobuf.js supports service clients built from reflected service definitions. T
268268

269269
### Descriptors
270270

271-
For protobuf descriptor interoperability, see [ext/descriptor](./ext/descriptor). Note that because the internals of this package do not rely on `google/protobuf/descriptor.proto`, options are parsed and presented literally.
271+
For protobuf descriptor interoperability, see [ext/descriptor](./ext/README.md#descriptor). Note that because protobuf.js does not use `descriptor.proto` internally, options are parsed and presented literally.
272272

273273
### Content Security Policy
274274

ext/README.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# protobuf.js Extensions
2+
3+
## descriptor
4+
5+
Optional `google/protobuf/descriptor.proto` interoperability layer for reflected roots and objects.
6+
7+
```js
8+
import protobuf from "protobufjs";
9+
import descriptor from "protobufjs/ext/descriptor.js";
10+
11+
// Convert an existing root to a FileDescriptorSet message.
12+
const root = protobuf.Root.fromJSON(bundle);
13+
const set = root.toDescriptor("proto2");
14+
15+
// Encode descriptor buffers.
16+
const buffer = descriptor.FileDescriptorSet.encode(set).finish();
17+
18+
// Convert a FileDescriptorSet message or buffer back to a root.
19+
const decodedRoot = protobuf.Root.fromDescriptor(buffer);
20+
```
21+
22+
The extension requires reflection metadata and also works with `protobufjs/light.js` when schemas are loaded from JSON or otherwise provided as reflection objects.
23+
24+
Importing the extension adds `.fromDescriptor(descriptor[, syntaxOrEdition])` and `#toDescriptor([syntaxOrEdition])` methods to reflection objects and exports reflected descriptor types from `google.protobuf`. Descriptor inputs can be decoded messages, readers, or `Uint8Array`s for the corresponding descriptor message.
25+
26+
| Descriptor type | protobuf.js type | Remarks |
27+
|-------------------------------|------------------|---------|
28+
| **FileDescriptorSet** | Root | |
29+
| FileDescriptorProto | | dependencies and source info are ignored on input and not emitted |
30+
| FileOptions | | |
31+
| FileOptionsOptimizeMode | | |
32+
| SourceCodeInfo | | exported descriptor type; not mapped to reflection |
33+
| SourceCodeInfoLocation | | |
34+
| GeneratedCodeInfo | | exported descriptor type; not mapped to reflection |
35+
| GeneratedCodeInfoAnnotation | | |
36+
| **DescriptorProto** | Type | |
37+
| MessageOptions | | |
38+
| DescriptorProtoExtensionRange | | |
39+
| DescriptorProtoReservedRange | | |
40+
| **FieldDescriptorProto** | Field / MapField | map entries are reconstructed as map fields |
41+
| FieldDescriptorProtoLabel | | |
42+
| FieldDescriptorProtoType | | |
43+
| FieldOptions | | |
44+
| FieldOptionsCType | | |
45+
| FieldOptionsJSType | | |
46+
| **OneofDescriptorProto** | OneOf | |
47+
| OneofOptions | | |
48+
| **EnumDescriptorProto** | Enum | |
49+
| EnumOptions | | |
50+
| EnumValueDescriptorProto | | |
51+
| EnumValueOptions | | |
52+
| **ServiceDescriptorProto** | Service | |
53+
| ServiceOptions | | |
54+
| **MethodDescriptorProto** | Method | |
55+
| MethodOptions | | |
56+
| FeatureSet | | exported descriptor type; used by edition-aware options |
57+
| FeatureSetDefaults | | exported descriptor type |
58+
| UninterpretedOption | | exported descriptor type; options are not interpreted |
59+
| UninterpretedOptionNamePart | | |
60+
61+
Not all `descriptor.proto` features translate perfectly to a protobuf.js root. A root has only limited knowledge of packages and individual files, for example, which is compensated by guessing and generating file names.
62+
63+
The exported TypeScript interfaces can be used to reference specific descriptor message instances, for example `protobuf.Message<IDescriptorProto>`.

ext/descriptor.d.ts

Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
import * as $protobuf from "..";
2+
3+
type DescriptorInput<T> = T | $protobuf.Reader | Uint8Array;
4+
5+
declare module ".." {
6+
namespace Root {
7+
/** Creates a root from a descriptor set. */
8+
function fromDescriptor(descriptor: DescriptorInput<IFileDescriptorSet>): $protobuf.Root;
9+
}
10+
11+
interface Root {
12+
/** Converts this root to a descriptor set. */
13+
toDescriptor(edition?: string): $protobuf.Message<IFileDescriptorSet> & IFileDescriptorSet;
14+
}
15+
16+
namespace Type {
17+
/** Creates a type from a descriptor. */
18+
function fromDescriptor(descriptor: DescriptorInput<IDescriptorProto>, edition?: string, nested?: boolean): $protobuf.Type;
19+
}
20+
21+
interface Type {
22+
/** Converts this type to a descriptor. */
23+
toDescriptor(edition?: string): $protobuf.Message<IDescriptorProto> & IDescriptorProto;
24+
}
25+
26+
namespace Field {
27+
/** Creates a field from a descriptor. */
28+
function fromDescriptor(descriptor: DescriptorInput<IFieldDescriptorProto>, edition?: string, nested?: boolean): $protobuf.Field;
29+
}
30+
31+
interface Field {
32+
/** Converts this field to a descriptor. */
33+
toDescriptor(edition?: string): $protobuf.Message<IFieldDescriptorProto> & IFieldDescriptorProto;
34+
}
35+
36+
namespace Enum {
37+
/** Creates an enum from a descriptor. */
38+
function fromDescriptor(descriptor: DescriptorInput<IEnumDescriptorProto>, edition?: string, nested?: boolean): $protobuf.Enum;
39+
}
40+
41+
interface Enum {
42+
/** Converts this enum to a descriptor. */
43+
toDescriptor(): $protobuf.Message<IEnumDescriptorProto> & IEnumDescriptorProto;
44+
}
45+
46+
namespace OneOf {
47+
/** Creates a oneof from a descriptor. */
48+
function fromDescriptor(descriptor: DescriptorInput<IOneofDescriptorProto>): $protobuf.OneOf;
49+
}
50+
51+
interface OneOf {
52+
/** Converts this oneof to a descriptor. */
53+
toDescriptor(): $protobuf.Message<IOneofDescriptorProto> & IOneofDescriptorProto;
54+
}
55+
56+
namespace Service {
57+
/** Creates a service from a descriptor. */
58+
function fromDescriptor(descriptor: DescriptorInput<IServiceDescriptorProto>, edition?: string, nested?: boolean): $protobuf.Service;
59+
}
60+
61+
interface Service {
62+
/** Converts this service to a descriptor. */
63+
toDescriptor(): $protobuf.Message<IServiceDescriptorProto> & IServiceDescriptorProto;
64+
}
65+
66+
namespace Method {
67+
/** Creates a method from a descriptor. */
68+
function fromDescriptor(descriptor: DescriptorInput<IMethodDescriptorProto>): $protobuf.Method;
69+
}
70+
71+
interface Method {
72+
/** Converts this method to a descriptor. */
73+
toDescriptor(): $protobuf.Message<IMethodDescriptorProto> & IMethodDescriptorProto;
74+
}
75+
}
76+
77+
export const FileDescriptorSet: $protobuf.Type;
78+
79+
export const FileDescriptorProto: $protobuf.Type;
80+
81+
export const DescriptorProto: $protobuf.Type & {
82+
ExtensionRange: $protobuf.Type,
83+
ReservedRange: $protobuf.Type
84+
};
85+
86+
export const FieldDescriptorProto: $protobuf.Type & {
87+
Label: $protobuf.Enum,
88+
Type: $protobuf.Enum
89+
};
90+
91+
export const OneofDescriptorProto: $protobuf.Type;
92+
93+
export const EnumDescriptorProto: $protobuf.Type;
94+
95+
export const ServiceDescriptorProto: $protobuf.Type;
96+
97+
export const EnumValueDescriptorProto: $protobuf.Type;
98+
99+
export const MethodDescriptorProto: $protobuf.Type;
100+
101+
export const FileOptions: $protobuf.Type & {
102+
OptimizeMode: $protobuf.Enum
103+
};
104+
105+
export const MessageOptions: $protobuf.Type;
106+
107+
export const FieldOptions: $protobuf.Type & {
108+
CType: $protobuf.Enum,
109+
JSType: $protobuf.Enum
110+
};
111+
112+
export const OneofOptions: $protobuf.Type;
113+
114+
export const EnumOptions: $protobuf.Type;
115+
116+
export const EnumValueOptions: $protobuf.Type;
117+
118+
export const ServiceOptions: $protobuf.Type;
119+
120+
export const MethodOptions: $protobuf.Type;
121+
122+
export const FeatureSet: $protobuf.Type & {
123+
FieldPresence: $protobuf.Enum,
124+
EnumType: $protobuf.Enum,
125+
RepeatedFieldEncoding: $protobuf.Enum,
126+
Utf8Validation: $protobuf.Enum,
127+
MessageEncoding: $protobuf.Enum,
128+
JsonFormat: $protobuf.Enum,
129+
EnforceNamingStyle: $protobuf.Enum,
130+
VisibilityFeature: $protobuf.Type
131+
};
132+
133+
export const FeatureSetDefaults: $protobuf.Type & {
134+
FeatureSetEditionDefault: $protobuf.Type
135+
};
136+
137+
export const UninterpretedOption: $protobuf.Type & {
138+
NamePart: $protobuf.Type
139+
};
140+
141+
export const SourceCodeInfo: $protobuf.Type & {
142+
Location: $protobuf.Type
143+
};
144+
145+
export const GeneratedCodeInfo: $protobuf.Type & {
146+
Annotation: $protobuf.Type
147+
};
148+
149+
export interface IFileDescriptorSet {
150+
file: IFileDescriptorProto[];
151+
}
152+
153+
export interface IFileDescriptorProto {
154+
name?: string;
155+
package?: string;
156+
dependency?: any;
157+
publicDependency?: any;
158+
weakDependency?: any;
159+
messageType?: IDescriptorProto[];
160+
enumType?: IEnumDescriptorProto[];
161+
service?: IServiceDescriptorProto[];
162+
extension?: IFieldDescriptorProto[];
163+
options?: IFileOptions;
164+
sourceCodeInfo?: any;
165+
syntax?: string;
166+
edition?: IEdition;
167+
}
168+
169+
type IEdition = number;
170+
171+
export interface IFileOptions {
172+
javaPackage?: string;
173+
javaOuterClassname?: string;
174+
javaMultipleFiles?: boolean;
175+
javaGenerateEqualsAndHash?: boolean;
176+
javaStringCheckUtf8?: boolean;
177+
optimizeFor?: IFileOptionsOptimizeMode;
178+
goPackage?: string;
179+
ccGenericServices?: boolean;
180+
javaGenericServices?: boolean;
181+
pyGenericServices?: boolean;
182+
deprecated?: boolean;
183+
ccEnableArenas?: boolean;
184+
objcClassPrefix?: string;
185+
csharpNamespace?: string;
186+
}
187+
188+
type IFileOptionsOptimizeMode = number;
189+
190+
export interface IDescriptorProto {
191+
name?: string;
192+
field?: IFieldDescriptorProto[];
193+
extension?: IFieldDescriptorProto[];
194+
nestedType?: IDescriptorProto[];
195+
enumType?: IEnumDescriptorProto[];
196+
extensionRange?: IDescriptorProtoExtensionRange[];
197+
oneofDecl?: IOneofDescriptorProto[];
198+
options?: IMessageOptions;
199+
reservedRange?: IDescriptorProtoReservedRange[];
200+
reservedName?: string[];
201+
}
202+
203+
export interface IMessageOptions {
204+
mapEntry?: boolean;
205+
}
206+
207+
export interface IDescriptorProtoExtensionRange {
208+
start?: number;
209+
end?: number;
210+
}
211+
212+
export interface IDescriptorProtoReservedRange {
213+
start?: number;
214+
end?: number;
215+
}
216+
217+
export interface IFieldDescriptorProto {
218+
name?: string;
219+
number?: number;
220+
label?: IFieldDescriptorProtoLabel;
221+
type?: IFieldDescriptorProtoType;
222+
typeName?: string;
223+
extendee?: string;
224+
defaultValue?: string;
225+
oneofIndex?: number;
226+
jsonName?: any;
227+
options?: IFieldOptions;
228+
proto3Optional?: boolean;
229+
}
230+
231+
type IFieldDescriptorProtoLabel = number;
232+
233+
type IFieldDescriptorProtoType = number;
234+
235+
export interface IFieldOptions {
236+
packed?: boolean;
237+
jstype?: IFieldOptionsJSType;
238+
}
239+
240+
type IFieldOptionsJSType = number;
241+
242+
export interface IEnumDescriptorProto {
243+
name?: string;
244+
value?: IEnumValueDescriptorProto[];
245+
options?: IEnumOptions;
246+
}
247+
248+
export interface IEnumValueDescriptorProto {
249+
name?: string;
250+
number?: number;
251+
options?: IEnumValueOptions;
252+
}
253+
254+
export interface IEnumOptions {
255+
allowAlias?: boolean;
256+
deprecated?: boolean;
257+
}
258+
259+
export interface IOneofDescriptorProto {
260+
name?: string;
261+
options?: IOneofOptions;
262+
}
263+
264+
export interface IOneofOptions {
265+
features?: IFeatureSet;
266+
uninterpretedOption?: any[];
267+
}
268+
269+
export interface IEnumValueOptions {
270+
deprecated?: boolean;
271+
features?: IFeatureSet;
272+
debugRedact?: boolean;
273+
featureSupport?: any;
274+
uninterpretedOption?: any[];
275+
}
276+
277+
export interface IFeatureSet {
278+
fieldPresence?: number;
279+
enumType?: number;
280+
repeatedFieldEncoding?: number;
281+
utf8Validation?: number;
282+
messageEncoding?: number;
283+
jsonFormat?: number;
284+
enforceNamingStyle?: number;
285+
defaultSymbolVisibility?: number;
286+
}
287+
288+
export interface IServiceDescriptorProto {
289+
name?: string;
290+
method?: IMethodDescriptorProto[];
291+
options?: IServiceOptions;
292+
}
293+
294+
export interface IServiceOptions {
295+
deprecated?: boolean;
296+
}
297+
298+
export interface IMethodDescriptorProto {
299+
name?: string;
300+
inputType?: string;
301+
outputType?: string;
302+
options?: IMethodOptions;
303+
clientStreaming?: boolean;
304+
serverStreaming?: boolean;
305+
}
306+
307+
export interface IMethodOptions {
308+
deprecated?: boolean;
309+
}

0 commit comments

Comments
 (0)