Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support the jstype field option #592

Merged
merged 1 commit into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions docs/generated_code.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,13 +162,20 @@ as `optional`. Protobuf types map to ECMAScript types as follows:

### 64-bit integral types

We use the `bigint` primitive to represent 64-bit integral types. If bigint
is unavailable, we fall back to a string representation, which means that
all values typed as `bigint` will actually be strings.
We use the `BigInt` primitive to represent 64-bit integral types. `BigInt` has
been available in all major runtimes since 2020.

For presentation purposes, it is always safe to simply call `toString()` on
the field value. For more detailed information, see the conversion utility
[`protoInt64`][src-proto-int64] provided by [@bufbuild/protobuf][pkg-protobuf].
If you prefer to avoid `BigInt` in generated code, you can set the field option
`jstype = JS_STRING` to generate `String` instead:

```protobuf
int64 my_field = 1 [jstype = JS_STRING]; // will generate `myField: string`
```

If `BigInt` is unavailable in your environment, Protobuf-ES falls back to the
string representation. This means all values typed as `bigint` will be a `string`
at runtime. For detailed information on how to handle both variants, see the
conversion utility [`protoInt64`][src-proto-int64] provided by [@bufbuild/protobuf][pkg-protobuf].


### Message fields
Expand Down
2 changes: 1 addition & 1 deletion packages/protobuf-bench/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ server would usually do.

| code generator | bundle size | minified | compressed |
|---------------------|------------------------:|-----------------------:|-------------------:|
| protobuf-es | 89,648 b | 37,862 b | 9,699 b |
| protobuf-es | 90,449 b | 38,223 b | 9,818 b |
| protobuf-javascript | 394,384 b | 288,653 b | 45,140 b |
68 changes: 68 additions & 0 deletions packages/protobuf-test/extra/jstype-proto2.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2021-2023 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto2";
package spec;

message JSTypeProto2OmittedMessage {
optional fixed64 fixed64_field = 1;
optional int64 int64_field = 3;
optional sfixed64 sfixed64_field = 4;
optional sint64 sint64_field = 5;
optional uint64 uint64_field = 6;
repeated fixed64 repeated_fixed64_field = 11;
repeated int64 repeated_int64_field = 12;
repeated sfixed64 repeated_sfixed64_field = 13;
repeated sint64 repeated_sint64_field = 14;
repeated uint64 repeated_uint64_field = 15;
}

message JSTypeProto2NormalMessage {
optional fixed64 fixed64_field = 1 [jstype = JS_NORMAL];
optional int64 int64_field = 3 [jstype = JS_NORMAL];
optional sfixed64 sfixed64_field = 4 [jstype = JS_NORMAL];
optional sint64 sint64_field = 5 [jstype = JS_NORMAL];
optional uint64 uint64_field = 6 [jstype = JS_NORMAL];
repeated fixed64 repeated_fixed64_field = 11 [jstype = JS_NORMAL];
repeated int64 repeated_int64_field = 12 [jstype = JS_NORMAL];
repeated sfixed64 repeated_sfixed64_field = 13 [jstype = JS_NORMAL];
repeated sint64 repeated_sint64_field = 14 [jstype = JS_NORMAL];
repeated uint64 repeated_uint64_field = 15 [jstype = JS_NORMAL];
}

message JSTypeProto2StringMessage {
optional fixed64 fixed64_field = 1 [jstype = JS_STRING];
optional int64 int64_field = 3 [jstype = JS_STRING];
optional sfixed64 sfixed64_field = 4 [jstype = JS_STRING];
optional sint64 sint64_field = 5 [jstype = JS_STRING];
optional uint64 uint64_field = 6 [jstype = JS_STRING];
repeated fixed64 repeated_fixed64_field = 11 [jstype = JS_STRING];
repeated int64 repeated_int64_field = 12 [jstype = JS_STRING];
repeated sfixed64 repeated_sfixed64_field = 13 [jstype = JS_STRING];
repeated sint64 repeated_sint64_field = 14 [jstype = JS_STRING];
repeated uint64 repeated_uint64_field = 15 [jstype = JS_STRING];
}

message JSTypeProto2NumberMessage {
optional fixed64 fixed64_field = 1 [jstype = JS_NUMBER];
optional int64 int64_field = 3 [jstype = JS_NUMBER];
optional sfixed64 sfixed64_field = 4 [jstype = JS_NUMBER];
optional sint64 sint64_field = 5 [jstype = JS_NUMBER];
optional uint64 uint64_field = 6 [jstype = JS_NUMBER];
repeated fixed64 repeated_fixed64_field = 11 [jstype = JS_NUMBER];
repeated int64 repeated_int64_field = 12 [jstype = JS_NUMBER];
repeated sfixed64 repeated_sfixed64_field = 13 [jstype = JS_NUMBER];
repeated sint64 repeated_sint64_field = 14 [jstype = JS_NUMBER];
repeated uint64 repeated_uint64_field = 15 [jstype = JS_NUMBER];
}
68 changes: 68 additions & 0 deletions packages/protobuf-test/extra/jstype.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2021-2023 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";
package spec;

