From d49e44026d73f305b81f9ae77c8a03f8c3d7dfae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 26 Nov 2024 16:33:40 +0100 Subject: [PATCH] Generating "else if" where applicable In oneof scenarios, this commit proposes generating "else if" statements where applicable. The original idea was an attempt to speed up Typescript compilation by reducing the amount of paths Typescript can analyze. Spoiler alert => nothing changes from that point of view. Still, the "else if" conditions should slightly speed up the runtime execution, by avoiding unnecessary checks to the Javascript runtime. --- .../google/protobuf/struct.ts | 30 ++++------- .../google/protobuf/struct.ts | 36 ++++++------- integration/oneof-unions-value/oneof.ts | 54 +++++++++---------- .../oneof-unions/google/protobuf/struct.ts | 34 +++++------- integration/oneof-unions/oneof.ts | 48 +++++++---------- .../google/protobuf/struct.ts | 34 +++++------- .../use-readonly-types/use-readonly-types.ts | 6 +-- src/main.ts | 12 ++++- 8 files changed, 112 insertions(+), 142 deletions(-) diff --git a/integration/oneof-unions-snake/google/protobuf/struct.ts b/integration/oneof-unions-snake/google/protobuf/struct.ts index c37458bb6..6e2f28c4e 100644 --- a/integration/oneof-unions-snake/google/protobuf/struct.ts +++ b/integration/oneof-unions-snake/google/protobuf/struct.ts @@ -401,20 +401,15 @@ export const Value: MessageFns & AnyValueWrapperFns = { const obj: any = {}; if (message.kind?.$case === "null_value") { obj.null_value = nullValueToJSON(message.kind.null_value); - } - if (message.kind?.$case === "number_value") { + } else if (message.kind?.$case === "number_value") { obj.number_value = message.kind.number_value; - } - if (message.kind?.$case === "string_value") { + } else if (message.kind?.$case === "string_value") { obj.string_value = message.kind.string_value; - } - if (message.kind?.$case === "bool_value") { + } else if (message.kind?.$case === "bool_value") { obj.bool_value = message.kind.bool_value; - } - if (message.kind?.$case === "struct_value") { + } else if (message.kind?.$case === "struct_value") { obj.struct_value = message.kind.struct_value; - } - if (message.kind?.$case === "list_value") { + } else if (message.kind?.$case === "list_value") { obj.list_value = message.kind.list_value; } return obj; @@ -429,34 +424,29 @@ export const Value: MessageFns & AnyValueWrapperFns = { object.kind?.$case === "null_value" && object.kind?.null_value !== undefined && object.kind?.null_value !== null ) { message.kind = { $case: "null_value", null_value: object.kind.null_value }; - } - if ( + } else if ( object.kind?.$case === "number_value" && object.kind?.number_value !== undefined && object.kind?.number_value !== null ) { message.kind = { $case: "number_value", number_value: object.kind.number_value }; - } - if ( + } else if ( object.kind?.$case === "string_value" && object.kind?.string_value !== undefined && object.kind?.string_value !== null ) { message.kind = { $case: "string_value", string_value: object.kind.string_value }; - } - if ( + } else if ( object.kind?.$case === "bool_value" && object.kind?.bool_value !== undefined && object.kind?.bool_value !== null ) { message.kind = { $case: "bool_value", bool_value: object.kind.bool_value }; - } - if ( + } else if ( object.kind?.$case === "struct_value" && object.kind?.struct_value !== undefined && object.kind?.struct_value !== null ) { message.kind = { $case: "struct_value", struct_value: object.kind.struct_value }; - } - if ( + } else if ( object.kind?.$case === "list_value" && object.kind?.list_value !== undefined && object.kind?.list_value !== null ) { message.kind = { $case: "list_value", list_value: object.kind.list_value }; diff --git a/integration/oneof-unions-value/google/protobuf/struct.ts b/integration/oneof-unions-value/google/protobuf/struct.ts index 5bc88ea6d..602beeb67 100644 --- a/integration/oneof-unions-value/google/protobuf/struct.ts +++ b/integration/oneof-unions-value/google/protobuf/struct.ts @@ -398,20 +398,15 @@ export const Value: MessageFns & AnyValueWrapperFns = { const obj: any = {}; if (message.kind?.$case === "nullValue") { obj.nullValue = nullValueToJSON(message.kind.value); - } - if (message.kind?.$case === "numberValue") { + } else if (message.kind?.$case === "numberValue") { obj.numberValue = message.kind.value; - } - if (message.kind?.$case === "stringValue") { + } else if (message.kind?.$case === "stringValue") { obj.stringValue = message.kind.value; - } - if (message.kind?.$case === "boolValue") { + } else if (message.kind?.$case === "boolValue") { obj.boolValue = message.kind.value; - } - if (message.kind?.$case === "structValue") { + } else if (message.kind?.$case === "structValue") { obj.structValue = message.kind.value; - } - if (message.kind?.$case === "listValue") { + } else if (message.kind?.$case === "listValue") { obj.listValue = message.kind.value; } return obj; @@ -424,20 +419,21 @@ export const Value: MessageFns & AnyValueWrapperFns = { const message = createBaseValue(); if (object.kind?.$case === "nullValue" && object.kind?.value !== undefined && object.kind?.value !== null) { message.kind = { $case: "nullValue", value: object.kind.value }; - } - if (object.kind?.$case === "numberValue" && object.kind?.value !== undefined && object.kind?.value !== null) { + } else if ( + object.kind?.$case === "numberValue" && object.kind?.value !== undefined && object.kind?.value !== null + ) { message.kind = { $case: "numberValue", value: object.kind.value }; - } - if (object.kind?.$case === "stringValue" && object.kind?.value !== undefined && object.kind?.value !== null) { + } else if ( + object.kind?.$case === "stringValue" && object.kind?.value !== undefined && object.kind?.value !== null + ) { message.kind = { $case: "stringValue", value: object.kind.value }; - } - if (object.kind?.$case === "boolValue" && object.kind?.value !== undefined && object.kind?.value !== null) { + } else if (object.kind?.$case === "boolValue" && object.kind?.value !== undefined && object.kind?.value !== null) { message.kind = { $case: "boolValue", value: object.kind.value }; - } - if (object.kind?.$case === "structValue" && object.kind?.value !== undefined && object.kind?.value !== null) { + } else if ( + object.kind?.$case === "structValue" && object.kind?.value !== undefined && object.kind?.value !== null + ) { message.kind = { $case: "structValue", value: object.kind.value }; - } - if (object.kind?.$case === "listValue" && object.kind?.value !== undefined && object.kind?.value !== null) { + } else if (object.kind?.$case === "listValue" && object.kind?.value !== undefined && object.kind?.value !== null) { message.kind = { $case: "listValue", value: object.kind.value }; } return message; diff --git a/integration/oneof-unions-value/oneof.ts b/integration/oneof-unions-value/oneof.ts index 024a74157..439063cb4 100644 --- a/integration/oneof-unions-value/oneof.ts +++ b/integration/oneof-unions-value/oneof.ts @@ -302,20 +302,15 @@ export const PleaseChoose: MessageFns = { } if (message.choice?.$case === "aNumber") { obj.aNumber = message.choice.value; - } - if (message.choice?.$case === "aString") { + } else if (message.choice?.$case === "aString") { obj.aString = message.choice.value; - } - if (message.choice?.$case === "aMessage") { + } else if (message.choice?.$case === "aMessage") { obj.aMessage = PleaseChoose_Submessage.toJSON(message.choice.value); - } - if (message.choice?.$case === "aBool") { + } else if (message.choice?.$case === "aBool") { obj.aBool = message.choice.value; - } - if (message.choice?.$case === "bunchaBytes") { + } else if (message.choice?.$case === "bunchaBytes") { obj.bunchaBytes = base64FromBytes(message.choice.value); - } - if (message.choice?.$case === "anEnum") { + } else if (message.choice?.$case === "anEnum") { obj.anEnum = pleaseChoose_StateEnumToJSON(message.choice.value); } if (message.age !== 0) { @@ -323,11 +318,9 @@ export const PleaseChoose: MessageFns = { } if (message.eitherOr?.$case === "either") { obj.either = message.eitherOr.value; - } - if (message.eitherOr?.$case === "or") { + } else if (message.eitherOr?.$case === "or") { obj.or = message.eitherOr.value; - } - if (message.eitherOr?.$case === "thirdOption") { + } else if (message.eitherOr?.$case === "thirdOption") { obj.thirdOption = message.eitherOr.value; } if (message.signature.length !== 0) { @@ -347,20 +340,25 @@ export const PleaseChoose: MessageFns = { message.name = object.name ?? ""; if (object.choice?.$case === "aNumber" && object.choice?.value !== undefined && object.choice?.value !== null) { message.choice = { $case: "aNumber", value: object.choice.value }; - } - if (object.choice?.$case === "aString" && object.choice?.value !== undefined && object.choice?.value !== null) { + } else if ( + object.choice?.$case === "aString" && object.choice?.value !== undefined && object.choice?.value !== null + ) { message.choice = { $case: "aString", value: object.choice.value }; - } - if (object.choice?.$case === "aMessage" && object.choice?.value !== undefined && object.choice?.value !== null) { + } else if ( + object.choice?.$case === "aMessage" && object.choice?.value !== undefined && object.choice?.value !== null + ) { message.choice = { $case: "aMessage", value: PleaseChoose_Submessage.fromPartial(object.choice.value) }; - } - if (object.choice?.$case === "aBool" && object.choice?.value !== undefined && object.choice?.value !== null) { + } else if ( + object.choice?.$case === "aBool" && object.choice?.value !== undefined && object.choice?.value !== null + ) { message.choice = { $case: "aBool", value: object.choice.value }; - } - if (object.choice?.$case === "bunchaBytes" && object.choice?.value !== undefined && object.choice?.value !== null) { + } else if ( + object.choice?.$case === "bunchaBytes" && object.choice?.value !== undefined && object.choice?.value !== null + ) { message.choice = { $case: "bunchaBytes", value: object.choice.value }; - } - if (object.choice?.$case === "anEnum" && object.choice?.value !== undefined && object.choice?.value !== null) { + } else if ( + object.choice?.$case === "anEnum" && object.choice?.value !== undefined && object.choice?.value !== null + ) { message.choice = { $case: "anEnum", value: object.choice.value }; } message.age = object.age ?? 0; @@ -368,11 +366,11 @@ export const PleaseChoose: MessageFns = { object.eitherOr?.$case === "either" && object.eitherOr?.value !== undefined && object.eitherOr?.value !== null ) { message.eitherOr = { $case: "either", value: object.eitherOr.value }; - } - if (object.eitherOr?.$case === "or" && object.eitherOr?.value !== undefined && object.eitherOr?.value !== null) { + } else if ( + object.eitherOr?.$case === "or" && object.eitherOr?.value !== undefined && object.eitherOr?.value !== null + ) { message.eitherOr = { $case: "or", value: object.eitherOr.value }; - } - if ( + } else if ( object.eitherOr?.$case === "thirdOption" && object.eitherOr?.value !== undefined && object.eitherOr?.value !== null diff --git a/integration/oneof-unions/google/protobuf/struct.ts b/integration/oneof-unions/google/protobuf/struct.ts index 2516fe90b..66c81b604 100644 --- a/integration/oneof-unions/google/protobuf/struct.ts +++ b/integration/oneof-unions/google/protobuf/struct.ts @@ -398,20 +398,15 @@ export const Value: MessageFns & AnyValueWrapperFns = { const obj: any = {}; if (message.kind?.$case === "nullValue") { obj.nullValue = nullValueToJSON(message.kind.nullValue); - } - if (message.kind?.$case === "numberValue") { + } else if (message.kind?.$case === "numberValue") { obj.numberValue = message.kind.numberValue; - } - if (message.kind?.$case === "stringValue") { + } else if (message.kind?.$case === "stringValue") { obj.stringValue = message.kind.stringValue; - } - if (message.kind?.$case === "boolValue") { + } else if (message.kind?.$case === "boolValue") { obj.boolValue = message.kind.boolValue; - } - if (message.kind?.$case === "structValue") { + } else if (message.kind?.$case === "structValue") { obj.structValue = message.kind.structValue; - } - if (message.kind?.$case === "listValue") { + } else if (message.kind?.$case === "listValue") { obj.listValue = message.kind.listValue; } return obj; @@ -424,32 +419,31 @@ export const Value: MessageFns & AnyValueWrapperFns = { const message = createBaseValue(); if (object.kind?.$case === "nullValue" && object.kind?.nullValue !== undefined && object.kind?.nullValue !== null) { message.kind = { $case: "nullValue", nullValue: object.kind.nullValue }; - } - if ( + } else if ( object.kind?.$case === "numberValue" && object.kind?.numberValue !== undefined && object.kind?.numberValue !== null ) { message.kind = { $case: "numberValue", numberValue: object.kind.numberValue }; - } - if ( + } else if ( object.kind?.$case === "stringValue" && object.kind?.stringValue !== undefined && object.kind?.stringValue !== null ) { message.kind = { $case: "stringValue", stringValue: object.kind.stringValue }; - } - if (object.kind?.$case === "boolValue" && object.kind?.boolValue !== undefined && object.kind?.boolValue !== null) { + } else if ( + object.kind?.$case === "boolValue" && object.kind?.boolValue !== undefined && object.kind?.boolValue !== null + ) { message.kind = { $case: "boolValue", boolValue: object.kind.boolValue }; - } - if ( + } else if ( object.kind?.$case === "structValue" && object.kind?.structValue !== undefined && object.kind?.structValue !== null ) { message.kind = { $case: "structValue", structValue: object.kind.structValue }; - } - if (object.kind?.$case === "listValue" && object.kind?.listValue !== undefined && object.kind?.listValue !== null) { + } else if ( + object.kind?.$case === "listValue" && object.kind?.listValue !== undefined && object.kind?.listValue !== null + ) { message.kind = { $case: "listValue", listValue: object.kind.listValue }; } return message; diff --git a/integration/oneof-unions/oneof.ts b/integration/oneof-unions/oneof.ts index f4416fbf0..8c17b53e3 100644 --- a/integration/oneof-unions/oneof.ts +++ b/integration/oneof-unions/oneof.ts @@ -302,20 +302,15 @@ export const PleaseChoose: MessageFns = { } if (message.choice?.$case === "aNumber") { obj.aNumber = message.choice.aNumber; - } - if (message.choice?.$case === "aString") { + } else if (message.choice?.$case === "aString") { obj.aString = message.choice.aString; - } - if (message.choice?.$case === "aMessage") { + } else if (message.choice?.$case === "aMessage") { obj.aMessage = PleaseChoose_Submessage.toJSON(message.choice.aMessage); - } - if (message.choice?.$case === "aBool") { + } else if (message.choice?.$case === "aBool") { obj.aBool = message.choice.aBool; - } - if (message.choice?.$case === "bunchaBytes") { + } else if (message.choice?.$case === "bunchaBytes") { obj.bunchaBytes = base64FromBytes(message.choice.bunchaBytes); - } - if (message.choice?.$case === "anEnum") { + } else if (message.choice?.$case === "anEnum") { obj.anEnum = pleaseChoose_StateEnumToJSON(message.choice.anEnum); } if (message.age !== 0) { @@ -323,11 +318,9 @@ export const PleaseChoose: MessageFns = { } if (message.eitherOr?.$case === "either") { obj.either = message.eitherOr.either; - } - if (message.eitherOr?.$case === "or") { + } else if (message.eitherOr?.$case === "or") { obj.or = message.eitherOr.or; - } - if (message.eitherOr?.$case === "thirdOption") { + } else if (message.eitherOr?.$case === "thirdOption") { obj.thirdOption = message.eitherOr.thirdOption; } if (message.signature.length !== 0) { @@ -347,26 +340,27 @@ export const PleaseChoose: MessageFns = { message.name = object.name ?? ""; if (object.choice?.$case === "aNumber" && object.choice?.aNumber !== undefined && object.choice?.aNumber !== null) { message.choice = { $case: "aNumber", aNumber: object.choice.aNumber }; - } - if (object.choice?.$case === "aString" && object.choice?.aString !== undefined && object.choice?.aString !== null) { + } else if ( + object.choice?.$case === "aString" && object.choice?.aString !== undefined && object.choice?.aString !== null + ) { message.choice = { $case: "aString", aString: object.choice.aString }; - } - if ( + } else if ( object.choice?.$case === "aMessage" && object.choice?.aMessage !== undefined && object.choice?.aMessage !== null ) { message.choice = { $case: "aMessage", aMessage: PleaseChoose_Submessage.fromPartial(object.choice.aMessage) }; - } - if (object.choice?.$case === "aBool" && object.choice?.aBool !== undefined && object.choice?.aBool !== null) { + } else if ( + object.choice?.$case === "aBool" && object.choice?.aBool !== undefined && object.choice?.aBool !== null + ) { message.choice = { $case: "aBool", aBool: object.choice.aBool }; - } - if ( + } else if ( object.choice?.$case === "bunchaBytes" && object.choice?.bunchaBytes !== undefined && object.choice?.bunchaBytes !== null ) { message.choice = { $case: "bunchaBytes", bunchaBytes: object.choice.bunchaBytes }; - } - if (object.choice?.$case === "anEnum" && object.choice?.anEnum !== undefined && object.choice?.anEnum !== null) { + } else if ( + object.choice?.$case === "anEnum" && object.choice?.anEnum !== undefined && object.choice?.anEnum !== null + ) { message.choice = { $case: "anEnum", anEnum: object.choice.anEnum }; } message.age = object.age ?? 0; @@ -374,11 +368,9 @@ export const PleaseChoose: MessageFns = { object.eitherOr?.$case === "either" && object.eitherOr?.either !== undefined && object.eitherOr?.either !== null ) { message.eitherOr = { $case: "either", either: object.eitherOr.either }; - } - if (object.eitherOr?.$case === "or" && object.eitherOr?.or !== undefined && object.eitherOr?.or !== null) { + } else if (object.eitherOr?.$case === "or" && object.eitherOr?.or !== undefined && object.eitherOr?.or !== null) { message.eitherOr = { $case: "or", or: object.eitherOr.or }; - } - if ( + } else if ( object.eitherOr?.$case === "thirdOption" && object.eitherOr?.thirdOption !== undefined && object.eitherOr?.thirdOption !== null diff --git a/integration/use-readonly-types/google/protobuf/struct.ts b/integration/use-readonly-types/google/protobuf/struct.ts index 325e08200..a3c773bf5 100644 --- a/integration/use-readonly-types/google/protobuf/struct.ts +++ b/integration/use-readonly-types/google/protobuf/struct.ts @@ -398,20 +398,15 @@ export const Value: MessageFns & AnyValueWrapperFns = { const obj: any = {}; if (message.kind?.$case === "nullValue") { obj.nullValue = nullValueToJSON(message.kind.nullValue); - } - if (message.kind?.$case === "numberValue") { + } else if (message.kind?.$case === "numberValue") { obj.numberValue = message.kind.numberValue; - } - if (message.kind?.$case === "stringValue") { + } else if (message.kind?.$case === "stringValue") { obj.stringValue = message.kind.stringValue; - } - if (message.kind?.$case === "boolValue") { + } else if (message.kind?.$case === "boolValue") { obj.boolValue = message.kind.boolValue; - } - if (message.kind?.$case === "structValue") { + } else if (message.kind?.$case === "structValue") { obj.structValue = message.kind.structValue; - } - if (message.kind?.$case === "listValue") { + } else if (message.kind?.$case === "listValue") { obj.listValue = message.kind.listValue; } return obj; @@ -424,32 +419,31 @@ export const Value: MessageFns & AnyValueWrapperFns = { const message = createBaseValue() as any; if (object.kind?.$case === "nullValue" && object.kind?.nullValue !== undefined && object.kind?.nullValue !== null) { message.kind = { $case: "nullValue", nullValue: object.kind.nullValue }; - } - if ( + } else if ( object.kind?.$case === "numberValue" && object.kind?.numberValue !== undefined && object.kind?.numberValue !== null ) { message.kind = { $case: "numberValue", numberValue: object.kind.numberValue }; - } - if ( + } else if ( object.kind?.$case === "stringValue" && object.kind?.stringValue !== undefined && object.kind?.stringValue !== null ) { message.kind = { $case: "stringValue", stringValue: object.kind.stringValue }; - } - if (object.kind?.$case === "boolValue" && object.kind?.boolValue !== undefined && object.kind?.boolValue !== null) { + } else if ( + object.kind?.$case === "boolValue" && object.kind?.boolValue !== undefined && object.kind?.boolValue !== null + ) { message.kind = { $case: "boolValue", boolValue: object.kind.boolValue }; - } - if ( + } else if ( object.kind?.$case === "structValue" && object.kind?.structValue !== undefined && object.kind?.structValue !== null ) { message.kind = { $case: "structValue", structValue: object.kind.structValue }; - } - if (object.kind?.$case === "listValue" && object.kind?.listValue !== undefined && object.kind?.listValue !== null) { + } else if ( + object.kind?.$case === "listValue" && object.kind?.listValue !== undefined && object.kind?.listValue !== null + ) { message.kind = { $case: "listValue", listValue: object.kind.listValue }; } return message; diff --git a/integration/use-readonly-types/use-readonly-types.ts b/integration/use-readonly-types/use-readonly-types.ts index 85064f680..a88bb5bf8 100644 --- a/integration/use-readonly-types/use-readonly-types.ts +++ b/integration/use-readonly-types/use-readonly-types.ts @@ -270,8 +270,7 @@ export const Entity: MessageFns = { } if (message.oneOfValue?.$case === "theStringValue") { obj.theStringValue = message.oneOfValue.theStringValue; - } - if (message.oneOfValue?.$case === "theIntValue") { + } else if (message.oneOfValue?.$case === "theIntValue") { obj.theIntValue = Math.round(message.oneOfValue.theIntValue); } return obj; @@ -300,8 +299,7 @@ export const Entity: MessageFns = { object.oneOfValue?.theStringValue !== null ) { message.oneOfValue = { $case: "theStringValue", theStringValue: object.oneOfValue.theStringValue }; - } - if ( + } else if ( object.oneOfValue?.$case === "theIntValue" && object.oneOfValue?.theIntValue !== undefined && object.oneOfValue?.theIntValue !== null diff --git a/src/main.ts b/src/main.ts index 38ea50845..2c73628af 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2394,6 +2394,8 @@ function generateToJson( const obj: any = {}; `); + let currentIfTarget = ""; + // then add a case for each field messageDesc.field.forEach((field) => { const fieldName = getFieldName(field, options); @@ -2525,10 +2527,13 @@ function generateToJson( : getPropertyAccessor("message", maybeSnakeToCamel(messageDesc.oneofDecl[field.oneofIndex].name, options)); const valueName = oneofValueName(fieldName, options); chunks.push(code` - if (${oneofNameWithMessage}?.$case === '${fieldName}') { + ${ + currentIfTarget === oneofNameWithMessage ? "else " : "" + }if (${oneofNameWithMessage}?.$case === '${fieldName}') { ${jsonProperty} = ${readSnippet(`${oneofNameWithMessage}.${valueName}`)}; } `); + currentIfTarget = oneofNameWithMessage; } else { let emitDefaultValuesForJson = ctx.options.emitDefaultValues.includes("json-methods"); const check = @@ -2587,6 +2592,8 @@ function generateFromPartial(ctx: Context, fullName: string, messageDesc: Descri chunks.push(code`const message = ${createBase}${maybeAsAny(options)};`); + let currentIfTarget = ""; + // add a check for each incoming field messageDesc.field.forEach((field) => { const fieldName = getFieldName(field, options); @@ -2704,7 +2711,7 @@ function generateFromPartial(ctx: Context, fullName: string, messageDesc: Descri const valueName = oneofValueName(fieldName, options); const v = readSnippet(`${oneofNameWithObject}.${valueName}`); chunks.push(code` - if ( + ${currentIfTarget === oneofNameWithObject ? "else " : ""}if ( ${oneofNameWithObject}?.$case === '${fieldName}' && ${oneofNameWithObject}?.${valueName} !== undefined && ${oneofNameWithObject}?.${valueName} !== null @@ -2712,6 +2719,7 @@ function generateFromPartial(ctx: Context, fullName: string, messageDesc: Descri ${oneofNameWithMessage} = { $case: '${fieldName}', ${valueName}: ${v} }; } `); + currentIfTarget = oneofNameWithObject; } else if (readSnippet(`x`).toCodeString([]) == "x") { // An optimized case of the else below that works when `readSnippet` returns the plain input const fallback = isWithinOneOf(field) || noDefaultValue ? "undefined" : defaultValue(ctx, field);