From 8d9e78eb39c460f6727458f6a2dd149deb983668 Mon Sep 17 00:00:00 2001 From: Bouke Versteegh Date: Mon, 21 Feb 2022 16:31:53 +0100 Subject: [PATCH] fix: support json_name containing hyphen on all field types (#521) --- integration/simple-json-name/simple.bin | Bin 7485 -> 7629 bytes integration/simple-json-name/simple.proto | 1 + integration/simple-json-name/simple.ts | 25 +++++++++++++++++++++- src/main.ts | 15 +++++++------ src/utils.ts | 7 +++--- 5 files changed, 37 insertions(+), 11 deletions(-) diff --git a/integration/simple-json-name/simple.bin b/integration/simple-json-name/simple.bin index 98d2a04860da195ea7bf87330542ea1c7081c80b..29222dfc2581fdf9c612964d6f75de3bca2aa705 100644 GIT binary patch delta 218 zcmdmMb=G>rV+p1goRgnQSTJsyEGPNfNl2cHE2FX?BQ?(_v$#ZpU4dDHGl&}^qMHL0 za$@6RiBC*Vb>ijXj!!O1O)N=GiBBx?`pCw`Cd9(Pz(3haN{f+ybE?z@rgAQBE*2IB zCUzlaJ|@(UQ?!BcxPUw*Yh<3D NbrM@aQGQ9jF#y String(e)) : [], }; }, @@ -102,6 +119,11 @@ export const Simple = { message.spaces !== undefined && (obj['name with spaces'] = message.spaces); message.dollarStart !== undefined && (obj.$dollar = message.dollarStart); message.dollarEnd !== undefined && (obj.dollar$ = message.dollarEnd); + if (message.hyphenList) { + obj['hyphen-list'] = message.hyphenList.map((e) => e); + } else { + obj['hyphen-list'] = []; + } return obj; }, @@ -114,6 +136,7 @@ export const Simple = { message.spaces = object.spaces ?? ''; message.dollarStart = object.dollarStart ?? ''; message.dollarEnd = object.dollarEnd ?? ''; + message.hyphenList = object.hyphenList?.map((e) => e) || []; return message; }, }; diff --git a/src/main.ts b/src/main.ts index 49fced731..14fa2a055 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1117,6 +1117,7 @@ function generateFromJson(ctx: Context, fullName: string, messageDesc: Descripto const fieldName = maybeSnakeToCamel(field.name, options); const jsonName = getFieldJsonName(field, options); const jsonProperty = getPropertyAccessor('object', jsonName); + const jsonPropertyOptional = getPropertyAccessor('object', jsonName, true); // get code that extracts value from incoming object const readSnippet = (from: string): Code => { @@ -1224,11 +1225,11 @@ function generateFromJson(ctx: Context, fullName: string, messageDesc: Descripto } else { const readValueSnippet = readSnippet('e'); if (readValueSnippet.toString() === code`e`.toString()) { - chunks.push(code`${fieldName}: Array.isArray(object?.${jsonName}) ? [...${jsonProperty}] : [],`); + chunks.push(code`${fieldName}: Array.isArray(${jsonPropertyOptional}) ? [...${jsonProperty}] : [],`); } else { // Explicit `any` type required to make TS with noImplicitAny happy. `object` is also `any` here. chunks.push(code` - ${fieldName}: Array.isArray(object?.${jsonName}) ? ${jsonProperty}.map((e: any) => ${readValueSnippet}): [], + ${fieldName}: Array.isArray(${jsonPropertyOptional}) ? ${jsonProperty}.map((e: any) => ${readValueSnippet}): [], `); } } @@ -1250,7 +1251,7 @@ function generateFromJson(ctx: Context, fullName: string, messageDesc: Descripto chunks.push(code`undefined,`); } } else if (isAnyValueType(field)) { - chunks.push(code`${fieldName}: ${ctx.utils.isSet}(object?.${jsonName}) + chunks.push(code`${fieldName}: ${ctx.utils.isSet}(${jsonPropertyOptional}) ? ${readSnippet(`${jsonProperty}`)} : undefined, `); @@ -1365,10 +1366,10 @@ function generateToJson(ctx: Context, fullName: string, messageDesc: DescriptorP if (isMapType(ctx, messageDesc, field)) { // Maps might need their values transformed, i.e. bytes --> base64 chunks.push(code` - obj.${jsonName} = {}; + ${jsonProperty} = {}; if (message.${fieldName}) { Object.entries(message.${fieldName}).forEach(([k, v]) => { - obj.${jsonName}[k] = ${readSnippet('v')}; + ${jsonProperty}[k] = ${readSnippet('v')}; }); } `); @@ -1376,9 +1377,9 @@ function generateToJson(ctx: Context, fullName: string, messageDesc: DescriptorP // Arrays might need their elements transformed chunks.push(code` if (message.${fieldName}) { - obj.${jsonName} = message.${fieldName}.map(e => ${readSnippet('e')}); + ${jsonProperty} = message.${fieldName}.map(e => ${readSnippet('e')}); } else { - obj.${jsonName} = []; + ${jsonProperty} = []; } `); } else if (isWithinOneOfThatShouldBeUnion(options, field)) { diff --git a/src/utils.ts b/src/utils.ts index 55cd35f1d..d13531d2d 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -189,12 +189,13 @@ export function getFieldJsonName(field: FieldDescriptorProto, options: Options): * For simplicity, we don't match the ECMA 5/6 rules for valid identifiers exactly, and return array syntax liberally. * @param objectName * @param propertyName + * @param optional */ -export function getPropertyAccessor(objectName: string, propertyName: string): string { +export function getPropertyAccessor(objectName: string, propertyName: string, optional: boolean = false): string { let validIdentifier = /^[a-zA-Z_$][\w$]*$/; return validIdentifier.test(propertyName) - ? `${objectName}.${propertyName}` - : `${objectName}[${JSON.stringify(propertyName)}]`; + ? `${objectName}${optional ? '?' : ''}.${propertyName}` + : `${objectName}${optional ? '?.' : ''}[${JSON.stringify(propertyName)}]`; } export function impProto(options: Options, module: string, type: string): Import {