ts-proto 1.161.1 → 1.162.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/README.markdown CHANGED
@@ -477,6 +477,8 @@ Generated code will be placed in the Gradle build directory.
477
477
 
478
478
  Note that, as indicated, this means Object.keys will not include set-by-default fields, so if you have code that iterates over messages keys in a generic fashion, it will have to also iterate over keys inherited from the prototype.
479
479
 
480
+ - With `--ts_proto_opt=useJsonName=true`, `json_name` defined in protofiles will be used instead of message field names.
481
+
480
482
  - With `--ts_proto_opt=useJsonWireFormat=true`, the generated code will reflect the JSON representation of Protobuf messages.
481
483
 
482
484
  Requires `onlyTypes=true`. Implies `useDate=string` and `stringEnums=true`. This option is to generate types that can be directly used with marshalling/unmarshalling Protobuf messages serialized as JSON.
package/build/main.js CHANGED
@@ -615,10 +615,10 @@ function generateInterfaceDeclaration(ctx, fullName, messageDesc, sourceInfo, fu
615
615
  }
616
616
  const info = sourceInfo.lookup(sourceInfo_1.Fields.message.field, index);
617
617
  (0, utils_1.maybeAddComment)(info, chunks, (_a = fieldDesc.options) === null || _a === void 0 ? void 0 : _a.deprecated);
618
- const name = (0, case_1.maybeSnakeToCamel)(fieldDesc.name, options);
618
+ const fieldKey = (0, utils_1.safeAccessor)((0, utils_1.getFieldName)(fieldDesc, options));
619
619
  const isOptional = (0, types_1.isOptionalProperty)(fieldDesc, messageDesc.options, options);
620
620
  const type = (0, types_1.toTypeName)(ctx, messageDesc, fieldDesc, isOptional);
621
- chunks.push((0, ts_poet_1.code) `${maybeReadonly(options)}${name}${isOptional ? "?" : ""}: ${type}, `);
621
+ chunks.push((0, ts_poet_1.code) `${maybeReadonly(options)}${fieldKey}${isOptional ? "?" : ""}: ${type}, `);
622
622
  });
