Skip to content

Commit

Permalink
feat: extensions (#808)
Browse files Browse the repository at this point in the history
* feat: extensions

* docs: outputExtensions=true
  • Loading branch information
davidzeng0 authored Apr 1, 2023
1 parent 8fe2c28 commit f956128
Show file tree
Hide file tree
Showing 10 changed files with 1,119 additions and 53 deletions.
7 changes: 6 additions & 1 deletion README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ Generated code will be placed in the Gradle build directory.

- With `--ts_proto_opt=useJsonWireFormat=true`, the generated code will reflect the JSON representation of Protobuf messages.

Requires `onlyTypes=true`. Implies `useDate=string` and `stringEnums=true`. This option is to generate types that can be directly used with marshalling/unmarshalling Protobuf messages serialized as JSON.
Requires `onlyTypes=true`. Implies `useDate=string` and `stringEnums=true`. This option is to generate types that can be directly used with marshalling/unmarshalling Protobuf messages serialized as JSON.
You may also want to set `useOptionals=all`, as gRPC gateways are not required to send default value for scalar values.

- With `--ts_proto_opt=useNumericEnumForJson=true`, the JSON converter (`toJSON`) will encode enum values as int, rather than a string literal.
Expand Down Expand Up @@ -502,6 +502,11 @@ Generated code will be placed in the Gradle build directory.

by default this is enabled which would generate a type of `Box_Element_Image_Alignment`. By disabling this option the type that is generated would be `BoxElementImageAlignment`.

- With `--ts_proto_opt=outputExtensions=true`, the generated code will include proto2 extensions

Extension encode/decode methods are compliant with the `outputEncodeMethods` option, and if `unknownFields=true`,
the `setExtension` and `getExtension` methods will be created for extendable messages, also compliant with `outputEncodeMethods` (setExtension = encode, getExtension = decode).

### NestJS Support

We have a great way of working together with [nestjs](https://docs.nestjs.com/microservices/grpc). `ts-proto` generates `interfaces` and `decorators` for you controller, client. For more information see the [nestjs readme](NESTJS.markdown).
Expand Down
103 changes: 103 additions & 0 deletions integration/extensions/extensions-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { Extendable, Nested, packed, repeated, bytes, string, long, fixed, enumField, group, Enum } from './test';
import * as Long from 'long';

describe('extensions-test', () => {
it('works with namespaced extensions', () => {
const test: Extendable = {
field: 'hello'
};

const extensionData = [
{
field: 'a'
},
{
field: 'b'
}
];

Extendable.setExtension(test, Nested.message, extensionData);

const encoded = Extendable.encode(test).finish();
const result = Extendable.decode(encoded);

expect(result).toEqual(test);

const extension = Extendable.getExtension(result, Nested.message);

expect(extension).toEqual(extensionData);

const unsetExtension = Extendable.getExtension(result, packed);

expect(unsetExtension).toEqual(undefined);
});

it('works with repeated fields', () => {
const test: Extendable = {
field: 'repeated',

_unknownFields: {
[(6 << 3) | 2]: [Buffer.from([1, 1]), Buffer.from([1, 1])],
[(6 << 3) | 0]: [Buffer.from([2]), Buffer.from([3]), Buffer.from([5])]
}
};

const extensionData = [1, 2, 3, 4, 5];

Extendable.setExtension(test, packed, extensionData);

const encoded = Extendable.encode(test).finish();
const result = Extendable.decode(encoded);

expect(result).toEqual(test);

const extension = Extendable.getExtension(result, packed);

expect(extension).toEqual(extensionData);

expect(Extendable.getExtension(result, repeated)).toEqual([1, 1, 2, 3, 5]);

const unsetExtension = Extendable.getExtension(result, Nested.message);

expect(unsetExtension).toEqual(undefined);
});

it('works with various field types', () => {
const test: Extendable = {
field: 'various'
};

const bytesExtensionData = Buffer.from([2, 3, 5, 7, 11]);
const stringExtensionData = "this is a string";
const longExtensionData = new Long(0x89ABCDEF, 0x01234567, false);
const fixedExtensionData = new Long(0x01234567, 0x89ABCDEF, true);
const enumExtensionData = Enum.ENUM_ONE;
const groupExtensionData = {
name: 'this is',
value: 'a group'
};

Extendable.setExtension(test, bytes, bytesExtensionData);
Extendable.setExtension(test, string, stringExtensionData);
Extendable.setExtension(test, long, longExtensionData);
Extendable.setExtension(test, fixed, fixedExtensionData);
Extendable.setExtension(test, enumField, enumExtensionData);
Extendable.setExtension(test, group, groupExtensionData);

const encoded = Extendable.encode(test).finish();
const result = Extendable.decode(encoded);

expect(result).toEqual(test);

expect( Extendable.getExtension(result, bytes) ).toEqual(bytesExtensionData);
expect( Extendable.getExtension(result, string) ).toEqual(stringExtensionData);
expect( Extendable.getExtension(result, long) ).toEqual(longExtensionData);
expect( Extendable.getExtension(result, fixed) ).toEqual(fixedExtensionData);
expect( Extendable.getExtension(result, enumField) ).toEqual(enumExtensionData);
expect( Extendable.getExtension(result, group) ).toEqual(groupExtensionData);

const unsetExtension = Extendable.getExtension(result, Nested.message);

expect(unsetExtension).toEqual(undefined);
});
});
1 change: 1 addition & 0 deletions integration/extensions/parameters.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
outputExtensions=true,forceLong=long,unknownFields=true,initializeFieldsAsUndefined=false,useOptionals=all
Binary file added integration/extensions/test.bin
Binary file not shown.
35 changes: 35 additions & 0 deletions integration/extensions/test.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
syntax = "proto2";

message Extendable{
required string field = 1;

extensions 4 to max;
}

message Nested{
required string field = 1;

extend Extendable{
repeated Nested message = 4;
}
}

enum Enum{
ENUM_UNRECOGNIZED = 0;
ENUM_ONE = 1;
ENUM_TWO = 2;
}

extend Extendable{
repeated int32 packed = 5 [packed = true];
repeated int32 repeated = 6;
optional bytes bytes = 7;
optional string string = 8;
optional int64 long = 9;
optional fixed64 fixed = 10;
optional Enum enum_field = 11;
optional group Group = 12 {
optional string name = 1;
optional string value = 2;
}
}
Loading

0 comments on commit f956128

Please sign in to comment.