ts-proto 1.97.0 → 1.97.1

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 CHANGED
@@ -1,3 +1,10 @@
1
+ ## [1.97.1](https://github.com/stephenh/ts-proto/compare/v1.97.0...v1.97.1) (2022-01-05)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * oneof=union breaks wrapper types [#458](https://github.com/stephenh/ts-proto/issues/458) ([#462](https://github.com/stephenh/ts-proto/issues/462)) ([dd16992](https://github.com/stephenh/ts-proto/commit/dd16992a409f24e88e3a142830cd0745f50dbd10))
7
+
1
8
  # [1.97.0](https://github.com/stephenh/ts-proto/compare/v1.96.1...v1.97.0) (2021-12-30)
2
9
 
3
10
 
package/build/main.js CHANGED
@@ -86,8 +86,8 @@ function generateFile(ctx, fileDesc) {
86
86
  if (options.outputPartialMethods) {
87
87
  staticMembers.push(generateFromPartial(ctx, fullName, message));
88
88
  }
89
- staticMembers.push(...generateWrap(fullTypeName));
90
- staticMembers.push(...generateUnwrap(fullTypeName));
89
+ staticMembers.push(...generateWrap(ctx, fullTypeName));
90
+ staticMembers.push(...generateUnwrap(ctx, fullTypeName));
91
91
  chunks.push(ts_poet_1.code `
92
92
  export const ${ts_poet_1.def(fullName)} = {
93
93
  ${ts_poet_1.joinCode(staticMembers, { on: ',\n\n' })}
@@ -195,6 +195,7 @@ function makeUtils(options) {
195
195
  ...makeDeepPartial(options, longs),
196
196
  ...makeTimestampMethods(options, longs),
197
197
  ...longs,
198
+ ...makeComparisonUtils(),
198
199
  };
199
200
  }
200
201
  exports.makeUtils = makeUtils;
@@ -396,6 +397,17 @@ function makeTimestampMethods(options, longs) {
396
397
  `);
397
398
  return { toTimestamp, fromTimestamp, fromJsonTimestamp };
398
399
  }
400
+ function makeComparisonUtils() {
401
+ const isObject = ts_poet_1.conditionalOutput('isObject', ts_poet_1.code `
402
+ function isObject(value: any): boolean {
403
+ return typeof value === 'object' && value !== null;
404
+ }`);
405
+ const isSet = ts_poet_1.conditionalOutput('isSet', ts_poet_1.code `
406
+ function isSet(value: any): boolean {
407
+ return value !== null && value !== undefined;
408
+ }`);
409
+ return { isObject, isSet };
410
+ }
399
411
  // Create the interface with properties