message JSTypeOmittedMessage {
fixed64 fixed64_field = 1;
int64 int64_field = 3;
sfixed64 sfixed64_field = 4;
sint64 sint64_field = 5;
uint64 uint64_field = 6;
repeated fixed64 repeated_fixed64_field = 11;
repeated int64 repeated_int64_field = 12;
repeated sfixed64 repeated_sfixed64_field = 13;
repeated sint64 repeated_sint64_field = 14;
repeated uint64 repeated_uint64_field = 15;
}

message JSTypeNormalMessage {
fixed64 fixed64_field = 1 [jstype = JS_NORMAL];
int64 int64_field = 3 [jstype = JS_NORMAL];
sfixed64 sfixed64_field = 4 [jstype = JS_NORMAL];
sint64 sint64_field = 5 [jstype = JS_NORMAL];
uint64 uint64_field = 6 [jstype = JS_NORMAL];
repeated fixed64 repeated_fixed64_field = 11 [jstype = JS_NORMAL];
repeated int64 repeated_int64_field = 12 [jstype = JS_NORMAL];
repeated sfixed64 repeated_sfixed64_field = 13 [jstype = JS_NORMAL];
repeated sint64 repeated_sint64_field = 14 [jstype = JS_NORMAL];
repeated uint64 repeated_uint64_field = 15 [jstype = JS_NORMAL];
}

message JSTypeStringMessage {
fixed64 fixed64_field = 1 [jstype = JS_STRING];
int64 int64_field = 3 [jstype = JS_STRING];
sfixed64 sfixed64_field = 4 [jstype = JS_STRING];
sint64 sint64_field = 5 [jstype = JS_STRING];
uint64 uint64_field = 6 [jstype = JS_STRING];
repeated fixed64 repeated_fixed64_field = 11 [jstype = JS_STRING];
repeated int64 repeated_int64_field = 12 [jstype = JS_STRING];
repeated sfixed64 repeated_sfixed64_field = 13 [jstype = JS_STRING];
repeated sint64 repeated_sint64_field = 14 [jstype = JS_STRING];
repeated uint64 repeated_uint64_field = 15 [jstype = JS_STRING];
}

message JSTypeNumberMessage {
fixed64 fixed64_field = 1 [jstype = JS_NUMBER];
int64 int64_field = 3 [jstype = JS_NUMBER];
sfixed64 sfixed64_field = 4 [jstype = JS_NUMBER];
sint64 sint64_field = 5 [jstype = JS_NUMBER];
uint64 uint64_field = 6 [jstype = JS_NUMBER];
repeated fixed64 repeated_fixed64_field = 11 [jstype = JS_NUMBER];
repeated int64 repeated_int64_field = 12 [jstype = JS_NUMBER];
repeated sfixed64 repeated_sfixed64_field = 13 [jstype = JS_NUMBER];
repeated sint64 repeated_sint64_field = 14 [jstype = JS_NUMBER];
repeated uint64 repeated_uint64_field = 15 [jstype = JS_NUMBER];
}
25 changes: 25 additions & 0 deletions packages/protobuf-test/src/constructor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,33 @@ import {
TestAllTypesProto3_NestedMessage as TS_TestAllTypesProto3_NestedMessage,
} from "./gen/ts/google/protobuf/test_messages_proto3_pb.js";
import { TestAllTypesProto3 as JS_TestAllTypesProto3 } from "./gen/js/google/protobuf/test_messages_proto3_pb.js";
import { JSTypeStringMessage as TS_JSTypeStringMessage } from "./gen/ts/extra/jstype_pb.js";
import { JSTypeStringMessage as JS_JSTypeStringMessage } from "./gen/js/extra/jstype_pb.js";
import { testMT } from "./helpers.js";

describe("constructor initializes jstype=JS_STRING with string", function () {
testMT(
{ ts: TS_JSTypeStringMessage, js: JS_JSTypeStringMessage },
(messageType) => {
const m = new messageType({
fixed64Field: "123",
repeatedFixed64Field: ["123"],
});
expect(m.fixed64Field).toBe("123");
expect(m.int64Field).toBe("0");
expect(m.sfixed64Field).toBe("0");
expect(m.sint64Field).toBe("0");
expect(m.uint64Field).toBe("0");
expect(m.repeatedFixed64Field.length).toBe(1);
expect(m.repeatedFixed64Field).toStrictEqual(["123"]);
expect(m.repeatedInt64Field.length).toBe(0);
expect(m.repeatedSfixed64Field.length).toBe(0);
expect(m.repeatedSint64Field.length).toBe(0);
expect(m.repeatedUint64Field.length).toBe(0);
},
);
});

