ts-proto 1.105.2 → 1.106.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 CHANGED
@@ -1,3 +1,10 @@
1
+ # [1.106.0](https://github.com/stephenh/ts-proto/compare/v1.105.2...v1.106.0) (2022-02-21)
2
+
3
+
4
+ ### Features
5
+
6
+ * Support json names containing non-alphanumeric characters ([#520](https://github.com/stephenh/ts-proto/issues/520)) ([ce44668](https://github.com/stephenh/ts-proto/commit/ce44668b8fe01b14f50ac3c5c950f73db769fa76))
7
+
1
8
  ## [1.105.2](https://github.com/stephenh/ts-proto/compare/v1.105.1...v1.105.2) (2022-02-17)
2
9
 
3
10
 
package/build/main.js CHANGED
@@ -895,7 +895,8 @@ function generateFromJson(ctx, fullName, messageDesc) {
895
895
  // add a check for each incoming field
896
896
  messageDesc.field.forEach((field) => {
897
897
  const fieldName = case_1.maybeSnakeToCamel(field.name, options);
898
- const jsonName = utils_1.determineFieldJsonName(field, options);
898
+ const jsonName = utils_1.getFieldJsonName(field, options);
899
+ const jsonProperty = utils_1.getPropertyAccessor('object', jsonName);
899
900
  // get code that extracts value from incoming object
900
901
  const readSnippet = (from) => {
901
902
  if (types_1.isEnum(field)) {
@@ -1013,8 +1014,8 @@ function generateFromJson(ctx, fullName, messageDesc) {
1013
1014
  const fieldType = types_1.toTypeName(ctx, messageDesc, field);
1014
1015
  const i = maybeCastToNumber(ctx, messageDesc, field, 'key');
1015
1016
  chunks.push(ts_poet_1.code `
1016
- ${fieldName}: ${ctx.utils.isObject}(object.${jsonName})
1017
- ? Object.entries(object.${jsonName}).reduce<${fieldType}>((acc, [key, value]) => {
1017
+ ${fieldName}: ${ctx.utils.isObject}(${jsonProperty})
1018
+ ? Object.entries(${jsonProperty}).reduce<${fieldType}>((acc, [key, value]) => {
1018
1019
  acc[${i}] = ${readSnippet('value')};
1019
1020
  return acc;
1020
1021
  }, {})
@@ -1024,12 +1025,12 @@ function generateFromJson(ctx, fullName, messageDesc) {
1024
1025
  else {
1025
1026
  const readValueSnippet = readSnippet('e');
1026
1027
  if (readValueSnippet.toString() === ts_poet_1.code `e`.toString()) {
1027
- chunks.push(ts_poet_1.code `${fieldName}: Array.isArray(object?.${jsonName}) ? [...object.${jsonName}] : [],`);
1028
+ chunks.push(ts_poet_1.code `${fieldName}: Array.isArray(object?.${jsonName}) ? [...${jsonProperty}] : [],`);
1028
1029
  }
1029
1030
  else {
1030
1031
  // Explicit `any` type required to make TS with noImplicitAny happy. `object` is also `any` here.
1031
1032
  chunks.push(ts_poet_1.code `
1032
- ${fieldName}: Array.isArray(object?.${jsonName}) ? object.${jsonName}.map((e: any) => ${readValueSnippet}): [],
1033
+ ${fieldName}: Array.isArray(object?.${jsonName}) ? ${jsonProperty}.map((e: any) => ${readValueSnippet}): [],
1033
1034
  `);
1034
1035
  }
1035
1036
  }
@@ -1042,8 +1043,8 @@ function generateFromJson(ctx, fullName, messageDesc) {
1042
1043
  const fieldName = case_1.maybeSnakeToCamel(messageDesc.oneofDecl[field.oneofIndex].name, options);
1043
1044
  chunks.push(ts_poet_1.code `${fieldName}: `);
1044
1045
  }
1045
- const ternaryIf = ts_poet_1.code `${ctx.utils.isSet}(object.${jsonName})`;
1046
- const ternaryThen = ts_poet_1.code `{ $case: '${fieldName}', ${fieldName}: ${readSnippet(`object.${jsonName}`)}`;
1046
+ const ternaryIf = ts_poet_1.code `${ctx.utils.isSet}(${jsonProperty})`;
1047
+ const ternaryThen = ts_poet_1.code `{ $case: '${fieldName}', ${fieldName}: ${readSnippet(`${jsonProperty}`)}`;
1047
1048
  chunks.push(ts_poet_1.code `${ternaryIf} ? ${ternaryThen}} : `);
1048
1049
  if (field === lastCase) {
1049
1050
  chunks.push(ts_poet_1.code `undefined,`);
@@ -1051,27 +1052,27 @@ function generateFromJson(ctx, fullName, messageDesc) {
1051
1052
  }
1052
1053
  else if (types_1.isAnyValueType(field)) {
1053
1054
  chunks.push(ts_poet_1.code `${fieldName}: ${ctx.utils.isSet}(object?.${jsonName})
1054
- ? ${readSnippet(`object.${jsonName}`)}
1055
+ ? ${readSnippet(`${jsonProperty}`)}
1055
1056
  : undefined,
1056
1057
  `);
1057
1058
  }
1058
1059
  else if (types_1.isStructType(field)) {
1059
- chunks.push(ts_poet_1.code `${fieldName}: ${ctx.utils.isObject}(object.${jsonName})
1060
- ? ${readSnippet(`object.${jsonName}`)}
1060
+ chunks.push(ts_poet_1.code `${fieldName}: ${ctx.utils.isObject}(${jsonProperty})
1061
+ ? ${readSnippet(`${jsonProperty}`)}
1061
1062
  : undefined,`);
1062
1063
  }
1063
1064
  else if (types_1.isListValueType(field)) {
1064
1065
  chunks.push(ts_poet_1.code `
1065
- ${fieldName}: Array.isArray(object.${jsonName})
1066
- ? ${readSnippet(`object.${jsonName}`)}
1066
+ ${fieldName}: Array.isArray(${jsonProperty})
1067
+ ? ${readSnippet(`${jsonProperty}`)}
1067
1068
  : undefined,
1068
1069
  `);
1069
1070
  }
1070
1071
  else {
1071
1072
  const fallback = types_1.isWithinOneOf(field) ? 'undefined' : types_1.defaultValue(ctx, field);
1072
1073
  chunks.push(ts_poet_1.code `
1073
- ${fieldName}: ${ctx.utils.isSet}(object.${jsonName})
1074
- ? ${readSnippet(`object.${jsonName}`)}
1074
+ ${fieldName}: ${ctx.utils.isSet}(${jsonProperty})
1075
+ ? ${readSnippet(`${jsonProperty}`)}
1075
1076
  : ${fallback},
1076
1077
  `);
1077
1078
  }
@@ -1092,7 +1093,8 @@ function generateToJson(ctx, fullName, messageDesc) {
1092
1093
  // then add a case for each field
1093
1094
  messageDesc.field.forEach((field) => {
1094
1095
  const fieldName = case_1.maybeSnakeToCamel(field.name, options);
1095
- const jsonName = utils_1.determineFieldJsonName(field, options);
1096
+ const jsonName = utils_1.getFieldJsonName(field, options);
1097
+ const jsonProperty = utils_1.getPropertyAccessor('obj', jsonName);
1096
1098
  const readSnippet = (from) => {
1097
1099
  if (types_1.isEnum(field)) {
1098
1100
  const toJson = types_1.getEnumMethod(ctx, field.typeName, 'ToJSON');
@@ -1205,11 +1207,11 @@ function generateToJson(ctx, fullName, messageDesc) {
1205
1207
  // oneofs in a union are only output as `oneof name = ...`
1206
1208
  const oneofName = case_1.maybeSnakeToCamel(messageDesc.oneofDecl[field.oneofIndex].name, options);
1207
1209
  const v = readSnippet(`message.${oneofName}?.${fieldName}`);
1208
- chunks.push(ts_poet_1.code `message.${oneofName}?.$case === '${fieldName}' && (obj.${jsonName} = ${v});`);
1210
+ chunks.push(ts_poet_1.code `message.${oneofName}?.$case === '${fieldName}' && (${jsonProperty} = ${v});`);
1209
1211
  }
1210
1212
  else {
1211
1213
  const v = readSnippet(`message.${fieldName}`);
1212
- chunks.push(ts_poet_1.code `message.${fieldName} !== undefined && (obj.${jsonName} = ${v});`);
1214
+ chunks.push(ts_poet_1.code `message.${fieldName} !== undefined && (${jsonProperty} = ${v});`);
1213
1215
  }
1214
1216
  });
1215
1217
  chunks.push(ts_poet_1.code `return obj;`);
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.determineFieldJsonName = exports.FormattedMethodDescriptor = exports.assertInstanceOf = exports.maybePrefixPackage = exports.prefixDisableLinter = exports.maybeAddComment = exports.upperFirst = exports.lowerFirst = exports.singular = exports.fail = exports.readToBuffer = exports.protoFilesToGenerate = void 0;
3
+ exports.impProto = 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.protoFilesToGenerate = void 0;
4
4
  const ts_poet_1 = require("ts-poet");
5
5
  const options_1 = require("./options");
6
6
  const case_1 = require("./case");
@@ -144,7 +144,7 @@ class FormattedMethodDescriptor {
144
144
  }
145
145
  }
146
146
  exports.FormattedMethodDescriptor = FormattedMethodDescriptor;
147
- function determineFieldJsonName(field, options) {
147
+ function getFieldJsonName(field, options) {
148
148
  // jsonName will be camelCased by the protocol compiler, plus can be overridden by the user,
149
149
  // so just use that instead of our own maybeSnakeToCamel
150
150
  if (options.snakeToCamel.includes('json')) {
@@ -154,7 +154,20 @@ function determineFieldJsonName(field, options) {
154
154
  return field.name;
155
155
  }
156
156
  }
157
- exports.determineFieldJsonName = determineFieldJsonName;
157
+ exports.getFieldJsonName = getFieldJsonName;
158
+ /**
159
+ * Returns a snippet for reading an object's property, such as `foo.bar`, or `foo['bar']` if the property name contains unusual characters.
160
+ * For simplicity, we don't match the ECMA 5/6 rules for valid identifiers exactly, and return array syntax liberally.
161
+ * @param objectName
162
+ * @param propertyName
163
+ */
164
+ function getPropertyAccessor(objectName, propertyName) {
165
+ let validIdentifier = /^[a-zA-Z_$][\w$]*$/;
166
+ return validIdentifier.test(propertyName)
167
+ ? `${objectName}.${propertyName}`
168
+ : `${objectName}[${JSON.stringify(propertyName)}]`;
169
+ }
170
+ exports.getPropertyAccessor = getPropertyAccessor;
158
171
  function impProto(options, module, type) {
159
172
  return ts_poet_1.imp(`${type}@./${module}${options.fileSuffix}`);
160
173
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-proto",
3
- "version": "1.105.2",
3
+ "version": "1.106.0",
4
4
  "description": "",
5
5
  "main": "build/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",