ts-proto 1.93.3 → 1.96.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.markdown +3 -1
- package/build/case.js +2 -8
- package/build/enums.js +17 -4
- package/build/generate-grpc-js.js +1 -0
- package/build/main.js +55 -13
- package/build/options.js +9 -2
- package/build/types.js +50 -17
- package/build/utils.js +6 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
# [1.96.0](https://github.com/stephenh/ts-proto/compare/v1.95.1...v1.96.0) (2021-12-24)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* `enumsAsLiterals` option ([#450](https://github.com/stephenh/ts-proto/issues/450)) ([fcaade2](https://github.com/stephenh/ts-proto/commit/fcaade2855ae28ea3553a365556ccb92a9644d70))
|
|
7
|
+
|
|
8
|
+
## [1.95.1](https://github.com/stephenh/ts-proto/compare/v1.95.0...v1.95.1) (2021-12-23)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* Add service to the client constructor. ([#455](https://github.com/stephenh/ts-proto/issues/455)) ([8c32104](https://github.com/stephenh/ts-proto/commit/8c32104a8522cfe2febcf2338d51710021d837ff))
|
|
14
|
+
|
|
15
|
+
# [1.95.0](https://github.com/stephenh/ts-proto/compare/v1.94.0...v1.95.0) (2021-12-14)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* Add useOptionals=all to enable non-field members to be optional. ([#402](https://github.com/stephenh/ts-proto/issues/402)) ([e7b70cb](https://github.com/stephenh/ts-proto/commit/e7b70cbd7b9bd43bf9e6e54e25bc48c527718317))
|
|
21
|
+
|
|
22
|
+
# [1.94.0](https://github.com/stephenh/ts-proto/compare/v1.93.3...v1.94.0) (2021-12-14)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Features
|
|
26
|
+
|
|
27
|
+
* Round numbers in toJSON. ([#444](https://github.com/stephenh/ts-proto/issues/444)) ([bd2df7b](https://github.com/stephenh/ts-proto/commit/bd2df7b7176e961955ed1dcacb3602384e13ee45))
|
|
28
|
+
|
|
1
29
|
## [1.93.3](https://github.com/stephenh/ts-proto/compare/v1.93.2...v1.93.3) (2021-12-13)
|
|
2
30
|
|
|
3
31
|
|
package/README.markdown
CHANGED
|
@@ -159,7 +159,7 @@ creating a class and calling the right getters/setters.
|
|
|
159
159
|
|
|
160
160
|
(Configurable with the `useDate` parameter.)
|
|
161
161
|
|
|
162
|
-
- `fromJSON`/`toJSON`
|
|
162
|
+
- `fromJSON`/`toJSON` use the [proto3 canonical JSON encoding format](https://developers.google.com/protocol-buffers/docs/proto3#json) (e.g. timestamps are ISO strings), unlike [`protobufjs`](https://github.com/protobufjs/protobuf.js/issues/1304).
|
|
163
163
|
|
|
164
164
|
# Auto-Batching / N+1 Prevention
|
|
165
165
|
|
|
@@ -348,6 +348,8 @@ Generated code will be placed in the Gradle build directory.
|
|
|
348
348
|
|
|
349
349
|
- With `--ts_proto_opt=fileSuffix=<SUFFIX>`, ts-proto will emit generated files using the specified suffix. A `helloworld.proto` file with `fileSuffix=.pb` would be generated as `helloworld.pb.ts`. This is common behavior in other protoc plugins and provides a way to quickly glob all the generated files.
|
|
350
350
|
|
|
351
|
+
- With `--ts_proto_opt=enumsAsLiterals=true`, the generated enum types will be enum-ish object with `as const`.
|
|
352
|
+
|
|
351
353
|
### Only Types
|
|
352
354
|
|
|
353
355
|
If you're looking for `ts-proto` to generate only types for your Protobuf types then passing all three of `outputEncodeMethods`, `outputJsonMethods`, and `outputClientImpl` as `false` is probably what you want, i.e.:
|
package/build/case.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.camelCase = exports.capitalize = exports.camelToSnake = exports.
|
|
3
|
+
exports.camelCase = exports.capitalize = exports.camelToSnake = exports.maybeSnakeToCamel = void 0;
|
|
4
4
|
function maybeSnakeToCamel(s, options) {
|
|
5
|
-
|
|
6
|
-
const fromBooleanSnakeToCamel = options.snakeToCamel === true;
|
|
7
|
-
if ((fromBooleanSnakeToCamel || fromStringSnakeToCamel) && s.includes('_')) {
|
|
5
|
+
if (options.snakeToCamel.includes('keys') && s.includes('_')) {
|
|
8
6
|
return s
|
|
9
7
|
.split('_')
|
|
10
8
|
.map((word, i) => {
|
|
@@ -23,10 +21,6 @@ function maybeSnakeToCamel(s, options) {
|
|
|
23
21
|
}
|
|
24
22
|
}
|
|
25
23
|
exports.maybeSnakeToCamel = maybeSnakeToCamel;
|
|
26
|
-
function stringToSnakeCase(s) {
|
|
27
|
-
return s.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase();
|
|
28
|
-
}
|
|
29
|
-
exports.stringToSnakeCase = stringToSnakeCase;
|
|
30
24
|
function camelToSnake(s) {
|
|
31
25
|
return s
|
|
32
26
|
.replace(/[\w]([A-Z])/g, function (m) {
|
package/build/enums.js
CHANGED
|
@@ -13,17 +13,30 @@ function generateEnum(ctx, fullName, enumDesc, sourceInfo) {
|
|
|
13
13
|
const { options } = ctx;
|
|
14
14
|
const chunks = [];
|
|
15
15
|
utils_1.maybeAddComment(sourceInfo, chunks, (_a = enumDesc.options) === null || _a === void 0 ? void 0 : _a.deprecated);
|
|
16
|
-
|
|
16
|
+
if (options.enumsAsLiterals) {
|
|
17
|
+
chunks.push(ts_poet_1.code `export const ${ts_poet_1.def(fullName)} = {`);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
chunks.push(ts_poet_1.code `export ${options.constEnums ? 'const ' : ''}enum ${ts_poet_1.def(fullName)} {`);
|
|
21
|
+
}
|
|
22
|
+
const delimiter = options.enumsAsLiterals ? ':' : '=';
|
|
17
23
|
enumDesc.value.forEach((valueDesc, index) => {
|
|
18
24
|
var _a;
|
|
19
25
|
const info = sourceInfo.lookup(sourceInfo_1.Fields.enum.value, index);
|
|
20
26
|
utils_1.maybeAddComment(info, chunks, (_a = valueDesc.options) === null || _a === void 0 ? void 0 : _a.deprecated, `${valueDesc.name} - `);
|
|
21
|
-
chunks.push(ts_poet_1.code `${valueDesc.name}
|
|
27
|
+
chunks.push(ts_poet_1.code `${valueDesc.name} ${delimiter} ${options.stringEnums ? `"${valueDesc.name}"` : valueDesc.number.toString()},`);
|
|
22
28
|
});
|
|
23
29
|
if (options.unrecognizedEnum)
|
|
24
30
|
chunks.push(ts_poet_1.code `
|
|
25
|
-
${UNRECOGNIZED_ENUM_NAME}
|
|
26
|
-
|
|
31
|
+
${UNRECOGNIZED_ENUM_NAME} ${delimiter} ${options.stringEnums ? `"${UNRECOGNIZED_ENUM_NAME}"` : UNRECOGNIZED_ENUM_VALUE.toString()},`);
|
|
32
|
+
if (options.enumsAsLiterals) {
|
|
33
|
+
chunks.push(ts_poet_1.code `} as const`);
|
|
34
|
+
chunks.push(ts_poet_1.code `\n`);
|
|
35
|
+
chunks.push(ts_poet_1.code `export type ${ts_poet_1.def(fullName)} = typeof ${ts_poet_1.def(fullName)}[keyof typeof ${ts_poet_1.def(fullName)}]`);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
chunks.push(ts_poet_1.code `}`);
|
|
39
|
+
}
|
|
27
40
|
if (options.outputJsonMethods || (options.stringEnums && options.outputEncodeMethods)) {
|
|
28
41
|
chunks.push(ts_poet_1.code `\n`);
|
|
29
42
|
chunks.push(generateEnumFromJson(ctx, fullName, enumDesc));
|
package/build/main.js
CHANGED
|
@@ -19,6 +19,14 @@ const generate_generic_service_definition_1 = require("./generate-generic-servic
|
|
|
19
19
|
function generateFile(ctx, fileDesc) {
|
|
20
20
|
var _a;
|
|
21
21
|
const { options, utils } = ctx;
|
|
22
|
+
if (options.useOptionals === false) {
|
|
23
|
+
console.warn("ts-proto: Passing useOptionals as a boolean option is deprecated and will be removed in a future version. Please pass the string 'none' instead of false.");
|
|
24
|
+
options.useOptionals = 'none';
|
|
25
|
+
}
|
|
26
|
+
else if (options.useOptionals === true) {
|
|
27
|
+
console.warn("ts-proto: Passing useOptionals as a boolean option is deprecated and will be removed in a future version. Please pass the string 'messages' instead of true.");
|
|
28
|
+
options.useOptionals = 'messages';
|
|
29
|
+
}
|
|
22
30
|
// Google's protofiles are organized like Java, where package == the folder the file
|
|
23
31
|
// is in, and file == a specific service within the package. I.e. you can have multiple
|
|
24
32
|
// company/foo.proto and company/bar.proto files, where package would be 'company'.
|
|
@@ -388,10 +396,6 @@ function makeTimestampMethods(options, longs) {
|
|
|
388
396
|
`);
|
|
389
397
|
return { toTimestamp, fromTimestamp, fromJsonTimestamp };
|
|
390
398
|
}
|
|
391
|
-
// When useOptionals=true, non-scalar fields are translated into optional properties.
|
|
392
|
-
function isOptionalProperty(field, options) {
|
|
393
|
-
return (options.useOptionals && types_1.isMessage(field) && !types_1.isRepeated(field)) || field.proto3Optional;
|
|
394
|
-
}
|
|
395
399
|
// Create the interface with properties
|
|
396
400
|
function generateInterfaceDeclaration(ctx, fullName, messageDesc, sourceInfo, fullTypeName) {
|
|
397
401
|
var _a;
|
|
@@ -419,7 +423,7 @@ function generateInterfaceDeclaration(ctx, fullName, messageDesc, sourceInfo, fu
|
|
|
419
423
|
utils_1.maybeAddComment(info, chunks, (_a = fieldDesc.options) === null || _a === void 0 ? void 0 : _a.deprecated);
|
|
420
424
|
const name = case_1.maybeSnakeToCamel(fieldDesc.name, options);
|
|
421
425
|
const type = types_1.toTypeName(ctx, messageDesc, fieldDesc);
|
|
422
|
-
const q = isOptionalProperty(fieldDesc, options) ? '?' : '';
|
|
426
|
+
const q = types_1.isOptionalProperty(fieldDesc, messageDesc.options, options) ? '?' : '';
|
|
423
427
|
chunks.push(ts_poet_1.code `${name}${q}: ${type}, `);
|
|
424
428
|
});
|
|
425
429
|
chunks.push(ts_poet_1.code `}`);
|
|
@@ -662,6 +666,7 @@ function generateEncode(ctx, fullName, messageDesc) {
|
|
|
662
666
|
else {
|
|
663
667
|
throw new Error(`Unhandled field ${field}`);
|
|
664
668
|
}
|
|
669
|
+
const isOptional = types_1.isOptionalProperty(field, messageDesc.options, options);
|
|
665
670
|
if (types_1.isRepeated(field)) {
|
|
666
671
|
if (types_1.isMapType(ctx, messageDesc, field)) {
|
|
667
672
|
const valueType = typeMap.get(field.typeName)[2].field[1];
|
|
@@ -673,18 +678,29 @@ function generateEncode(ctx, fullName, messageDesc) {
|
|
|
673
678
|
}
|
|
674
679
|
`
|
|
675
680
|
: writeSnippet(`{ ${maybeTypeField} key: key as any, value }`);
|
|
681
|
+
const optionalAlternative = isOptional ? ' || {}' : '';
|
|
676
682
|
chunks.push(ts_poet_1.code `
|
|
677
|
-
Object.entries(message.${fieldName}).forEach(([key, value]) => {
|
|
683
|
+
Object.entries(message.${fieldName}${optionalAlternative}).forEach(([key, value]) => {
|
|
678
684
|
${entryWriteSnippet}
|
|
679
685
|
});
|
|
680
686
|
`);
|
|
681
687
|
}
|
|
682
688
|
else if (types_1.packedType(field.type) === undefined) {
|
|
683
|
-
|
|
689
|
+
const listWriteSnippet = ts_poet_1.code `
|
|
684
690
|
for (const v of message.${fieldName}) {
|
|
685
691
|
${writeSnippet('v!')};
|
|
686
692
|
}
|
|
687
|
-
|
|
693
|
+
`;
|
|
694
|
+
if (isOptional) {
|
|
695
|
+
chunks.push(ts_poet_1.code `
|
|
696
|
+
if (message.${fieldName} !== undefined && message.${fieldName}.length !== 0) {
|
|
697
|
+
${listWriteSnippet}
|
|
698
|
+
}
|
|
699
|
+
`);
|
|
700
|
+
}
|
|
701
|
+
else {
|
|
702
|
+
chunks.push(listWriteSnippet);
|
|
703
|
+
}
|
|
688
704
|
}
|
|
689
705
|
else if (types_1.isEnum(field) && options.stringEnums) {
|
|
690
706
|
// This is a lot like the `else` clause, but we wrap `fooToNumber` around it.
|
|
@@ -693,24 +709,44 @@ function generateEncode(ctx, fullName, messageDesc) {
|
|
|
693
709
|
// (i.e. just one tag and multiple values).
|
|
694
710
|
const tag = ((field.number << 3) | 2) >>> 0;
|
|
695
711
|
const toNumber = types_1.getEnumMethod(ctx, field.typeName, 'ToNumber');
|
|
696
|
-
|
|
712
|
+
const listWriteSnippet = ts_poet_1.code `
|
|
697
713
|
writer.uint32(${tag}).fork();
|
|
698
714
|
for (const v of message.${fieldName}) {
|
|
699
715
|
writer.${types_1.toReaderCall(field)}(${toNumber}(v));
|
|
700
716
|
}
|
|
701
717
|
writer.ldelim();
|
|
702
|
-
|
|
718
|
+
`;
|
|
719
|
+
if (isOptional) {
|
|
720
|
+
chunks.push(ts_poet_1.code `
|
|
721
|
+
if (message.${fieldName} !== undefined && message.${fieldName}.length !== 0) {
|
|
722
|
+
${listWriteSnippet}
|
|
723
|
+
}
|
|
724
|
+
`);
|
|
725
|
+
}
|
|
726
|
+
else {
|
|
727
|
+
chunks.push(listWriteSnippet);
|
|
728
|
+
}
|
|
703
729
|
}
|
|
704
730
|
else {
|
|
705
731
|
// Ideally we'd reuse `writeSnippet` but it has tagging embedded inside of it.
|
|
706
732
|
const tag = ((field.number << 3) | 2) >>> 0;
|
|
707
|
-
|
|
733
|
+
const listWriteSnippet = ts_poet_1.code `
|
|
708
734
|
writer.uint32(${tag}).fork();
|
|
709
735
|
for (const v of message.${fieldName}) {
|
|
710
736
|
writer.${types_1.toReaderCall(field)}(v);
|
|
711
737
|
}
|
|
712
738
|
writer.ldelim();
|
|
713
|
-
|
|
739
|
+
`;
|
|
740
|
+
if (isOptional) {
|
|
741
|
+
chunks.push(ts_poet_1.code `
|
|
742
|
+
if (message.${fieldName} !== undefined && message.${fieldName}.length !== 0) {
|
|
743
|
+
${listWriteSnippet}
|
|
744
|
+
}
|
|
745
|
+
`);
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
chunks.push(listWriteSnippet);
|
|
749
|
+
}
|
|
714
750
|
}
|
|
715
751
|
}
|
|
716
752
|
else if (types_1.isWithinOneOfThatShouldBeUnion(options, field)) {
|
|
@@ -738,7 +774,7 @@ function generateEncode(ctx, fullName, messageDesc) {
|
|
|
738
774
|
}
|
|
739
775
|
else if (types_1.isScalar(field) || types_1.isEnum(field)) {
|
|
740
776
|
chunks.push(ts_poet_1.code `
|
|
741
|
-
if (${types_1.notDefaultCheck(ctx, field, `message.${fieldName}`)}) {
|
|
777
|
+
if (${types_1.notDefaultCheck(ctx, field, messageDesc.options, `message.${fieldName}`)}) {
|
|
742
778
|
${writeSnippet(`message.${fieldName}`)};
|
|
743
779
|
}
|
|
744
780
|
`);
|
|
@@ -980,6 +1016,9 @@ function generateToJson(ctx, fullName, messageDesc) {
|
|
|
980
1016
|
else if (types_1.isLong(valueType) && options.forceLong === options_1.LongOption.LONG) {
|
|
981
1017
|
return ts_poet_1.code `${from}.toString()`;
|
|
982
1018
|
}
|
|
1019
|
+
else if (types_1.isWholeNumber(valueType) && !(types_1.isLong(valueType) && options.forceLong === options_1.LongOption.STRING)) {
|
|
1020
|
+
return ts_poet_1.code `Math.round(${from})`;
|
|
1021
|
+
}
|
|
983
1022
|
else if (types_1.isScalar(valueType) || types_1.isValueType(ctx, valueType)) {
|
|
984
1023
|
return ts_poet_1.code `${from}`;
|
|
985
1024
|
}
|
|
@@ -1010,6 +1049,9 @@ function generateToJson(ctx, fullName, messageDesc) {
|
|
|
1010
1049
|
const v = types_1.isWithinOneOf(field) ? 'undefined' : types_1.defaultValue(ctx, field);
|
|
1011
1050
|
return ts_poet_1.code `(${from} || ${v}).toString()`;
|
|
1012
1051
|
}
|
|
1052
|
+
else if (types_1.isWholeNumber(field) && !(types_1.isLong(field) && options.forceLong === options_1.LongOption.STRING)) {
|
|
1053
|
+
return ts_poet_1.code `Math.round(${from})`;
|
|
1054
|
+
}
|
|
1013
1055
|
else {
|
|
1014
1056
|
return ts_poet_1.code `${from}`;
|
|
1015
1057
|
}
|
package/build/options.js
CHANGED
|
@@ -34,9 +34,9 @@ var ServiceOption;
|
|
|
34
34
|
function defaultOptions() {
|
|
35
35
|
return {
|
|
36
36
|
context: false,
|
|
37
|
-
snakeToCamel:
|
|
37
|
+
snakeToCamel: ['json', 'keys'],
|
|
38
38
|
forceLong: LongOption.NUMBER,
|
|
39
|
-
useOptionals:
|
|
39
|
+
useOptionals: 'none',
|
|
40
40
|
useDate: DateOption.DATE,
|
|
41
41
|
oneof: OneofOption.PROPERTIES,
|
|
42
42
|
esModuleInterop: false,
|
|
@@ -48,6 +48,7 @@ function defaultOptions() {
|
|
|
48
48
|
outputTypeRegistry: false,
|
|
49
49
|
stringEnums: false,
|
|
50
50
|
constEnums: false,
|
|
51
|
+
enumsAsLiterals: false,
|
|
51
52
|
outputClientImpl: true,
|
|
52
53
|
outputServices: ServiceOption.DEFAULT,
|
|
53
54
|
returnObservable: false,
|
|
@@ -100,6 +101,12 @@ function optionsFromParameter(parameter) {
|
|
|
100
101
|
// Treat useDate=false as TIMESTAMP
|
|
101
102
|
options.useDate = DateOption.TIMESTAMP;
|
|
102
103
|
}
|
|
104
|
+
if (options.snakeToCamel === false) {
|
|
105
|
+
options.snakeToCamel = [];
|
|
106
|
+
}
|
|
107
|
+
else if (options.snakeToCamel === true) {
|
|
108
|
+
options.snakeToCamel = ['keys', 'json'];
|
|
109
|
+
}
|
|
103
110
|
return options;
|
|
104
111
|
}
|
|
105
112
|
exports.optionsFromParameter = optionsFromParameter;
|
package/build/types.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.detectBatchMethod = exports.responsePromiseOrObservable = exports.responseObservable = exports.responsePromise = exports.responseType = exports.requestType = exports.rawRequestType = exports.detectMapType = exports.toTypeName = exports.getEnumMethod = exports.messageToTypeName = exports.wrapperTypeName = exports.valueTypeName = exports.isEmptyType = exports.isLongValueType = exports.isStructTypeName = exports.isStructType = exports.isListValueTypeName = exports.isListValueType = exports.isBytesValueType = exports.isAnyValueTypeName = exports.isAnyValueType = exports.isValueType = exports.isTimestamp = exports.isMapType = exports.isLong = exports.isRepeated = exports.isWithinOneOfThatShouldBeUnion = exports.isWithinOneOf = exports.isEnum = exports.isMessage = exports.isBytes = exports.isPrimitive = exports.isScalar = exports.createTypeMap = exports.notDefaultCheck = exports.defaultValue = exports.packedType = exports.toReaderCall = exports.basicTypeName = exports.basicLongWireType = exports.basicWireType = void 0;
|
|
3
|
+
exports.detectBatchMethod = exports.responsePromiseOrObservable = exports.responseObservable = exports.responsePromise = exports.responseType = exports.requestType = exports.rawRequestType = exports.detectMapType = exports.toTypeName = exports.getEnumMethod = exports.messageToTypeName = exports.wrapperTypeName = exports.valueTypeName = exports.isEmptyType = exports.isLongValueType = exports.isStructTypeName = exports.isStructType = exports.isListValueTypeName = exports.isListValueType = exports.isBytesValueType = exports.isAnyValueTypeName = exports.isAnyValueType = exports.isValueType = exports.isTimestamp = exports.isMapType = exports.isWholeNumber = exports.isLong = exports.isRepeated = exports.isWithinOneOfThatShouldBeUnion = exports.isWithinOneOf = exports.isEnum = exports.isMessage = exports.isBytes = exports.isPrimitive = exports.isOptionalProperty = exports.isScalar = exports.createTypeMap = exports.notDefaultCheck = exports.defaultValue = exports.packedType = exports.toReaderCall = exports.basicTypeName = exports.basicLongWireType = exports.basicWireType = void 0;
|
|
4
4
|
const ts_proto_descriptors_1 = require("ts-proto-descriptors");
|
|
5
5
|
const ts_poet_1 = require("ts-poet");
|
|
6
6
|
const options_1 = require("./options");
|
|
@@ -225,8 +225,10 @@ function defaultValue(ctx, field) {
|
|
|
225
225
|
}
|
|
226
226
|
exports.defaultValue = defaultValue;
|
|
227
227
|
/** Creates code that checks that the field is not the default value. Supports scalars and enums. */
|
|
228
|
-
function notDefaultCheck(ctx, field, place) {
|
|
228
|
+
function notDefaultCheck(ctx, field, messageOptions, place) {
|
|
229
229
|
const { typeMap, options } = ctx;
|
|
230
|
+
const isOptional = isOptionalProperty(field, messageOptions, options);
|
|
231
|
+
const maybeNotUndefinedAnd = isOptional ? `${place} !== undefined && ` : '';
|
|
230
232
|
switch (field.type) {
|
|
231
233
|
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_DOUBLE:
|
|
232
234
|
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FLOAT:
|
|
@@ -235,7 +237,7 @@ function notDefaultCheck(ctx, field, place) {
|
|
|
235
237
|
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT32:
|
|
236
238
|
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED32:
|
|
237
239
|
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED32:
|
|
238
|
-
return ts_poet_1.code `${place} !== 0`;
|
|
240
|
+
return ts_poet_1.code `${maybeNotUndefinedAnd} ${place} !== 0`;
|
|
239
241
|
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_ENUM:
|
|
240
242
|
// proto3 enforces enums starting at 0, however proto2 does not, so we have
|
|
241
243
|
// to probe and see if zero is an allowed value. If it's not, pick the first one.
|
|
@@ -245,10 +247,10 @@ function notDefaultCheck(ctx, field, place) {
|
|
|
245
247
|
const zerothValue = enumProto.value.find((v) => v.number === 0) || enumProto.value[0];
|
|
246
248
|
if (options.stringEnums) {
|
|
247
249
|
const enumType = messageToTypeName(ctx, field.typeName);
|
|
248
|
-
return ts_poet_1.code `${place} !== ${enumType}.${zerothValue.name}`;
|
|
250
|
+
return ts_poet_1.code `${maybeNotUndefinedAnd} ${place} !== ${enumType}.${zerothValue.name}`;
|
|
249
251
|
}
|
|
250
252
|
else {
|
|
251
|
-
return ts_poet_1.code `${place} !== ${zerothValue.number}`;
|
|
253
|
+
return ts_poet_1.code `${maybeNotUndefinedAnd} ${place} !== ${zerothValue.number}`;
|
|
252
254
|
}
|
|
253
255
|
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT64:
|
|
254
256
|
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED64:
|
|
@@ -256,20 +258,20 @@ function notDefaultCheck(ctx, field, place) {
|
|
|
256
258
|
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT64:
|
|
257
259
|
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED64:
|
|
258
260
|
if (options.forceLong === options_1.LongOption.LONG) {
|
|
259
|
-
return ts_poet_1.code
|
|
261
|
+
return ts_poet_1.code `${maybeNotUndefinedAnd} !${place}.isZero()`;
|
|
260
262
|
}
|
|
261
263
|
else if (options.forceLong === options_1.LongOption.STRING) {
|
|
262
|
-
return ts_poet_1.code `${place} !== "0"`;
|
|
264
|
+
return ts_poet_1.code `${maybeNotUndefinedAnd} ${place} !== "0"`;
|
|
263
265
|
}
|
|
264
266
|
else {
|
|
265
|
-
return ts_poet_1.code `${place} !== 0`;
|
|
267
|
+
return ts_poet_1.code `${maybeNotUndefinedAnd} ${place} !== 0`;
|
|
266
268
|
}
|
|
267
269
|
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BOOL:
|
|
268
270
|
return ts_poet_1.code `${place} === true`;
|
|
269
271
|
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_STRING:
|
|
270
|
-
return ts_poet_1.code `${place} !== ""`;
|
|
272
|
+
return ts_poet_1.code `${maybeNotUndefinedAnd} ${place} !== ""`;
|
|
271
273
|
case ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_BYTES:
|
|
272
|
-
return ts_poet_1.code `${place}.length !== 0`;
|
|
274
|
+
return ts_poet_1.code `${maybeNotUndefinedAnd} ${place}.length !== 0`;
|
|
273
275
|
default:
|
|
274
276
|
throw new Error('Not implemented for the given type.');
|
|
275
277
|
}
|
|
@@ -314,6 +316,18 @@ function isScalar(field) {
|
|
|
314
316
|
return scalarTypes.includes(field.type);
|
|
315
317
|
}
|
|
316
318
|
exports.isScalar = isScalar;
|
|
319
|
+
// When useOptionals='messages', non-scalar fields are translated into optional
|
|
320
|
+
// properties. When useOptionals='all', all fields are translated into
|
|
321
|
+
// optional properties, with the exception of map Entry key/values, which must
|
|
322
|
+
// always be present.
|
|
323
|
+
function isOptionalProperty(field, messageOptions, options) {
|
|
324
|
+
const optionalMessages = options.useOptionals === true || options.useOptionals === 'messages' || options.useOptionals === 'all';
|
|
325
|
+
const optionalAll = options.useOptionals === 'all';
|
|
326
|
+
return ((optionalMessages && isMessage(field) && !isRepeated(field)) ||
|
|
327
|
+
(optionalAll && !(messageOptions === null || messageOptions === void 0 ? void 0 : messageOptions.mapEntry)) ||
|
|
328
|
+
field.proto3Optional);
|
|
329
|
+
}
|
|
330
|
+
exports.isOptionalProperty = isOptionalProperty;
|
|
317
331
|
/** This includes all scalars, enums and the [groups type](https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/DescriptorProtos.FieldDescriptorProto.Type.html#TYPE_GROUP) */
|
|
318
332
|
function isPrimitive(field) {
|
|
319
333
|
return !isMessage(field);
|
|
@@ -347,6 +361,19 @@ function isLong(field) {
|
|
|
347
361
|
return basicLongWireType(field.type) !== undefined;
|
|
348
362
|
}
|
|
349
363
|
exports.isLong = isLong;
|
|
364
|
+
function isWholeNumber(field) {
|
|
365
|
+
return (field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT32 ||
|
|
366
|
+
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_INT64 ||
|
|
367
|
+
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT32 ||
|
|
368
|
+
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_UINT64 ||
|
|
369
|
+
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT32 ||
|
|
370
|
+
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SINT64 ||
|
|
371
|
+
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED32 ||
|
|
372
|
+
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_FIXED64 ||
|
|
373
|
+
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED32 ||
|
|
374
|
+
field.type === ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_SFIXED64);
|
|
375
|
+
}
|
|
376
|
+
exports.isWholeNumber = isWholeNumber;
|
|
350
377
|
function isMapType(ctx, messageDesc, field) {
|
|
351
378
|
return detectMapType(ctx, messageDesc, field) !== undefined;
|
|
352
379
|
}
|
|
@@ -462,11 +489,14 @@ function messageToTypeName(ctx, protoType, typeOptions = {}) {
|
|
|
462
489
|
// them to basic built-in types, we union the type with undefined to
|
|
463
490
|
// indicate the value is optional. Exceptions:
|
|
464
491
|
// - If the field is repeated, values cannot be undefined.
|
|
465
|
-
// - If useOptionals=
|
|
466
|
-
// properties, so there's no need for that union.
|
|
492
|
+
// - If useOptionals='messages' or useOptionals='all', all non-scalar types
|
|
493
|
+
// are already optional properties, so there's no need for that union.
|
|
467
494
|
let valueType = valueTypeName(ctx, protoType);
|
|
468
495
|
if (!typeOptions.keepValueType && valueType) {
|
|
469
|
-
if (!!typeOptions.repeated ||
|
|
496
|
+
if (!!typeOptions.repeated ||
|
|
497
|
+
options.useOptionals === true ||
|
|
498
|
+
options.useOptionals === 'messages' ||
|
|
499
|
+
options.useOptionals === 'all') {
|
|
470
500
|
return valueType;
|
|
471
501
|
}
|
|
472
502
|
return ts_poet_1.code `${valueType} | undefined`;
|
|
@@ -509,18 +539,21 @@ function toTypeName(ctx, messageDesc, field) {
|
|
|
509
539
|
// in messageToTypeName, so no need to consider them for that here.
|
|
510
540
|
return type;
|
|
511
541
|
}
|
|
512
|
-
// By default (useOptionals=
|
|
542
|
+
// By default (useOptionals='none', oneof=properties), non-scalar fields
|
|
513
543
|
// outside oneofs and all fields within a oneof clause need to be unioned
|
|
514
544
|
// with `undefined` to indicate the value is optional.
|
|
515
545
|
//
|
|
516
|
-
// When useOptionals=
|
|
517
|
-
// properties, so no need for the union with
|
|
546
|
+
// When useOptionals='messages' or useOptionals='all', non-scalar fields are
|
|
547
|
+
// translated to optional properties, so no need for the union with
|
|
548
|
+
// `undefined` here.
|
|
518
549
|
//
|
|
519
550
|
// When oneof=unions, we generate a single property for the entire `oneof`
|
|
520
551
|
// clause, spelling each option out inside a large type union. No need for
|
|
521
552
|
// union with `undefined` here, either.
|
|
522
553
|
const { options } = ctx;
|
|
523
|
-
if ((!isWithinOneOf(field) &&
|
|
554
|
+
if ((!isWithinOneOf(field) &&
|
|
555
|
+
isMessage(field) &&
|
|
556
|
+
(options.useOptionals === false || options.useOptionals === 'none')) ||
|
|
524
557
|
(isWithinOneOf(field) && options.oneof === options_1.OneofOption.PROPERTIES) ||
|
|
525
558
|
(isWithinOneOf(field) && field.proto3Optional)) {
|
|
526
559
|
return ts_poet_1.code `${type} | undefined`;
|
package/build/utils.js
CHANGED
|
@@ -145,14 +145,14 @@ class FormattedMethodDescriptor {
|
|
|
145
145
|
}
|
|
146
146
|
exports.FormattedMethodDescriptor = FormattedMethodDescriptor;
|
|
147
147
|
function determineFieldJsonName(field, options) {
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
|
|
151
|
-
const fromBooleanSnakeToCamel = options.snakeToCamel === true;
|
|
152
|
-
if (fromBooleanSnakeToCamel || fromStringSnakeToCamel) {
|
|
148
|
+
// jsonName will be camelCased by the protocol compiler, plus can be overridden by the user,
|
|
149
|
+
// so just use that instead of our own maybeSnakeToCamel
|
|
150
|
+
if (options.snakeToCamel.includes('json')) {
|
|
153
151
|
return field.jsonName;
|
|
154
152
|
}
|
|
155
|
-
|
|
153
|
+
else {
|
|
154
|
+
return field.name;
|
|
155
|
+
}
|
|
156
156
|
}
|
|
157
157
|
exports.determineFieldJsonName = determineFieldJsonName;
|
|
158
158
|
function impProto(options, module, type) {
|