describe("constructor takes message partial for message field", function () {
testMT(
{ ts: TS_TestAllTypesProto3, js: JS_TestAllTypesProto3 },
Expand Down
90 changes: 90 additions & 0 deletions packages/protobuf-test/src/equals.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,99 @@ import { ScalarValuesMessage as TS_ScalarValuesMessage } from "./gen/ts/extra/ms
import { ScalarValuesMessage as JS_ScalarValuesMessage } from "./gen/js/extra/msg-scalar_pb.js";
import { OneofMessage as TS_OneofMessage } from "./gen/ts/extra/msg-oneof_pb.js";
import { OneofMessage as JS_OneofMessage } from "./gen/js/extra/msg-oneof_pb.js";
import { JSTypeStringMessage as TS_JSTypeStringMessage } from "./gen/ts/extra/jstype_pb.js";
import { JSTypeStringMessage as JS_JSTypeStringMessage } from "./gen/js/extra/jstype_pb.js";
import { JSTypeProto2StringMessage as TS_JSTypeProto2StringMessage } from "./gen/ts/extra/jstype-proto2_pb.js";
import { JSTypeProto2StringMessage as JS_JSTypeProto2StringMessage } from "./gen/js/extra/jstype-proto2_pb.js";
import { describeMT } from "./helpers.js";

describe("equals", function () {
describeMT(
{ ts: TS_JSTypeProto2StringMessage, js: JS_JSTypeProto2StringMessage },
(messageType) => {
let a: TS_JSTypeProto2StringMessage | JS_JSTypeProto2StringMessage,
b: TS_JSTypeProto2StringMessage | JS_JSTypeProto2StringMessage;
beforeEach(() => {
a = new messageType({
fixed64Field: "123",
int64Field: "123",
sfixed64Field: "123",
sint64Field: "123",
uint64Field: "123",
repeatedFixed64Field: ["123"],
repeatedInt64Field: ["123"],
repeatedSfixed64Field: ["123"],
repeatedSint64Field: ["123"],
repeatedUint64Field: ["123"],
});
b = new messageType({
fixed64Field: "123",
int64Field: "123",
sfixed64Field: "123",
sint64Field: "123",
uint64Field: "123",
repeatedFixed64Field: ["123"],
repeatedInt64Field: ["123"],
repeatedSfixed64Field: ["123"],
repeatedSint64Field: ["123"],
repeatedUint64Field: ["123"],
});
});
test("same are equal", () => {
expect(a).toStrictEqual(b);
expect(a.equals(b)).toBeTruthy();
});
test("changed are not equal", () => {
a.int64Field = undefined;
expect(a).not.toStrictEqual(b);
expect(a.equals(b)).toBeFalsy();
});
},
);

describeMT(
{ ts: TS_JSTypeStringMessage, js: JS_JSTypeStringMessage },
(messageType) => {
let a: TS_JSTypeStringMessage | JS_JSTypeStringMessage,
b: TS_JSTypeStringMessage | JS_JSTypeStringMessage;
beforeEach(() => {
a = new messageType({
fixed64Field: "123",
int64Field: "123",
sfixed64Field: "123",
sint64Field: "123",
uint64Field: "123",
repeatedFixed64Field: ["123"],
repeatedInt64Field: ["123"],
repeatedSfixed64Field: ["123"],
repeatedSint64Field: ["123"],
repeatedUint64Field: ["123"],
});
b = new messageType({
fixed64Field: "123",
int64Field: "123",
sfixed64Field: "123",
sint64Field: "123",
uint64Field: "123",
repeatedFixed64Field: ["123"],
repeatedInt64Field: ["123"],
repeatedSfixed64Field: ["123"],
repeatedSint64Field: ["123"],
repeatedUint64Field: ["123"],
});
});
test("same are equal", () => {
expect(a).toStrictEqual(b);
expect(a.equals(b)).toBeTruthy();
});
test("changed are not equal", () => {
a.int64Field = "456";
expect(a).not.toStrictEqual(b);
expect(a.equals(b)).toBeFalsy();
});
},
);

describeMT({ ts: TS_OneofMessage, js: JS_OneofMessage }, (messageType) => {
test("oneof scalars are equal", () => {
const a = new messageType({ scalar: { case: "value", value: 1 } });
Expand Down
Loading