diff --git a/packages/proto-loader/README.md b/packages/proto-loader/README.md index 935c100dc..34d844a2f 100644 --- a/packages/proto-loader/README.md +++ b/packages/proto-loader/README.md @@ -31,7 +31,7 @@ The options parameter is an object that can have the following optional properti | Field name | Valid values | Description |------------|--------------|------------ | `keepCase` | `true` or `false` | Preserve field names. The default is to change them to camel case. -| `longs` | `String` or `Number` | The type to use to represent `long` values. Defaults to a `Long` object type. +| `longs` | `String`, `Number`, or `BigInt` | The type to use to represent `long` values. Defaults to a `Long` object type. Requires `protobufjs` >= 7.6.0 when using `BigInt`. | `enums` | `String` | The type to use to represent `enum` values. Defaults to the numeric value. | `bytes` | `Array` or `String` | The type to use to represent `bytes` values. Defaults to `Buffer`. | `defaults` | `true` or `false` | Set default values on output objects. Defaults to `false`. @@ -66,7 +66,7 @@ Options: --keepCase Preserve the case of field names [boolean] [default: false] --longs The type that should be used to output 64 bit - integer values. Can be String, Number + integer values. Can be String, Number, BigInt [string] [default: "Long"] --enums The type that should be used to output enum fields. Can be String [string] [default: "number"] diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 14850a7e7..5f8af2148 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -214,7 +214,7 @@ function getTypeNamePermissive(fieldType: string, resolvedType: Protobuf.Type | case 'sint64': case 'fixed64': case 'sfixed64': - return 'number | string | Long'; + return 'number | string | Long | bigint'; case 'bool': return 'boolean'; case 'string': @@ -312,6 +312,8 @@ function getTypeNameRestricted(fieldType: string, resolvedType: Protobuf.Type | return 'number'; } else if (options.longs === String) { return 'string'; + } else if (options.longs === BigInt) { + return 'bigint'; } else { return 'Long'; } @@ -887,6 +889,7 @@ async function runScript() { switch (value) { case 'String': return String; case 'Number': return Number; + case 'BigInt': return BigInt; default: return undefined; } }).coerce('enums', value => { @@ -906,7 +909,7 @@ async function runScript() { verbose: 'v' }).describe({ keepCase: 'Preserve the case of field names', - longs: 'The type that should be used to output 64 bit integer values. Can be String, Number', + longs: 'The type that should be used to output 64 bit integer values. Can be String, Number, BigInt', enums: 'The type that should be used to output enum fields. Can be String', bytes: 'The type that should be used to output bytes fields. Can be String, Array', defaults: 'Output default values for omitted fields', diff --git a/packages/proto-loader/golden-generated/google/protobuf/Duration.ts b/packages/proto-loader/golden-generated/google/protobuf/Duration.ts index d5e3be89a..440609e6f 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/Duration.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/Duration.ts @@ -3,7 +3,7 @@ import type { Long } from '@grpc/proto-loader'; export interface IDuration { - 'seconds'?: (number | string | Long); + 'seconds'?: (number | string | Long | bigint); 'nanos'?: (number); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/Timestamp.ts b/packages/proto-loader/golden-generated/google/protobuf/Timestamp.ts index 06d756134..c1d317a87 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/Timestamp.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/Timestamp.ts @@ -3,7 +3,7 @@ import type { Long } from '@grpc/proto-loader'; export interface ITimestamp { - 'seconds'?: (number | string | Long); + 'seconds'?: (number | string | Long | bigint); 'nanos'?: (number); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/UninterpretedOption.ts b/packages/proto-loader/golden-generated/google/protobuf/UninterpretedOption.ts index fa0feaf52..c1adf1cf1 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/UninterpretedOption.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/UninterpretedOption.ts @@ -15,8 +15,8 @@ export interface O_google_protobuf_UninterpretedOption_NamePart { export interface IUninterpretedOption { 'name'?: (I_google_protobuf_UninterpretedOption_NamePart)[]; 'identifierValue'?: (string); - 'positiveIntValue'?: (number | string | Long); - 'negativeIntValue'?: (number | string | Long); + 'positiveIntValue'?: (number | string | Long | bigint); + 'negativeIntValue'?: (number | string | Long | bigint); 'doubleValue'?: (number | string); 'stringValue'?: (Buffer | Uint8Array | string); 'aggregateValue'?: (string); diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 7b748e175..e1d0de75f 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -47,7 +47,7 @@ "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", - "protobufjs": "^7.5.5", + "protobufjs": "^7.6.0", "yargs": "^17.7.2" }, "devDependencies": { diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index c56b29215..4c08101bb 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -412,8 +412,8 @@ function createPackageDefinitionFromDescriptorSet( * @param options.keepCase Preserve field names. The default is to change them * to camel case. * @param options.longs The type that should be used to represent `long` values. - * Valid options are `Number` and `String`. Defaults to a `Long` object type - * from a library. + * Valid options are `Number`, `String`, and `BigInt`. Defaults to a `Long` + * object type from a library. * @param options.enums The type that should be used to represent `enum` values. * The only valid option is `String`. Defaults to the numeric value. * @param options.bytes The type that should be used to represent `bytes` diff --git a/packages/proto-loader/test/descriptor_type_test.ts b/packages/proto-loader/test/descriptor_type_test.ts index 0329b08fe..942af527e 100644 --- a/packages/proto-loader/test/descriptor_type_test.ts +++ b/packages/proto-loader/test/descriptor_type_test.ts @@ -178,4 +178,47 @@ describe('Descriptor types', () => { }, }) }) + + it('Can deserialize int64 values as BigInt', () => { + const wideValue = '9223372036854775807'; + const encodedDef = proto_loader.loadSync( + `${TEST_PROTO_DIR}/messages.proto`, + { keepCase: true } + ).LongValues; + assert(isTypeObject(encodedDef)); + const longValuesDef = encodedDef as proto_loader.MessageTypeDefinition< + object, + object + >; + const encoded = longValuesDef.serialize({ + int_64: wideValue, + uint_64: wideValue, + sint_64: wideValue, + fixed_64: wideValue, + sfixed_64: wideValue, + }); + const decodedDef = proto_loader.loadSync( + `${TEST_PROTO_DIR}/messages.proto`, + { + keepCase: true, + longs: BigInt, + } + ).LongValues; + assert(isTypeObject(decodedDef)); + const decoded = ( + decodedDef as proto_loader.MessageTypeDefinition + ).deserialize(encoded) as { + int_64: bigint; + uint_64: bigint; + sint_64: bigint; + fixed_64: bigint; + sfixed_64: bigint; + }; + assert.strictEqual(typeof decoded.int_64, 'bigint'); + assert.strictEqual(decoded.int_64, BigInt(wideValue)); + assert.strictEqual(decoded.uint_64, BigInt(wideValue)); + assert.strictEqual(decoded.sint_64, BigInt(wideValue)); + assert.strictEqual(decoded.fixed_64, BigInt(wideValue)); + assert.strictEqual(decoded.sfixed_64, BigInt(wideValue)); + }); }); diff --git a/packages/proto-loader/tsconfig.json b/packages/proto-loader/tsconfig.json index e46980866..0aef75cee 100644 --- a/packages/proto-loader/tsconfig.json +++ b/packages/proto-loader/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "rootDir": ".", "outDir": "build", - "lib": ["es2017"], + "lib": ["es2017", "ES2020.BigInt"], "target": "es2017" }, "include": [