400
412
  function generateInterfaceDeclaration(ctx, fullName, messageDesc, sourceInfo, fullTypeName) {
401
413
  var _a;
@@ -811,7 +823,7 @@ function generateFromJson(ctx, fullName, messageDesc) {
811
823
  messageDesc.field.forEach((field) => {
812
824
  const fieldName = case_1.maybeSnakeToCamel(field.name, options);
813
825
  const jsonName = utils_1.determineFieldJsonName(field, options);
814
- // get a generic 'reader.doSomething' bit that is specific to the basic type
826
+ // get code that extracts value from incoming object
815
827
  const readSnippet = (from) => {
816
828
  if (types_1.isEnum(field)) {
817
829
  const fromJson = types_1.getEnumMethod(ctx, field.typeName, 'FromJSON');
@@ -846,6 +858,9 @@ function generateFromJson(ctx, fullName, messageDesc) {
846
858
  else if (types_1.isAnyValueType(field) || types_1.isStructType(field)) {
847
859
  return ts_poet_1.code `${from}`;
848
860
  }
861
+ else if (types_1.isListValueType(field)) {
862
+ return ts_poet_1.code `[...${from}]`;
863
+ }
849
864
  else if (types_1.isValueType(ctx, field)) {
850
865
  const valueType = types_1.valueTypeName(ctx, field.typeName);
851
866
  if (types_1.isLongValueType(field) && options.forceLong === options_1.LongOption.LONG) {
@@ -854,9 +869,6 @@ function generateFromJson(ctx, fullName, messageDesc) {
854
869
  else if (types_1.isBytesValueType(field)) {
855
870
  return ts_poet_1.code `new ${case_1.capitalize(valueType.toCodeString())}(${from})`;
856
871
  }
857
- else if (types_1.isListValueType(field)) {
858
- return ts_poet_1.code `[...${from}]`;
859
- }
860
872
  else {
861
873
  return ts_poet_1.code `${case_1.capitalize(valueType.toCodeString())}(${from})`;
862
874
  }
@@ -923,22 +935,23 @@ function generateFromJson(ctx, fullName, messageDesc) {
923
935
  acc[${i}] = ${readSnippet('value')};
924
936
  return acc;
925
937
  }, {});
926
- `);
927
- }
928
- else if (types_1.isAnyValueType(field)) {
929
- chunks.push(ts_poet_1.code `
930
- message.${fieldName} = Array.isArray(object?.${jsonName}) ? [...object.${jsonName}] : [];
931
938
  `);
932
939
  }
933
940
  else {
934
- // Explicit `any` type required to make TS with noImplicitAny happy. `object` is also `any` here.
935
- chunks.push(ts_poet_1.code `
936
- message.${fieldName} = (object.${jsonName} ?? []).map((e: any) => ${readSnippet('e')});
937
- `);
941
+ const readValueSnippet = readSnippet('e');
942
+ if (readValueSnippet.toString() === ts_poet_1.code `e`.toString()) {
943
+ chunks.push(ts_poet_1.code `message.${fieldName} = Array.isArray(object?.${jsonName}) ? [...object.${jsonName}] : [];`);
944
+ }
945
+ else {
946
+ // Explicit `any` type required to make TS with noImplicitAny happy. `object` is also `any` here.
947
+ chunks.push(ts_poet_1.code `
948
+ message.${fieldName} = Array.isArray(object?.${jsonName}) ? object.${jsonName}.map((e: any) => ${readValueSnippet}): [];
949
+ `);
950
+ }
938
951
  }
939
952
  }
940
953
  else if (types_1.isWithinOneOfThatShouldBeUnion(options, field)) {
941
- chunks.push(ts_poet_1.code `if (object.${jsonName} !== undefined && object.${jsonName} !== null) {`);
954
+ chunks.push(ts_poet_1.code `if (${ctx.utils.isSet}(object.${jsonName})) {`);
942
955
  const oneofName = case_1.maybeSnakeToCamel(messageDesc.oneofDecl[field.oneofIndex].name, options);
943
956
  chunks.push(ts_poet_1.code `
944
957
  message.${oneofName} = { $case: '${fieldName}', ${fieldName}: ${readSnippet(`object.${jsonName}`)} }
@@ -946,22 +959,27 @@ function generateFromJson(ctx, fullName, messageDesc) {
946
959
  chunks.push(ts_poet_1.code `}`);
947
960
  }
948
961
  else if (types_1.isAnyValueType(field)) {
949
- chunks.push(ts_poet_1.code `message.${fieldName} = object.${fieldName};`);
962
+ chunks.push(ts_poet_1.code `message.${fieldName} = ${ctx.utils.isSet}(object?.${jsonName})
963
+ ? ${readSnippet(`object.${jsonName}`)}
964
+ : undefined;
965
+ `);
950
966
  }
951
967
  else if (types_1.isStructType(field)) {
952
- chunks.push(ts_poet_1.code `message.${fieldName} = typeof(object.${fieldName}) === 'object' ? object.${fieldName} : undefined;`);
968
+ chunks.push(ts_poet_1.code `message.${fieldName} = ${ctx.utils.isObject}(object.${jsonName})
969
+ ? ${readSnippet(`object.${jsonName}`)}
970
+ : undefined;`);
953
971
  }
954
972
  else if (types_1.isListValueType(field)) {
955
973
  chunks.push(ts_poet_1.code `
956
- message.${fieldName} = Array.isArray(object?.${fieldName})
957
- ? ${readSnippet(`object.${fieldName}`)}
974
+ message.${fieldName} = Array.isArray(object.${jsonName})
975
+ ? ${readSnippet(`object.${jsonName}`)}
958
976
  : ${'undefined'};
959
977
  `);
960
978
  }
961
979
  else {
962
980
  const fallback = types_1.isWithinOneOf(field) ? 'undefined' : types_1.defaultValue(ctx, field);
963
981
  chunks.push(ts_poet_1.code `
964
- message.${fieldName} = (object.${jsonName} !== undefined && object.${jsonName} !== null)
982
+ message.${fieldName} = ${ctx.utils.isSet}(object.${jsonName})
965
983
  ? ${readSnippet(`object.${jsonName}`)}
966
984
  : ${fallback};
967
985
  `);
@@ -1223,7 +1241,7 @@ function generateFromPartial(ctx, fullName, messageDesc) {
1223
1241
  chunks.push(ts_poet_1.code `}`);
1224
1242
  return ts_poet_1.joinCode(chunks, { on: '\n' });
1225
1243
  }
1226
- function generateWrap(fullProtoTypeName) {
1244
+ function generateWrap(ctx, fullProtoTypeName) {
1227
1245
  const chunks = [];
1228
1246
  if (types_1.isStructTypeName(fullProtoTypeName)) {
1229
1247
  chunks.push(ts_poet_1.code `wrap(object: {[key: string]: any} | undefined): Struct {
@@ -1237,7 +1255,29 @@ function generateWrap(fullProtoTypeName) {
1237
1255
  }`);
1238
1256
  }
1239
1257
  if (types_1.isAnyValueTypeName(fullProtoTypeName)) {
1240
- chunks.push(ts_poet_1.code `wrap(value: any): Value {
1258
+ if (ctx.options.oneof === options_1.OneofOption.UNIONS) {
1259
+ chunks.push(ts_poet_1.code `wrap(value: any): Value {
1260
+ if (value === null) {
1261
+ return {kind: {$case: 'nullValue', nullValue: NullValue.NULL_VALUE}};
1262
+ } else if (typeof value === 'boolean') {
1263
+ return {kind: {$case: 'boolValue', boolValue: value}};
1264
+ } else if (typeof value === 'number') {
1265
+ return {kind: {$case: 'numberValue', numberValue: value}};
1266
+ } else if (typeof value === 'string') {
1267
+ return {kind: {$case: 'stringValue', stringValue: value}};
1268
+ } else if (Array.isArray(value)) {
1269
+ return {kind: {$case: 'listValue', listValue: value}};
1270
+ } else if (typeof value === 'object') {
1271
+ return {kind: {$case: 'structValue', structValue: value}};
1272
+ } else if (typeof value === 'undefined') {
1273
+ return {} as Value;
1274
+ } else {
1275
+ throw new Error('Unsupported any value type: ' + typeof value);
1276
+ }
1277
+ }`);
1278
+ }
1279
+ else {
1280
+ chunks.push(ts_poet_1.code `wrap(value: any): Value {
1241
1281
  if (value === null) {
1242
1282
  return {nullValue: NullValue.NULL_VALUE} as Value;
1243
1283
  } else if (typeof value === 'boolean') {
@@ -1256,15 +1296,16 @@ function generateWrap(fullProtoTypeName) {
1256
1296
  throw new Error('Unsupported any value type: ' + typeof value);
1257
1297
  }
1258
1298
  }`);
1299
+ }
1259
1300
  }
1260
1301
  if (types_1.isListValueTypeName(fullProtoTypeName)) {
1261
- chunks.push(ts_poet_1.code `wrap(value: Array<any>): ListValue {
1262
- return {values: value};
1302
+ chunks.push(ts_poet_1.code `wrap(value: Array<any> | undefined): ListValue {
1303
+ return {values: value ?? []};
1263
1304
  }`);
1264
1305
  }
1265
1306
  return chunks;
1266
1307
  }
1267
- function generateUnwrap(fullProtoTypeName) {
1308
+ function generateUnwrap(ctx, fullProtoTypeName) {
1268
1309
  const chunks = [];
1269
1310
  if (types_1.isStructTypeName(fullProtoTypeName)) {
1270
1311
  chunks.push(ts_poet_1.code `unwrap(message: Struct): {[key: string]: any} {
@@ -1276,7 +1317,27 @@ function generateUnwrap(fullProtoTypeName) {
1276
1317
  }`);
1277
1318
  }
1278
1319
  if (types_1.isAnyValueTypeName(fullProtoTypeName)) {
1279
- chunks.push(ts_poet_1.code `unwrap(message: Value): string | number | boolean | Object | null | Array<any> | undefined {
1320
+ if (ctx.options.oneof === options_1.OneofOption.UNIONS) {
1321
+ chunks.push(ts_poet_1.code `unwrap(message: Value): string | number | boolean | Object | null | Array<any> | undefined {
1322
+ if (message.kind?.$case === 'nullValue') {
1323
+ return null;
1324
+ } else if (message.kind?.$case === 'numberValue') {
1325
+ return message.kind?.numberValue;
1326
+ } else if (message.kind?.$case === 'stringValue') {
1327
+ return message.kind?.stringValue;
1328
+ } else if (message.kind?.$case === 'boolValue') {
1329
+ return message.kind?.boolValue;
1330
+ } else if (message.kind?.$case === 'structValue') {
1331
+ return message.kind?.structValue;
1332
+ } else if (message.kind?.$case === 'listValue') {
1333
+ return message.kind?.listValue;
1334
+ } else {
1335
+ return undefined;
1336
+ }
1337
+ }`);
1338
+ }
1339
+ else {
1340
+ chunks.push(ts_poet_1.code `unwrap(message: Value): string | number | boolean | Object | null | Array<any> | undefined {
1280
1341
  if (message?.stringValue !== undefined) {
1281
1342
  return message.stringValue;
1282
1343
  } else if (message?.numberValue !== undefined) {
@@ -1292,6 +1353,7 @@ function generateUnwrap(fullProtoTypeName) {
1292
1353
  }
1293
1354
  return undefined;
1294
1355
  }`);
1356
+ }
1295
1357
  }
1296
1358
  if (types_1.isListValueTypeName(fullProtoTypeName)) {
1297
1359
  chunks.push(ts_poet_1.code `unwrap(message: ListValue): Array<any> {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-proto",
3
- "version": "1.97.0",
3
+ "version": "1.97.1",
4
4
  "description": "",
5
5
  "main": "build/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",