ts-proto 1.106.0 → 1.107.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 +21 -0
- package/README.markdown +2 -0
- package/build/main.js +38 -30
- package/build/options.js +9 -2
- package/build/utils.js +5 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
# [1.107.0](https://github.com/stephenh/ts-proto/compare/v1.106.2...v1.107.0) (2022-03-04)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* Allow simultaneous services and generic service definitions ([#512](https://github.com/stephenh/ts-proto/issues/512)) ([680831e](https://github.com/stephenh/ts-proto/commit/680831e76f1a4ceb4337442a157d7e702cb14bfc))
|
|
7
|
+
|
|
8
|
+
## [1.106.2](https://github.com/stephenh/ts-proto/compare/v1.106.1...v1.106.2) (2022-02-27)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* Add M1/ARM support for the test suite ([#516](https://github.com/stephenh/ts-proto/issues/516)) ([7cf5625](https://github.com/stephenh/ts-proto/commit/7cf56251726d149eebd015367476f36e4edb48aa))
|
|
14
|
+
|
|
15
|
+
## [1.106.1](https://github.com/stephenh/ts-proto/compare/v1.106.0...v1.106.1) (2022-02-21)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* support json_name containing hyphen on all field types ([#521](https://github.com/stephenh/ts-proto/issues/521)) ([8d9e78e](https://github.com/stephenh/ts-proto/commit/8d9e78eb39c460f6727458f6a2dd149deb983668))
|
|
21
|
+
|
|
1
22
|
# [1.106.0](https://github.com/stephenh/ts-proto/compare/v1.105.2...v1.106.0) (2022-02-21)
|
|
2
23
|
|
|
3
24
|
|
package/README.markdown
CHANGED
|
@@ -362,6 +362,8 @@ Generated code will be placed in the Gradle build directory.
|
|
|
362
362
|
|
|
363
363
|
- With `--ts_proto_opt=outputServices=generic-definitions`, ts-proto will output generic (framework-agnostic) service definitions. These definitions contain descriptors for each method with links to request and response types, which allows to generate server and client stubs at runtime, and also generate strong types for them at compile time. An example of a library that uses this approach is [nice-grpc](https://github.com/deeplay-io/nice-grpc).
|
|
364
364
|
|
|
365
|
+
- With `--ts_proto_opt=outputServices=generic-definitions,outputServices=default`, ts-proto will output both generic definitions and interfaces. This is useful if you want to rely on the interfaces, but also have some reflection capabilities at runtime.
|
|
366
|
+
|
|
365
367
|
- With `--ts_proto_opt=outputServices=false`, or `=none`, ts-proto will output NO service definitions.
|
|
366
368
|
|
|
367
369
|
- With `--ts_proto_opt=emitImportedFiles=false`, ts-proto will not emit `google/protobuf/*` files unless you explicit add files to `protoc` like this
|
package/build/main.js
CHANGED
|
@@ -118,29 +118,34 @@ function generateFile(ctx, fileDesc) {
|
|
|
118
118
|
}
|
|
119
119
|
chunks.push(ts_poet_1.code `export const ${serviceConstName} = "${serviceDesc.name}";`);
|
|
120
120
|
}
|
|
121
|
-
else
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
chunks.push(generate_grpc_web_1.generateGrpcServiceDesc(fileDesc, serviceDesc));
|
|
137
|
-
serviceDesc.method.forEach((method) => {
|
|
138
|
-
chunks.push(generate_grpc_web_1.generateGrpcMethodDesc(ctx, serviceDesc, method));
|
|
139
|
-
if (method.serverStreaming) {
|
|
140
|
-
hasServerStreamingMethods = true;
|
|
121
|
+
else {
|
|
122
|
+
const uniqueServices = [...new Set(options.outputServices)].sort();
|
|
123
|
+
uniqueServices.forEach((outputService) => {
|
|
124
|
+
if (outputService === options_1.ServiceOption.GRPC) {
|
|
125
|
+
chunks.push(generate_grpc_js_1.generateGrpcJsService(ctx, fileDesc, sInfo, serviceDesc));
|
|
126
|
+
}
|
|
127
|
+
else if (outputService === options_1.ServiceOption.GENERIC) {
|
|
128
|
+
chunks.push(generate_generic_service_definition_1.generateGenericServiceDefinition(ctx, fileDesc, sInfo, serviceDesc));
|
|
129
|
+
}
|
|
130
|
+
else if (outputService === options_1.ServiceOption.DEFAULT) {
|
|
131
|
+
// This service could be Twirp or grpc-web or JSON (maybe). So far all of their
|
|
132
|
+
// interfaces are fairly similar so we share the same service interface.
|
|
133
|
+
chunks.push(generate_services_1.generateService(ctx, fileDesc, sInfo, serviceDesc));
|
|
134
|
+
if (options.outputClientImpl === true) {
|
|
135
|
+
chunks.push(generate_services_1.generateServiceClientImpl(ctx, fileDesc, serviceDesc));
|
|
141
136
|
}
|
|
142
|
-
|
|
143
|
-
|
|
137
|
+
else if (options.outputClientImpl === 'grpc-web') {
|
|
138
|
+
chunks.push(generate_grpc_web_1.generateGrpcClientImpl(ctx, fileDesc, serviceDesc));
|
|
139
|
+
chunks.push(generate_grpc_web_1.generateGrpcServiceDesc(fileDesc, serviceDesc));
|
|
140
|
+
serviceDesc.method.forEach((method) => {
|
|
141
|
+
chunks.push(generate_grpc_web_1.generateGrpcMethodDesc(ctx, serviceDesc, method));
|
|
142
|
+
if (method.serverStreaming) {
|
|
143
|
+
hasServerStreamingMethods = true;
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
});
|
|
144
149
|
}
|
|
145
150
|
serviceDesc.method.forEach((methodDesc, index) => {
|
|
146
151
|
if (methodDesc.serverStreaming || methodDesc.clientStreaming) {
|
|
@@ -148,7 +153,9 @@ function generateFile(ctx, fileDesc) {
|
|
|
148
153
|
}
|
|
149
154
|
});
|
|
150
155
|
});
|
|
151
|
-
if (options.outputServices
|
|
156
|
+
if (options.outputServices.includes(options_1.ServiceOption.DEFAULT) &&
|
|
157
|
+
options.outputClientImpl &&
|
|
158
|
+
fileDesc.service.length > 0) {
|
|
152
159
|
if (options.outputClientImpl === true) {
|
|
153
160
|
chunks.push(generate_services_1.generateRpcType(ctx, hasStreamingMethods));
|
|
154
161
|
}
|
|
@@ -897,6 +904,7 @@ function generateFromJson(ctx, fullName, messageDesc) {
|
|
|
897
904
|
const fieldName = case_1.maybeSnakeToCamel(field.name, options);
|
|
898
905
|
const jsonName = utils_1.getFieldJsonName(field, options);
|
|
899
906
|
const jsonProperty = utils_1.getPropertyAccessor('object', jsonName);
|
|
907
|
+
const jsonPropertyOptional = utils_1.getPropertyAccessor('object', jsonName, true);
|
|
900
908
|
// get code that extracts value from incoming object
|
|
901
909
|
const readSnippet = (from) => {
|
|
902
910
|
if (types_1.isEnum(field)) {
|
|
@@ -1025,12 +1033,12 @@ function generateFromJson(ctx, fullName, messageDesc) {
|
|
|
1025
1033
|
else {
|
|
1026
1034
|
const readValueSnippet = readSnippet('e');
|
|
1027
1035
|
if (readValueSnippet.toString() === ts_poet_1.code `e`.toString()) {
|
|
1028
|
-
chunks.push(ts_poet_1.code `${fieldName}: Array.isArray(
|
|
1036
|
+
chunks.push(ts_poet_1.code `${fieldName}: Array.isArray(${jsonPropertyOptional}) ? [...${jsonProperty}] : [],`);
|
|
1029
1037
|
}
|
|
1030
1038
|
else {
|
|
1031
1039
|
// Explicit `any` type required to make TS with noImplicitAny happy. `object` is also `any` here.
|
|
1032
1040
|
chunks.push(ts_poet_1.code `
|
|
1033
|
-
${fieldName}: Array.isArray(
|
|
1041
|
+
${fieldName}: Array.isArray(${jsonPropertyOptional}) ? ${jsonProperty}.map((e: any) => ${readValueSnippet}): [],
|
|
1034
1042
|
`);
|
|
1035
1043
|
}
|
|
1036
1044
|
}
|
|
@@ -1051,7 +1059,7 @@ function generateFromJson(ctx, fullName, messageDesc) {
|
|
|
1051
1059
|
}
|
|
1052
1060
|
}
|
|
1053
1061
|
else if (types_1.isAnyValueType(field)) {
|
|
1054
|
-
chunks.push(ts_poet_1.code `${fieldName}: ${ctx.utils.isSet}(
|
|
1062
|
+
chunks.push(ts_poet_1.code `${fieldName}: ${ctx.utils.isSet}(${jsonPropertyOptional})
|
|
1055
1063
|
? ${readSnippet(`${jsonProperty}`)}
|
|
1056
1064
|
: undefined,
|
|
1057
1065
|
`);
|
|
@@ -1185,10 +1193,10 @@ function generateToJson(ctx, fullName, messageDesc) {
|
|
|
1185
1193
|
if (types_1.isMapType(ctx, messageDesc, field)) {
|
|
1186
1194
|
// Maps might need their values transformed, i.e. bytes --> base64
|
|
1187
1195
|
chunks.push(ts_poet_1.code `
|
|
1188
|
-
|
|
1196
|
+
${jsonProperty} = {};
|
|
1189
1197
|
if (message.${fieldName}) {
|
|
1190
1198
|
Object.entries(message.${fieldName}).forEach(([k, v]) => {
|
|
1191
|
-
|
|
1199
|
+
${jsonProperty}[k] = ${readSnippet('v')};
|
|
1192
1200
|
});
|
|
1193
1201
|
}
|
|
1194
1202
|
`);
|
|
@@ -1197,9 +1205,9 @@ function generateToJson(ctx, fullName, messageDesc) {
|
|
|
1197
1205
|
// Arrays might need their elements transformed
|
|
1198
1206
|
chunks.push(ts_poet_1.code `
|
|
1199
1207
|
if (message.${fieldName}) {
|
|
1200
|
-
|
|
1208
|
+
${jsonProperty} = message.${fieldName}.map(e => ${readSnippet('e')});
|
|
1201
1209
|
} else {
|
|
1202
|
-
|
|
1210
|
+
${jsonProperty} = [];
|
|
1203
1211
|
}
|
|
1204
1212
|
`);
|
|
1205
1213
|
}
|
package/build/options.js
CHANGED
|
@@ -51,7 +51,7 @@ function defaultOptions() {
|
|
|
51
51
|
constEnums: false,
|
|
52
52
|
enumsAsLiterals: false,
|
|
53
53
|
outputClientImpl: true,
|
|
54
|
-
outputServices:
|
|
54
|
+
outputServices: [],
|
|
55
55
|
returnObservable: false,
|
|
56
56
|
addGrpcMetadata: false,
|
|
57
57
|
addNestjsRestParameter: false,
|
|
@@ -95,7 +95,14 @@ function optionsFromParameter(parameter) {
|
|
|
95
95
|
}
|
|
96
96
|
// Treat outputServices=false as NONE
|
|
97
97
|
if (options.outputServices === false) {
|
|
98
|
-
options.outputServices = ServiceOption.NONE;
|
|
98
|
+
options.outputServices = [ServiceOption.NONE];
|
|
99
|
+
}
|
|
100
|
+
// Existing type-coercion inside parseParameter leaves a little to be desired.
|
|
101
|
+
if (typeof options.outputServices == 'string') {
|
|
102
|
+
options.outputServices = [options.outputServices];
|
|
103
|
+
}
|
|
104
|
+
if (options.outputServices.length == 0) {
|
|
105
|
+
options.outputServices = [ServiceOption.DEFAULT];
|
|
99
106
|
}
|
|
100
107
|
if (options.useDate === true) {
|
|
101
108
|
// Treat useDate=true as DATE
|
package/build/utils.js
CHANGED
|
@@ -137,7 +137,7 @@ class FormattedMethodDescriptor {
|
|
|
137
137
|
*/
|
|
138
138
|
static formatName(methodName, options) {
|
|
139
139
|
let result = methodName;
|
|
140
|
-
if (options.lowerCaseServiceMethods || options.outputServices
|
|
140
|
+
if (options.lowerCaseServiceMethods || options.outputServices.includes(options_1.ServiceOption.GRPC)) {
|
|
141
141
|
result = case_1.camelCase(result);
|
|
142
142
|
}
|
|
143
143
|
return result;
|
|
@@ -160,12 +160,13 @@ exports.getFieldJsonName = getFieldJsonName;
|
|
|
160
160
|
* For simplicity, we don't match the ECMA 5/6 rules for valid identifiers exactly, and return array syntax liberally.
|
|
161
161
|
* @param objectName
|
|
162
162
|
* @param propertyName
|
|
163
|
+
* @param optional
|
|
163
164
|
*/
|
|
164
|
-
function getPropertyAccessor(objectName, propertyName) {
|
|
165
|
+
function getPropertyAccessor(objectName, propertyName, optional = false) {
|
|
165
166
|
let validIdentifier = /^[a-zA-Z_$][\w$]*$/;
|
|
166
167
|
return validIdentifier.test(propertyName)
|
|
167
|
-
? `${objectName}.${propertyName}`
|
|
168
|
-
: `${objectName}[${JSON.stringify(propertyName)}]`;
|
|
168
|
+
? `${objectName}${optional ? '?' : ''}.${propertyName}`
|
|
169
|
+
: `${objectName}${optional ? '?.' : ''}[${JSON.stringify(propertyName)}]`;
|
|
169
170
|
}
|
|
170
171
|
exports.getPropertyAccessor = getPropertyAccessor;
|
|
171
172
|
function impProto(options, module, type) {
|