623
623
  if (ctx.options.unknownFields) {
624
624
  chunks.push((0, ts_poet_1.code) `_unknownFields?: {[key: number]: Uint8Array[]} | undefined,`);
@@ -669,15 +669,17 @@ function generateBaseInstanceFactory(ctx, fullName, messageDesc, fullTypeName) {
669
669
  const { oneofIndex } = field;
670
670
  if (!processedOneofs.has(oneofIndex)) {
671
671
  processedOneofs.add(oneofIndex);
672
- const name = (0, case_1.maybeSnakeToCamel)(messageDesc.oneofDecl[oneofIndex].name, ctx.options);
673
- fields.push((0, ts_poet_1.code) `${name}: undefined`);
672
+ const name = options.useJsonName
673
+ ? (0, utils_1.getFieldName)(field, options)
674
+ : (0, case_1.maybeSnakeToCamel)(messageDesc.oneofDecl[oneofIndex].name, ctx.options);
675
+ fields.push((0, ts_poet_1.code) `${(0, utils_1.safeAccessor)(name)}: undefined`);
674
676
  }
675
677
  continue;
676
678
  }
677
679
  if (!options.initializeFieldsAsUndefined && (0, types_1.isOptionalProperty)(field, messageDesc.options, options)) {
678
680
  continue;
679
681
  }
680
- const name = (0, case_1.maybeSnakeToCamel)(field.name, ctx.options);
682
+ const fieldKey = (0, utils_1.safeAccessor)((0, utils_1.getFieldName)(field, options));
681
683
  const val = (0, types_1.isWithinOneOf)(field)
682
684
  ? "undefined"
683
685
  : (0, types_1.isMapType)(ctx, messageDesc, field)
@@ -687,7 +689,7 @@ function generateBaseInstanceFactory(ctx, fullName, messageDesc, fullTypeName) {
687
689
  : (0, types_1.isRepeated)(field)
688
690
  ? "[]"
689
691
  : (0, types_1.defaultValue)(ctx, field);
690
- fields.push((0, ts_poet_1.code) `${name}: ${val}`);
692
+ fields.push((0, ts_poet_1.code) `${fieldKey}: ${val}`);
691
693
  }
692
694
  if ((0, options_1.addTypeToMessages)(options)) {
693
695
  fields.unshift((0, ts_poet_1.code) `$type: '${fullTypeName}'`);
@@ -795,7 +797,8 @@ function generateDecode(ctx, fullName, messageDesc) {
795
797
  `);
796
798
  // add a case for each incoming field
797
799
  messageDesc.field.forEach((field) => {
798
- const fieldName = (0, case_1.maybeSnakeToCamel)(field.name, options);
800
+ const fieldName = (0, utils_1.getFieldName)(field, options);
801
+ const messageProperty = (0, utils_1.getPropertyAccessor)("message", fieldName);
799
802
  chunks.push((0, ts_poet_1.code) `case ${field.number}:`);
800
803
  const tag = ((field.number << 3) | (0, types_1.basicWireType)(field.type)) >>> 0;
801
804
  const tagCheck = (0, ts_poet_1.code) `
@@ -816,15 +819,15 @@ function generateDecode(ctx, fullName, messageDesc) {
816
819
  const generateMapType = (0, types_1.shouldGenerateJSMapType)(ctx, messageDesc, field);
817
820
  let valueSetterSnippet;
818
821
  if (generateMapType) {
819
- valueSetterSnippet = `message.${fieldName}${maybeNonNullAssertion}.set(${varName}.key, ${varName}.value)`;
822
+ valueSetterSnippet = `${messageProperty}${maybeNonNullAssertion}.set(${varName}.key, ${varName}.value)`;
820
823
  }
821
824
  else {
822
- valueSetterSnippet = `message.${fieldName}${maybeNonNullAssertion}[${varName}.key] = ${varName}.value`;
825
+ valueSetterSnippet = `${messageProperty}${maybeNonNullAssertion}[${varName}.key] = ${varName}.value`;
823
826
  }
824
827
  const initializerSnippet = initializerNecessary
825
828
  ? `
826
- if (message.${fieldName} === undefined) {
827
- message.${fieldName} = ${generateMapType ? "new Map()" : "{}"};
829
+ if (${messageProperty} === undefined) {
830
+ ${messageProperty} = ${generateMapType ? "new Map()" : "{}"};
828
831
  }`
829
832
  : "";
830
833
  chunks.push((0, ts_poet_1.code) `
@@ -839,15 +842,15 @@ function generateDecode(ctx, fullName, messageDesc) {
839
842
  else {
840
843
  const initializerSnippet = initializerNecessary
841
844
  ? `
842
- if (message.${fieldName} === undefined) {
843
- message.${fieldName} = [];
845
+ if (${messageProperty} === undefined) {
846
+ ${messageProperty} = [];
844
847
  }`
845
848
  : "";
846
849
  if ((0, types_1.packedType)(field.type) === undefined) {
847
850
  chunks.push((0, ts_poet_1.code) `
848
851
  ${tagCheck}
849
852
  ${initializerSnippet}
850
- message.${fieldName}${maybeNonNullAssertion}.push(${readSnippet});
853
+ ${messageProperty}${maybeNonNullAssertion}.push(${readSnippet});
851
854
  `);
852
855
  }
853
856
  else {
@@ -855,7 +858,7 @@ function generateDecode(ctx, fullName, messageDesc) {
855
858
  chunks.push((0, ts_poet_1.code) `
856
859
  if (tag === ${tag}) {
857
860
  ${initializerSnippet}
858
- message.${fieldName}${maybeNonNullAssertion}.push(${readSnippet});
861
+ ${messageProperty}${maybeNonNullAssertion}.push(${readSnippet});
859
862
 
860
863
  continue;
861
864
  }
@@ -864,7 +867,7 @@ function generateDecode(ctx, fullName, messageDesc) {
864
867
  ${initializerSnippet}
865
868
  const end2 = reader.uint32() + reader.pos;
866
869
  while (reader.pos < end2) {
867
- message.${fieldName}${maybeNonNullAssertion}.push(${readSnippet});
870
+ ${messageProperty}${maybeNonNullAssertion}.push(${readSnippet});
868
871
  }
869
872
 
870
873
  continue;
@@ -876,16 +879,18 @@ function generateDecode(ctx, fullName, messageDesc) {
876
879
  }
877
880
  }
878
881
  else if ((0, types_1.isWithinOneOfThatShouldBeUnion)(options, field)) {
879
- let oneofName = (0, case_1.maybeSnakeToCamel)(messageDesc.oneofDecl[field.oneofIndex].name, options);
882
+ const oneofNameWithMessage = options.useJsonName
883
+ ? messageProperty
884
+ : (0, utils_1.getPropertyAccessor)("message", (0, case_1.maybeSnakeToCamel)(messageDesc.oneofDecl[field.oneofIndex].name, options));
880
885
  chunks.push((0, ts_poet_1.code) `
881
886
  ${tagCheck}
882
- message.${oneofName} = { $case: '${fieldName}', ${fieldName}: ${readSnippet} };
887
+ ${oneofNameWithMessage} = { $case: '${fieldName}', ${fieldName}: ${readSnippet} };
883
888
  `);
884
889
  }
885
890
  else {
886
891
  chunks.push((0, ts_poet_1.code) `
887
892
  ${tagCheck}
888
- message.${fieldName} = ${readSnippet};
893
+ ${messageProperty} = ${readSnippet};
889
894
  `);
890
895
  }
891
896
  if (!(0, types_1.isRepeated)(field) || (0, types_1.packedType)(field.type) === undefined) {
@@ -1020,7 +1025,8 @@ function generateEncode(ctx, fullName, messageDesc) {
1020
1025
  .reduce((result, field) => ((result[field.oneofIndex] || (result[field.oneofIndex] = [])).push(field), result), {});
1021
1026
  // then add a case for each field
1022
1027
  messageDesc.field.forEach((field) => {
1023
- const fieldName = (0, case_1.maybeSnakeToCamel)(field.name, options);
1028
+ const fieldName = (0, utils_1.getFieldName)(field, options);
1029
+ const messageProperty = (0, utils_1.getPropertyAccessor)("message", fieldName);
1024
1030
  // get a generic writer.doSomething based on the basic type
1025
1031
  const writeSnippet = getEncodeWriteSnippet(ctx, field);
1026
1032
  const isOptional = (0, types_1.isOptionalProperty)(field, messageDesc.options, options);
@@ -1039,14 +1045,14 @@ function generateEncode(ctx, fullName, messageDesc) {
1039
1045
  const optionalAlternative = isOptional ? (useMapType ? " || new Map()" : " || {}") : "";
1040
1046
  if (useMapType) {
1041
1047
  chunks.push((0, ts_poet_1.code) `
1042
- (message.${fieldName}${optionalAlternative}).forEach((value, key) => {
1048
+ (${messageProperty}${optionalAlternative}).forEach((value, key) => {
1043
1049
  ${entryWriteSnippet}
1044
1050
  });
1045
1051
  `);
1046
1052
  }
1047
1053
  else {
1048
1054
  chunks.push((0, ts_poet_1.code) `
1049
- Object.entries(message.${fieldName}${optionalAlternative}).forEach(([key, value]) => {
1055
+ Object.entries(${messageProperty}${optionalAlternative}).forEach(([key, value]) => {
1050
1056
  ${entryWriteSnippet}
1051
1057
  });
1052
1058
  `);
@@ -1054,13 +1060,13 @@ function generateEncode(ctx, fullName, messageDesc) {
1054
1060
  }
1055
1061
  else if ((0, types_1.packedType)(field.type) === undefined) {
1056
1062
  const listWriteSnippet = (0, ts_poet_1.code) `
1057
- for (const v of message.${fieldName}) {
1063
+ for (const v of ${messageProperty}) {
1058
1064
  ${writeSnippet("v!")};
1059
1065
  }
1060
1066
  `;
1061
1067
  if (isOptional) {
1062
1068
  chunks.push((0, ts_poet_1.code) `
1063
- if (message.${fieldName} !== undefined && message.${fieldName}.length !== 0) {
1069
+ if (${messageProperty} !== undefined && ${messageProperty}.length !== 0) {
1064
1070
  ${listWriteSnippet}
1065
1071
  }
1066
1072
  `);
@@ -1078,14 +1084,14 @@ function generateEncode(ctx, fullName, messageDesc) {
1078
1084
  const toNumber = (0, types_1.getEnumMethod)(ctx, field.typeName, "ToNumber");
1079
1085
  const listWriteSnippet = (0, ts_poet_1.code) `
1080
1086
  writer.uint32(${tag}).fork();
1081
- for (const v of message.${fieldName}) {
1087
+ for (const v of ${messageProperty}) {
1082
1088
  writer.${(0, types_1.toReaderCall)(field)}(${toNumber}(v));
1083
1089
  }
1084
1090
  writer.ldelim();
1085
1091
  `;
1086
1092
  if (isOptional) {
1087
1093
  chunks.push((0, ts_poet_1.code) `
1088
- if (message.${fieldName} !== undefined && message.${fieldName}.length !== 0) {
1094
+ if (${messageProperty} !== undefined && ${messageProperty}.length !== 0) {
1089
1095
  ${listWriteSnippet}
1090
1096
  }
1091
1097
  `);
@@ -1100,7 +1106,7 @@ function generateEncode(ctx, fullName, messageDesc) {
1100
1106
  const rhs = (x) => ((0, types_1.isLong)(field) && options.forceLong === options_1.LongOption.BIGINT ? `${x}.toString()` : x);
1101
1107
  let listWriteSnippet = (0, ts_poet_1.code) `
1102
1108
  writer.uint32(${tag}).fork();
1103
- for (const v of message.${fieldName}) {
1109
+ for (const v of ${messageProperty}) {
1104
1110
  writer.${(0, types_1.toReaderCall)(field)}(${rhs("v")});
1105
1111
  }
1106
1112
  writer.ldelim();
@@ -1113,7 +1119,7 @@ function generateEncode(ctx, fullName, messageDesc) {
1113
1119
  case "sfixed64":
1114
1120
  listWriteSnippet = (0, ts_poet_1.code) `
1115
1121
  writer.uint32(${tag}).fork();
1116
- for (const v of message.${fieldName}) {
1122
+ for (const v of ${messageProperty}) {
1117
1123
  if (BigInt.asIntN(64, v) !== v) {
1118
1124
  throw new Error('a value provided in array field ${fieldName} of type ${fieldType} is too large');
1119
1125
  }
@@ -1126,7 +1132,7 @@ function generateEncode(ctx, fullName, messageDesc) {
1126
1132
  case "fixed64":
1127
1133
  listWriteSnippet = (0, ts_poet_1.code) `
1128
1134
  writer.uint32(${tag}).fork();
1129
- for (const v of message.${fieldName}) {
1135
+ for (const v of ${messageProperty}) {
1130
1136
  if (BigInt.asUintN(64, v) !== v) {
1131
1137
  throw new Error('a value provided in array field ${fieldName} of type ${fieldType} is too large');
1132
1138
  }
@@ -1141,7 +1147,7 @@ function generateEncode(ctx, fullName, messageDesc) {
1141
1147
  }
1142
1148
  if (isOptional) {
1143
1149
  chunks.push((0, ts_poet_1.code) `
1144
- if (message.${fieldName} !== undefined && message.${fieldName}.length !== 0) {
1150
+ if (${messageProperty} !== undefined && ${messageProperty}.length !== 0) {
1145
1151
  ${listWriteSnippet}
1146
1152
  }
1147
1153
  `);
@@ -1154,13 +1160,15 @@ function generateEncode(ctx, fullName, messageDesc) {
1154
1160
  else if ((0, types_1.isWithinOneOfThatShouldBeUnion)(options, field)) {
1155
1161
  if (!processedOneofs.has(field.oneofIndex)) {
1156
1162
  processedOneofs.add(field.oneofIndex);
1157
- const oneofName = (0, case_1.maybeSnakeToCamel)(messageDesc.oneofDecl[field.oneofIndex].name, options);
1158
- chunks.push((0, ts_poet_1.code) `switch (message.${oneofName}?.$case) {`);
1163
+ const oneofNameWithMessage = options.useJsonName
1164
+ ? messageProperty
1165
+ : (0, utils_1.getPropertyAccessor)("message", (0, case_1.maybeSnakeToCamel)(messageDesc.oneofDecl[field.oneofIndex].name, options));
1166
+ chunks.push((0, ts_poet_1.code) `switch (${oneofNameWithMessage}?.$case) {`);
1159
1167
  for (const oneOfField of oneOfFieldsDict[field.oneofIndex]) {
1160
1168
  const writeSnippet = getEncodeWriteSnippet(ctx, oneOfField);
1161
1169
  const oneOfFieldName = (0, case_1.maybeSnakeToCamel)(oneOfField.name, ctx.options);
1162
1170
  chunks.push((0, ts_poet_1.code) `case "${oneOfFieldName}":
1163
- ${writeSnippet(`message.${oneofName}.${oneOfFieldName}`)};
1171
+ ${writeSnippet(`${oneofNameWithMessage}.${oneOfFieldName}`)};
1164
1172
  break;`);
1165
1173
  }
1166
1174
  chunks.push((0, ts_poet_1.code) `}`);
@@ -1169,27 +1177,27 @@ function generateEncode(ctx, fullName, messageDesc) {
1169
1177
  else if ((0, types_1.isWithinOneOf)(field)) {
1170
1178
  // Oneofs don't have a default value check b/c they need to denote which-oneof presence
1171
1179
  chunks.push((0, ts_poet_1.code) `
1172
- if (message.${fieldName} !== undefined) {
1173
- ${writeSnippet(`message.${fieldName}`)};
1180
+ if (${messageProperty} !== undefined) {
1181
+ ${writeSnippet(`${messageProperty}`)};
1174
1182
  }
1175
1183
  `);
1176
1184
  }
1177
1185
  else if ((0, types_1.isMessage)(field)) {
1178
1186
  chunks.push((0, ts_poet_1.code) `
1179
- if (message.${fieldName} !== undefined) {
1180
- ${writeSnippet(`message.${fieldName}`)};
1187
+ if (${messageProperty} !== undefined) {
1188
+ ${writeSnippet(`${messageProperty}`)};
1181
1189
  }
1182
1190
  `);
1183
1191
  }
1184
1192
  else if ((0, types_1.isScalar)(field) || (0, types_1.isEnum)(field)) {
1185
1193
  chunks.push((0, ts_poet_1.code) `
1186
- if (${(0, types_1.notDefaultCheck)(ctx, field, messageDesc.options, `message.${fieldName}`)}) {
1187
- ${writeSnippet(`message.${fieldName}`)};
1194
+ if (${(0, types_1.notDefaultCheck)(ctx, field, messageDesc.options, `${messageProperty}`)}) {
1195
+ ${writeSnippet(`${messageProperty}`)};
1188
1196
  }
1189
1197
  `);
1190
1198
  }
1191
1199
  else {
1192
- chunks.push((0, ts_poet_1.code) `${writeSnippet(`message.${fieldName}`)};`);
1200
+ chunks.push((0, ts_poet_1.code) `${writeSnippet(`${messageProperty}`)};`);
1193
1201
  }
1194
1202
  });
1195
1203
  if (options.unknownFields) {
@@ -1461,7 +1469,8 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1461
1469
  // add a check for each incoming field
1462
1470
  messageDesc.field.forEach((field) => {
1463
1471
  var _a;
1464
- const fieldName = (0, case_1.maybeSnakeToCamel)(field.name, options);
1472
+ const fieldName = (0, utils_1.getFieldName)(field, options);
1473
+ const fieldKey = (0, utils_1.safeAccessor)(fieldName);
1465
1474
  const jsonName = (0, utils_1.getFieldJsonName)(field, options);
1466
1475
  const jsonProperty = (0, utils_1.getPropertyAccessor)("object", jsonName);
1467
1476
  const jsonPropertyOptional = (0, utils_1.getPropertyAccessor)("object", jsonName, true);
@@ -1597,7 +1606,7 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1597
1606
  if ((0, types_1.shouldGenerateJSMapType)(ctx, messageDesc, field)) {
1598
1607
  const fallback = noDefaultValue ? "undefined" : "new Map()";
1599
1608
  chunks.push((0, ts_poet_1.code) `
1600
- ${fieldName}: ${ctx.utils.isObject}(${jsonProperty})
1609
+ ${fieldKey}: ${ctx.utils.isObject}(${jsonProperty})
1601
1610
  ? Object.entries(${jsonProperty}).reduce<${fieldType}>((acc, [key, value]) => {
1602
1611
  acc.set(${i}, ${readSnippet("value")});
1603
1612
  return acc;
@@ -1608,7 +1617,7 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1608
1617
  else {
1609
1618
  const fallback = noDefaultValue ? "undefined" : "{}";
1610
1619
  chunks.push((0, ts_poet_1.code) `
1611
- ${fieldName}: ${ctx.utils.isObject}(${jsonProperty})
1620
+ ${fieldKey}: ${ctx.utils.isObject}(${jsonProperty})
1612
1621
  ? Object.entries(${jsonProperty}).reduce<${fieldType}>((acc, [key, value]) => {
1613
1622
  acc[${i}] = ${readSnippet("value")};
1614
1623
  return acc;
@@ -1621,12 +1630,12 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1621
1630
  const fallback = noDefaultValue ? "undefined" : "[]";
1622
1631
  const readValueSnippet = readSnippet("e");
1623
1632
  if (readValueSnippet.toString() === (0, ts_poet_1.code) `e`.toString()) {
1624
- chunks.push((0, ts_poet_1.code) `${fieldName}: ${ctx.utils.globalThis}.Array.isArray(${jsonPropertyOptional}) ? [...${jsonProperty}] : [],`);
1633
+ chunks.push((0, ts_poet_1.code) `${fieldKey}: ${ctx.utils.globalThis}.Array.isArray(${jsonPropertyOptional}) ? [...${jsonProperty}] : [],`);
1625
1634
  }
1626
1635
  else {
1627
1636
  // Explicit `any` type required to make TS with noImplicitAny happy. `object` is also `any` here.
1628
1637
  chunks.push((0, ts_poet_1.code) `
1629
- ${fieldName}: ${ctx.utils.globalThis}.Array.isArray(${jsonPropertyOptional}) ? ${jsonProperty}.map((e: any) => ${readValueSnippet}): ${fallback},
1638
+ ${fieldKey}: ${ctx.utils.globalThis}.Array.isArray(${jsonPropertyOptional}) ? ${jsonProperty}.map((e: any) => ${readValueSnippet}): ${fallback},
1630
1639
  `);
1631
1640
  }
1632
1641
  }
@@ -1640,26 +1649,26 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1640
1649
  chunks.push((0, ts_poet_1.code) `${fieldName}: `);
1641
1650
  }
1642
1651
  const ternaryIf = (0, ts_poet_1.code) `${ctx.utils.isSet}(${jsonProperty})`;
1643
- const ternaryThen = (0, ts_poet_1.code) `{ $case: '${fieldName}', ${fieldName}: ${readSnippet(`${jsonProperty}`)}`;
1652
+ const ternaryThen = (0, ts_poet_1.code) `{ $case: '${fieldName}', ${fieldKey}: ${readSnippet(`${jsonProperty}`)}`;
1644
1653
  chunks.push((0, ts_poet_1.code) `${ternaryIf} ? ${ternaryThen}} : `);
1645
1654
  if (field === lastCase) {
1646
1655
  chunks.push((0, ts_poet_1.code) `undefined,`);
1647
1656
  }
1648
1657
  }
1649
1658
  else if ((0, types_1.isAnyValueType)(field)) {
1650
- chunks.push((0, ts_poet_1.code) `${fieldName}: ${ctx.utils.isSet}(${jsonPropertyOptional})
1659
+ chunks.push((0, ts_poet_1.code) `${fieldKey}: ${ctx.utils.isSet}(${jsonPropertyOptional})
1651
1660
  ? ${readSnippet(`${jsonProperty}`)}
1652
1661
  : undefined,
1653
1662
  `);
1654
1663
  }
1655
1664
  else if ((0, types_1.isStructType)(field)) {
1656
- chunks.push((0, ts_poet_1.code) `${fieldName}: ${ctx.utils.isObject}(${jsonProperty})
1665
+ chunks.push((0, ts_poet_1.code) `${fieldKey}: ${ctx.utils.isObject}(${jsonProperty})
1657
1666
  ? ${readSnippet(`${jsonProperty}`)}
1658
1667
  : undefined,`);
1659
1668
  }
1660
1669
  else if ((0, types_1.isListValueType)(field)) {
1661
1670
  chunks.push((0, ts_poet_1.code) `
1662
- ${fieldName}: ${ctx.utils.globalThis}.Array.isArray(${jsonProperty})
1671
+ ${fieldKey}: ${ctx.utils.globalThis}.Array.isArray(${jsonProperty})
1663
1672
  ? ${readSnippet(`${jsonProperty}`)}
1664
1673
  : undefined,
1665
1674
  `);
@@ -1667,7 +1676,7 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1667
1676
  else {
1668
1677
  const fallback = (0, types_1.isWithinOneOf)(field) || noDefaultValue ? "undefined" : (0, types_1.defaultValue)(ctx, field);
1669
1678
  chunks.push((0, ts_poet_1.code) `
1670
- ${fieldName}: ${ctx.utils.isSet}(${jsonProperty})
1679
+ ${fieldKey}: ${ctx.utils.isSet}(${jsonProperty})
1671
1680
  ? ${readSnippet(`${jsonProperty}`)}
1672
1681
  : ${fallback},
1673
1682
  `);
@@ -1703,9 +1712,10 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
1703
1712
  `);
1704
1713
  // then add a case for each field
1705
1714
  messageDesc.field.forEach((field) => {
1706
- const fieldName = (0, case_1.maybeSnakeToCamel)(field.name, options);
1715
+ const fieldName = (0, utils_1.getFieldName)(field, options);
1707
1716
  const jsonName = (0, utils_1.getFieldJsonName)(field, options);
1708
1717
  const jsonProperty = (0, utils_1.getPropertyAccessor)("obj", jsonName);
1718
+ const messageProperty = (0, utils_1.getPropertyAccessor)("message", fieldName);
1709
1719
  const readSnippet = (from) => {
1710
1720
  if ((0, types_1.isEnum)(field)) {
1711
1721
  const toJson = (0, types_1.getEnumMethod)(ctx, field.typeName, "ToJSON");
@@ -1797,9 +1807,9 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
1797
1807
  const i = convertToObjectKey(ctx, messageDesc, field, "k");
1798
1808
  if ((0, types_1.shouldGenerateJSMapType)(ctx, messageDesc, field)) {
1799
1809
  chunks.push((0, ts_poet_1.code) `
1800
- if (message.${fieldName}?.size) {
1810
+ if (${messageProperty}?.size) {
1801
1811
  ${jsonProperty} = {};
1802
- message.${fieldName}.forEach((v, k) => {
1812
+ ${messageProperty}.forEach((v, k) => {
1803
1813
  ${jsonProperty}[${i}] = ${readSnippet("v")};
1804
1814
  });
1805
1815
  }
@@ -1807,8 +1817,8 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
1807
1817
  }
1808
1818
  else {
1809
1819
  chunks.push((0, ts_poet_1.code) `
1810
- if (message.${fieldName}) {
1811
- const entries = Object.entries(message.${fieldName});
1820
+ if (${messageProperty}) {
1821
+ const entries = Object.entries(${messageProperty});
1812
1822
  if (entries.length > 0) {
1813
1823
  ${jsonProperty} = {};
1814
1824
  entries.forEach(([k, v]) => {
@@ -1824,28 +1834,30 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
1824
1834
  const transformElement = readSnippet("e");
1825
1835
  const maybeMap = transformElement.toCodeString([]) !== "e" ? (0, ts_poet_1.code) `.map(e => ${transformElement})` : "";
1826
1836
  chunks.push((0, ts_poet_1.code) `
1827
- if (message.${fieldName}?.length) {
1828
- ${jsonProperty} = message.${fieldName}${maybeMap};
1837
+ if (${messageProperty}?.length) {
1838
+ ${jsonProperty} = ${messageProperty}${maybeMap};
1829
1839
  }
1830
1840
  `);
1831
1841
  }
1832
1842
  else if ((0, types_1.isWithinOneOfThatShouldBeUnion)(options, field)) {
1833
1843
  // oneofs in a union are only output as `oneof name = ...`
1834
- const oneofName = (0, case_1.maybeSnakeToCamel)(messageDesc.oneofDecl[field.oneofIndex].name, options);
1844
+ const oneofNameWithMessage = options.useJsonName
1845
+ ? messageProperty
1846
+ : (0, utils_1.getPropertyAccessor)("message", (0, case_1.maybeSnakeToCamel)(messageDesc.oneofDecl[field.oneofIndex].name, options));
1835
1847
  chunks.push((0, ts_poet_1.code) `
1836
- if (message.${oneofName}?.$case === '${fieldName}') {
1837
- ${jsonProperty} = ${readSnippet(`message.${oneofName}.${fieldName}`)};
1848
+ if (${oneofNameWithMessage}?.$case === '${fieldName}') {
1849
+ ${jsonProperty} = ${readSnippet(`${oneofNameWithMessage}.${fieldName}`)};
1838
1850
  }
1839
1851
  `);
1840
1852
  }
1841
1853
  else {
1842
1854
  let emitDefaultValuesForJson = ctx.options.emitDefaultValues.includes("json-methods");
1843
1855
  const check = ((0, types_1.isScalar)(field) || (0, types_1.isEnum)(field)) && !((0, types_1.isWithinOneOf)(field) || emitDefaultValuesForJson)
1844
- ? (0, types_1.notDefaultCheck)(ctx, field, messageDesc.options, `message.${fieldName}`)
1845
- : `message.${fieldName} !== undefined`;
1856
+ ? (0, types_1.notDefaultCheck)(ctx, field, messageDesc.options, `${messageProperty}`)
1857
+ : `${messageProperty} !== undefined`;
1846
1858
  chunks.push((0, ts_poet_1.code) `
1847
1859
  if (${check}) {
1848
- ${jsonProperty} = ${readSnippet(`message.${fieldName}`)};
1860
+ ${jsonProperty} = ${readSnippet(`${messageProperty}`)};
1849
1861
  }
1850
1862
  `);
1851
1863
  }
@@ -1891,7 +1903,9 @@ function generateFromPartial(ctx, fullName, messageDesc) {
1891
1903
  chunks.push((0, ts_poet_1.code) `const message = ${createBase}${maybeAsAny(options)};`);
1892
1904
  // add a check for each incoming field
1893
1905
  messageDesc.field.forEach((field) => {
1894
- const fieldName = (0, case_1.maybeSnakeToCamel)(field.name, options);
1906
+ const fieldName = (0, utils_1.getFieldName)(field, options);
1907
+ const messageProperty = (0, utils_1.getPropertyAccessor)("message", fieldName);
1908
+ const objectProperty = (0, utils_1.getPropertyAccessor)("object", fieldName);
1895
1909
  const readSnippet = (from) => {
1896
1910
  if (((0, types_1.isLong)(field) || (0, types_1.isLongValueType)(field)) && options.forceLong === options_1.LongOption.LONG) {
1897
1911
  return (0, ts_poet_1.code) `Long.fromValue(${from})`;
@@ -1962,13 +1976,13 @@ function generateFromPartial(ctx, fullName, messageDesc) {
1962
1976
  const fieldType = (0, types_1.toTypeName)(ctx, messageDesc, field);
1963
1977
  const i = convertFromObjectKey(ctx, messageDesc, field, "key");
1964
1978
  const noValueSnippet = noDefaultValue
1965
- ? `(object.${fieldName} === undefined || object.${fieldName} === null) ? undefined : `
1979
+ ? `(${objectProperty} === undefined || ${objectProperty} === null) ? undefined : `
1966
1980
  : "";
1967
1981
  if ((0, types_1.shouldGenerateJSMapType)(ctx, messageDesc, field)) {
1968
1982
  chunks.push((0, ts_poet_1.code) `
1969
- message.${fieldName} = ${noValueSnippet} (() => {
1983
+ ${messageProperty} = ${noValueSnippet} (() => {
1970
1984
  const m = new Map();
1971
- (object.${fieldName} as ${fieldType} ?? new Map()).forEach((value, key) => {
1985
+ (${objectProperty} as ${fieldType} ?? new Map()).forEach((value, key) => {
1972
1986
  if (value !== undefined) {
1973
1987
  m.set(key, ${readSnippet("value")});
1974
1988
  }
@@ -1979,7 +1993,7 @@ function generateFromPartial(ctx, fullName, messageDesc) {
1979
1993
  }
1980
1994
  else {
1981
1995
  chunks.push((0, ts_poet_1.code) `
1982
- message.${fieldName} = ${noValueSnippet} Object.entries(object.${fieldName} ?? {}).reduce<${fieldType}>((acc, [key, value]) => {
1996
+ ${messageProperty} = ${noValueSnippet} Object.entries(${objectProperty} ?? {}).reduce<${fieldType}>((acc, [key, value]) => {
1983
1997
  if (value !== undefined) {
1984
1998
  acc[${i}] = ${readSnippet("value")};
1985
1999
  }
@@ -1991,33 +2005,35 @@ function generateFromPartial(ctx, fullName, messageDesc) {
1991
2005
  else {
1992
2006
  const fallback = noDefaultValue ? "undefined" : "[]";
1993
2007
  chunks.push((0, ts_poet_1.code) `
1994
- message.${fieldName} = object.${fieldName}?.map((e) => ${readSnippet("e")}) || ${fallback};
2008
+ ${messageProperty} = ${objectProperty}?.map((e) => ${readSnippet("e")}) || ${fallback};
1995
2009
  `);
1996
2010
  }
1997
2011
  }
1998
2012
  else if ((0, types_1.isWithinOneOfThatShouldBeUnion)(options, field)) {
1999
- let oneofName = (0, case_1.maybeSnakeToCamel)(messageDesc.oneofDecl[field.oneofIndex].name, options);
2000
- const v = readSnippet(`object.${oneofName}.${fieldName}`);
2013
+ const oneofName = (0, case_1.maybeSnakeToCamel)(messageDesc.oneofDecl[field.oneofIndex].name, options);
2014
+ const oneofNameWithMessage = (0, utils_1.getPropertyAccessor)("message", oneofName);
2015
+ const oneofNameWithObject = (0, utils_1.getPropertyAccessor)("object", oneofName);
2016
+ const v = readSnippet(`${oneofNameWithObject}.${fieldName}`);
2001
2017
  chunks.push((0, ts_poet_1.code) `
2002
2018
  if (
2003
- object.${oneofName}?.$case === '${fieldName}'
2004
- && object.${oneofName}?.${fieldName} !== undefined
2005
- && object.${oneofName}?.${fieldName} !== null
2019
+ ${oneofNameWithObject}?.$case === '${fieldName}'
2020
+ && ${oneofNameWithObject}?.${fieldName} !== undefined
2021
+ && ${oneofNameWithObject}?.${fieldName} !== null
2006
2022
  ) {
2007
- message.${oneofName} = { $case: '${fieldName}', ${fieldName}: ${v} };
2023
+ ${oneofNameWithMessage} = { $case: '${fieldName}', ${fieldName}: ${v} };
2008
2024
  }
2009
2025
  `);
2010
2026
  }
2011
2027
  else if (readSnippet(`x`).toCodeString([]) == "x") {
2012
2028
  // An optimized case of the else below that works when `readSnippet` returns the plain input
2013
2029
  const fallback = (0, types_1.isWithinOneOf)(field) || noDefaultValue ? "undefined" : (0, types_1.defaultValue)(ctx, field);
2014
- chunks.push((0, ts_poet_1.code) `message.${fieldName} = object.${fieldName} ?? ${fallback};`);
2030
+ chunks.push((0, ts_poet_1.code) `${messageProperty} = ${objectProperty} ?? ${fallback};`);
2015
2031
  }
2016
2032
  else {
2017
2033
  const fallback = (0, types_1.isWithinOneOf)(field) || noDefaultValue ? "undefined" : (0, types_1.defaultValue)(ctx, field);
2018
2034
  chunks.push((0, ts_poet_1.code) `
2019
- message.${fieldName} = (object.${fieldName} !== undefined && object.${fieldName} !== null)
2020
- ? ${readSnippet(`object.${fieldName}`)}
2035
+ ${messageProperty} = (${objectProperty} !== undefined && ${objectProperty} !== null)
2036
+ ? ${readSnippet(`${objectProperty}`)}
2021
2037
  : ${fallback};
2022
2038
  `);
2023
2039
  }
package/build/options.js CHANGED
@@ -77,6 +77,7 @@ function defaultOptions() {
77
77
  useAsyncIterable: false,
78
78
  unknownFields: false,
79
79
  usePrototypeForDefaults: false,
80
+ useJsonName: false,
80
81
  useJsonWireFormat: false,
81
82
  useNumericEnumForJson: false,
82
83
  initializeFieldsAsUndefined: true,
package/build/utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.impProto = exports.impFile = exports.getPropertyAccessor = exports.getFieldJsonName = exports.FormattedMethodDescriptor = exports.assertInstanceOf = exports.maybePrefixPackage = exports.prefixDisableLinter = exports.maybeAddComment = exports.upperFirst = exports.lowerFirst = exports.singular = exports.fail = exports.readToBuffer = exports.generateIndexFiles = exports.protoFilesToGenerate = void 0;
3
+ exports.impProto = exports.impFile = exports.getPropertyAccessor = exports.safeAccessor = exports.getFieldName = exports.getFieldJsonName = exports.FormattedMethodDescriptor = exports.assertInstanceOf = exports.maybePrefixPackage = exports.prefixDisableLinter = exports.maybeAddComment = exports.upperFirst = exports.lowerFirst = exports.singular = exports.fail = exports.readToBuffer = exports.generateIndexFiles = exports.protoFilesToGenerate = void 0;
4
4
  const path = require("path");
5
5
  const ts_poet_1 = require("ts-poet");
6
6
  const options_1 = require("./options");
@@ -181,6 +181,10 @@ class FormattedMethodDescriptor {
181
181
  }
182
182
  exports.FormattedMethodDescriptor = FormattedMethodDescriptor;
183
183
  function getFieldJsonName(field, options) {
184
+ // use "json_name" defined in a proto file
185
+ if (options.useJsonName) {
186
+ return field.jsonName;
187
+ }
184
188
  // jsonName will be camelCased by the protocol compiler, plus can be overridden by the user,
185
189
  // so just use that instead of our own maybeSnakeToCamel
186
190
  if (options.snakeToCamel.includes("json")) {
@@ -195,6 +199,24 @@ function getFieldJsonName(field, options) {
195
199
  }
196
200
  }
197
201
  exports.getFieldJsonName = getFieldJsonName;
202
+ function getFieldName(field, options) {
203
+ if (options.useJsonName) {
204
+ return field.jsonName;
205
+ }
206
+ return (0, case_1.maybeSnakeToCamel)(field.name, options);
207
+ }
208
+ exports.getFieldName = getFieldName;
209
+ /**
210
+ * https://github.com/eslint-community/eslint-plugin-security/blob/main/docs/the-dangers-of-square-bracket-notation.md
211
+ */
212
+ function isValidIdentifier(propertyName) {
213
+ return /^[a-zA-Z_$][\w$]*$/.test(propertyName);
214
+ }
215
+ /** Returns `bar` or `"bar"` if `propertyName` isn't a safe property name. */
216
+ function safeAccessor(propertyName) {
217
+ return isValidIdentifier(propertyName) ? propertyName : JSON.stringify(propertyName);
218
+ }
219
+ exports.safeAccessor = safeAccessor;
198
220
  /**
199
221
  * Returns a snippet for reading an object's property, such as `foo.bar`, or `foo['bar']` if the property name contains unusual characters.
200
222
  * For simplicity, we don't match the ECMA 5/6 rules for valid identifiers exactly, and return array syntax liberally.
@@ -203,10 +225,9 @@ exports.getFieldJsonName = getFieldJsonName;
203
225
  * @param optional
204
226
  */
205
227
  function getPropertyAccessor(objectName, propertyName, optional = false) {
206
- let validIdentifier = /^[a-zA-Z_$][\w$]*$/;
207
- return validIdentifier.test(propertyName)
228
+ return isValidIdentifier(propertyName)
208
229
  ? `${objectName}${optional ? "?" : ""}.${propertyName}`
209
- : `${objectName}${optional ? "?." : ""}[${JSON.stringify(propertyName)}]`;
230
+ : `${objectName}${optional ? "?." : ""}[${safeAccessor(propertyName)}]`;
210
231
  }
211
232
  exports.getPropertyAccessor = getPropertyAccessor;
212
233
  function impFile(options, spec) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-proto",
3
- "version": "1.161.1",
3
+ "version": "1.162.1",
4
4
  "description": "",
5
5
  "main": "build/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",