From ee52e06a95d7790d1252831f1bb01344c94f16a4 Mon Sep 17 00:00:00 2001 From: David Zeng <40158558+davidzeng0@users.noreply.github.com> Date: Sun, 19 Mar 2023 12:17:49 -0700 Subject: [PATCH] fix: initialize undefined optional fields upon use (#802) * fix: initialize undefined optional fields upon use * chore: integration --- integration/groups/test.ts | 16 +- .../optionals-test.ts | 71 ++ .../use-optionals-no-undefined/parameters.txt | 1 + .../use-optionals-no-undefined/test.bin | Bin 0 -> 2755 bytes .../use-optionals-no-undefined/test.proto | 39 + .../use-optionals-no-undefined/test.ts | 748 ++++++++++++++++++ src/main.ts | 55 +- 7 files changed, 904 insertions(+), 26 deletions(-) create mode 100644 integration/use-optionals-no-undefined/optionals-test.ts create mode 100644 integration/use-optionals-no-undefined/parameters.txt create mode 100644 integration/use-optionals-no-undefined/test.bin create mode 100644 integration/use-optionals-no-undefined/test.proto create mode 100644 integration/use-optionals-no-undefined/test.ts diff --git a/integration/groups/test.ts b/integration/groups/test.ts index caae008f8..3b4d049a2 100644 --- a/integration/groups/test.ts +++ b/integration/groups/test.ts @@ -76,7 +76,7 @@ export const GroupsOptionalTest = { }, decode(input: _m0.Reader | Uint8Array, length?: number): GroupsOptionalTest { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseGroupsOptionalTest(); (message as any)._unknownFields = {}; @@ -180,7 +180,7 @@ export const GroupsOptionalTest_Group = { }, decode(input: _m0.Reader | Uint8Array, length?: number): GroupsOptionalTest_Group { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseGroupsOptionalTest_Group(); (message as any)._unknownFields = {}; @@ -281,7 +281,7 @@ export const GroupsRepeatedTest = { }, decode(input: _m0.Reader | Uint8Array, length?: number): GroupsRepeatedTest { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseGroupsRepeatedTest(); (message as any)._unknownFields = {}; @@ -416,7 +416,7 @@ export const GroupsRepeatedTest_Group = { }, decode(input: _m0.Reader | Uint8Array, length?: number): GroupsRepeatedTest_Group { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseGroupsRepeatedTest_Group(); (message as any)._unknownFields = {}; @@ -528,7 +528,7 @@ export const GroupsNestedTest = { }, decode(input: _m0.Reader | Uint8Array, length?: number): GroupsNestedTest { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseGroupsNestedTest(); (message as any)._unknownFields = {}; @@ -658,7 +658,7 @@ export const GroupsNestedTest_Group = { }, decode(input: _m0.Reader | Uint8Array, length?: number): GroupsNestedTest_Group { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseGroupsNestedTest_Group(); (message as any)._unknownFields = {}; @@ -744,7 +744,7 @@ export const GroupsNestedTest_Group_Nested = { }, decode(input: _m0.Reader | Uint8Array, length?: number): GroupsNestedTest_Group_Nested { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseGroupsNestedTest_Group_Nested(); (message as any)._unknownFields = {}; @@ -830,7 +830,7 @@ export const GroupsNestedTest_Group_Nested_Nested2 = { }, decode(input: _m0.Reader | Uint8Array, length?: number): GroupsNestedTest_Group_Nested_Nested2 { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseGroupsNestedTest_Group_Nested_Nested2(); (message as any)._unknownFields = {}; diff --git a/integration/use-optionals-no-undefined/optionals-test.ts b/integration/use-optionals-no-undefined/optionals-test.ts new file mode 100644 index 000000000..76f810257 --- /dev/null +++ b/integration/use-optionals-no-undefined/optionals-test.ts @@ -0,0 +1,71 @@ +import { OptionalsTest, StateEnum } from './test' + +describe('useOptionals=all initializeFieldsAsUndefined=false', () => { + it('has all optional members', () => { + const test: OptionalsTest = {}; + const data = OptionalsTest.encode(test).finish(); + const test2 = OptionalsTest.decode(data); + expect(test2).toEqual({}); + }); + + it('allows setting all members, too', () => { + const test: OptionalsTest = { + id: 1, + child: {}, + state: StateEnum.ON, + long: 10, + truth: true, + description: "hello world", + data: Buffer.alloc(2).fill(0x32), + + repId: [1, 2], + repChild: [{}, {}], + repLong: [11, 12], + repTruth: [true, false], + repDescription: ["hello", "world"], + repData: [Buffer.alloc(3).fill(0x33), Buffer.alloc(4).fill(0x34), Buffer.alloc(5).fill(0x35)], + + optChild: {}, + optId: 2, + optState: StateEnum.OFF, + optTruth: true, + optDescription: "mumble", + optData: Buffer.alloc(6).fill(0x36), + + translations: { + "hello": "hallo", + "world": "wereld", + }, + }; + const data = OptionalsTest.encode(test).finish(); + const test2 = OptionalsTest.decode(data); + expect(test2).toEqual({ + id: 1, + child: {}, + state: StateEnum.ON, + long: 10, + truth: true, + description: "hello world", + data: Buffer.alloc(2).fill(0x32), + + repId: [1, 2], + repChild: [{}, {}], + repLong: [11, 12], + repTruth: [true, false], + repDescription: ["hello", "world"], + repData: [Buffer.alloc(3).fill(0x33), Buffer.alloc(4).fill(0x34), Buffer.alloc(5).fill(0x35)], + + optChild: {}, + optId: 2, + optState: StateEnum.OFF, + optTruth: true, + optDescription: "mumble", + optData: Buffer.alloc(6).fill(0x36), + + translations: { + "hello": "hallo", + "world": "wereld", + }, + }); + }); +}) diff --git a/integration/use-optionals-no-undefined/parameters.txt b/integration/use-optionals-no-undefined/parameters.txt new file mode 100644 index 000000000..48ec4ec23 --- /dev/null +++ b/integration/use-optionals-no-undefined/parameters.txt @@ -0,0 +1 @@ +useOptionals=all,initializeFieldsAsUndefined=false \ No newline at end of file diff --git a/integration/use-optionals-no-undefined/test.bin b/integration/use-optionals-no-undefined/test.bin new file mode 100644 index 0000000000000000000000000000000000000000..11c02597f2d0e69c9ad97bc5c7c0eff732c3b4ee GIT binary patch literal 2755 zcmaKu?QR=I6oz+a_H*|8WY=E1Y2vs|Qz{gRA`t2yq|jC_phQ}N_!*fxq7fmf5*Mjl z0oTGkaSvPq@67HT+@kj1oH^%x=6uYKtpT?*I07^7`tR)GX>HYy`--$gXCk?X_={&CQ7f*Op!TMvI}8Jq_KVe@u1jC4So``8jNtx2 z2NrG@A<*z?$wz71pOKGKGTFj~_Ht=&-?)%T)>R4&jB?C5T2|Ey>C4VfSyT6l(F zTB0L9RfQ&Oc4dmVc;Rzn1(?d4K`5V!3P+Lt^& zeDBVlYU%-8+ow*Q)wo2$f3ydj8gYQgNr3`i}p;ynJ(RzNxtDjVIzO z_b683nXd6-b(AV)mS#w7nbsdADmFfSvDjrgcSNc*u8l5nxbDR~RKA(#qfb<9hNHho zN>upc@ps23KOL721xlP8mx4kiPo6(7<+p#QDj?5s9=Iw}Zc5T|NUsD**BL3Lgy)ba zox3j9(sNvrGHO(!JkJphNlz3iRlYWSZH3lCpcg4?NmyAv$l&q?4K6p(mX%?8(vLFh zgUm0hL57q9F&bO~vOpx(f-FcYYe5#&Hc1$vur7%tLq1JH7DnkHlRB~}htoWg5z9Qt zA`uLM9%NByWgcV^%Mcig$q?upE3y`3aa>yqvUuDMr=c3frv;EHPBMT@agqUKicbqk zrsD2E43TmwY|BGH(xkLLK+8c3?V>Th7cevkC*^ydBkX|Y#Fjea>66t0%XFFEkGtb;w?ZXJmM`t zCOqPr%CSq&h4V|T#zMt^HwZ|^~^6m+52-NTYUKkC5 oFy?(-P-)p*_(P!3z9=?76fSxD`iDgSP-xtKl>Ho-f32VY3-{H70ssI2 literal 0 HcmV?d00001 diff --git a/integration/use-optionals-no-undefined/test.proto b/integration/use-optionals-no-undefined/test.proto new file mode 100644 index 000000000..d752ce261 --- /dev/null +++ b/integration/use-optionals-no-undefined/test.proto @@ -0,0 +1,39 @@ +syntax = "proto3"; +package optionalstest; + +message OptionalsTest { + int32 id = 1; + Child child = 2; + StateEnum state = 3; + int64 long = 4; + bool truth = 5; + string description = 6; + bytes data = 7; + + repeated int32 rep_id = 11; + repeated Child rep_child = 12; + repeated StateEnum rep_state = 13; + repeated int64 rep_long = 14; + repeated bool rep_truth = 15; + repeated string rep_description = 16; + repeated bytes rep_data = 17; + + optional int32 opt_id = 21; + optional Child opt_child = 22; + optional StateEnum opt_state = 23; + optional int64 opt_long = 24; + optional bool opt_truth = 25; + optional string opt_description = 26; + optional bytes opt_data = 27; + + map translations = 30; +} + +enum StateEnum { + UNKNOWN = 0; + ON = 2; + OFF = 3; +} + +message Child { +} diff --git a/integration/use-optionals-no-undefined/test.ts b/integration/use-optionals-no-undefined/test.ts new file mode 100644 index 000000000..90e2395b3 --- /dev/null +++ b/integration/use-optionals-no-undefined/test.ts @@ -0,0 +1,748 @@ +/* eslint-disable */ +import * as Long from "long"; +import * as _m0 from "protobufjs/minimal"; + +export const protobufPackage = "optionalstest"; + +export enum StateEnum { + UNKNOWN = 0, + ON = 2, + OFF = 3, + UNRECOGNIZED = -1, +} + +export function stateEnumFromJSON(object: any): StateEnum { + switch (object) { + case 0: + case "UNKNOWN": + return StateEnum.UNKNOWN; + case 2: + case "ON": + return StateEnum.ON; + case 3: + case "OFF": + return StateEnum.OFF; + case -1: + case "UNRECOGNIZED": + default: + return StateEnum.UNRECOGNIZED; + } +} + +export function stateEnumToJSON(object: StateEnum): string { + switch (object) { + case StateEnum.UNKNOWN: + return "UNKNOWN"; + case StateEnum.ON: + return "ON"; + case StateEnum.OFF: + return "OFF"; + case StateEnum.UNRECOGNIZED: + default: + return "UNRECOGNIZED"; + } +} + +export interface OptionalsTest { + id?: number; + child?: Child; + state?: StateEnum; + long?: number; + truth?: boolean; + description?: string; + data?: Uint8Array; + repId?: number[]; + repChild?: Child[]; + repState?: StateEnum[]; + repLong?: number[]; + repTruth?: boolean[]; + repDescription?: string[]; + repData?: Uint8Array[]; + optId?: number | undefined; + optChild?: Child | undefined; + optState?: StateEnum | undefined; + optLong?: number | undefined; + optTruth?: boolean | undefined; + optDescription?: string | undefined; + optData?: Uint8Array | undefined; + translations?: { [key: string]: string }; +} + +export interface OptionalsTest_TranslationsEntry { + key: string; + value: string; +} + +export interface Child { +} + +function createBaseOptionalsTest(): OptionalsTest { + return {}; +} + +export const OptionalsTest = { + encode(message: OptionalsTest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.id !== undefined && message.id !== 0) { + writer.uint32(8).int32(message.id); + } + if (message.child !== undefined) { + Child.encode(message.child, writer.uint32(18).fork()).ldelim(); + } + if (message.state !== undefined && message.state !== 0) { + writer.uint32(24).int32(message.state); + } + if (message.long !== undefined && message.long !== 0) { + writer.uint32(32).int64(message.long); + } + if (message.truth === true) { + writer.uint32(40).bool(message.truth); + } + if (message.description !== undefined && message.description !== "") { + writer.uint32(50).string(message.description); + } + if (message.data !== undefined && message.data.length !== 0) { + writer.uint32(58).bytes(message.data); + } + if (message.repId !== undefined && message.repId.length !== 0) { + writer.uint32(90).fork(); + for (const v of message.repId) { + writer.int32(v); + } + writer.ldelim(); + } + if (message.repChild !== undefined && message.repChild.length !== 0) { + for (const v of message.repChild) { + Child.encode(v!, writer.uint32(98).fork()).ldelim(); + } + } + if (message.repState !== undefined && message.repState.length !== 0) { + writer.uint32(106).fork(); + for (const v of message.repState) { + writer.int32(v); + } + writer.ldelim(); + } + if (message.repLong !== undefined && message.repLong.length !== 0) { + writer.uint32(114).fork(); + for (const v of message.repLong) { + writer.int64(v); + } + writer.ldelim(); + } + if (message.repTruth !== undefined && message.repTruth.length !== 0) { + writer.uint32(122).fork(); + for (const v of message.repTruth) { + writer.bool(v); + } + writer.ldelim(); + } + if (message.repDescription !== undefined && message.repDescription.length !== 0) { + for (const v of message.repDescription) { + writer.uint32(130).string(v!); + } + } + if (message.repData !== undefined && message.repData.length !== 0) { + for (const v of message.repData) { + writer.uint32(138).bytes(v!); + } + } + if (message.optId !== undefined) { + writer.uint32(168).int32(message.optId); + } + if (message.optChild !== undefined) { + Child.encode(message.optChild, writer.uint32(178).fork()).ldelim(); + } + if (message.optState !== undefined) { + writer.uint32(184).int32(message.optState); + } + if (message.optLong !== undefined) { + writer.uint32(192).int64(message.optLong); + } + if (message.optTruth !== undefined) { + writer.uint32(200).bool(message.optTruth); + } + if (message.optDescription !== undefined) { + writer.uint32(210).string(message.optDescription); + } + if (message.optData !== undefined) { + writer.uint32(218).bytes(message.optData); + } + Object.entries(message.translations || {}).forEach(([key, value]) => { + OptionalsTest_TranslationsEntry.encode({ key: key as any, value }, writer.uint32(242).fork()).ldelim(); + }); + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): OptionalsTest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseOptionalsTest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag != 8) { + break; + } + + message.id = reader.int32(); + continue; + case 2: + if (tag != 18) { + break; + } + + message.child = Child.decode(reader, reader.uint32()); + continue; + case 3: + if (tag != 24) { + break; + } + + message.state = reader.int32() as any; + continue; + case 4: + if (tag != 32) { + break; + } + + message.long = longToNumber(reader.int64() as Long); + continue; + case 5: + if (tag != 40) { + break; + } + + message.truth = reader.bool(); + continue; + case 6: + if (tag != 50) { + break; + } + + message.description = reader.string(); + continue; + case 7: + if (tag != 58) { + break; + } + + message.data = reader.bytes(); + continue; + case 11: + if (tag == 88) { + if (message.repId === undefined) { + message.repId = []; + } + message.repId!.push(reader.int32()); + continue; + } + + if (tag == 90) { + if (message.repId === undefined) { + message.repId = []; + } + const end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) { + message.repId!.push(reader.int32()); + } + + continue; + } + + break; + case 12: + if (tag != 98) { + break; + } + + if (message.repChild === undefined) { + message.repChild = []; + } + message.repChild!.push(Child.decode(reader, reader.uint32())); + continue; + case 13: + if (tag == 104) { + if (message.repState === undefined) { + message.repState = []; + } + message.repState!.push(reader.int32() as any); + continue; + } + + if (tag == 106) { + if (message.repState === undefined) { + message.repState = []; + } + const end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) { + message.repState!.push(reader.int32() as any); + } + + continue; + } + + break; + case 14: + if (tag == 112) { + if (message.repLong === undefined) { + message.repLong = []; + } + message.repLong!.push(longToNumber(reader.int64() as Long)); + continue; + } + + if (tag == 114) { + if (message.repLong === undefined) { + message.repLong = []; + } + const end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) { + message.repLong!.push(longToNumber(reader.int64() as Long)); + } + + continue; + } + + break; + case 15: + if (tag == 120) { + if (message.repTruth === undefined) { + message.repTruth = []; + } + message.repTruth!.push(reader.bool()); + continue; + } + + if (tag == 122) { + if (message.repTruth === undefined) { + message.repTruth = []; + } + const end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) { + message.repTruth!.push(reader.bool()); + } + + continue; + } + + break; + case 16: + if (tag != 130) { + break; + } + + if (message.repDescription === undefined) { + message.repDescription = []; + } + message.repDescription!.push(reader.string()); + continue; + case 17: + if (tag != 138) { + break; + } + + if (message.repData === undefined) { + message.repData = []; + } + message.repData!.push(reader.bytes()); + continue; + case 21: + if (tag != 168) { + break; + } + + message.optId = reader.int32(); + continue; + case 22: + if (tag != 178) { + break; + } + + message.optChild = Child.decode(reader, reader.uint32()); + continue; + case 23: + if (tag != 184) { + break; + } + + message.optState = reader.int32() as any; + continue; + case 24: + if (tag != 192) { + break; + } + + message.optLong = longToNumber(reader.int64() as Long); + continue; + case 25: + if (tag != 200) { + break; + } + + message.optTruth = reader.bool(); + continue; + case 26: + if (tag != 210) { + break; + } + + message.optDescription = reader.string(); + continue; + case 27: + if (tag != 218) { + break; + } + + message.optData = reader.bytes(); + continue; + case 30: + if (tag != 242) { + break; + } + + const entry30 = OptionalsTest_TranslationsEntry.decode(reader, reader.uint32()); + if (entry30.value !== undefined) { + if (message.translations === undefined) { + message.translations = {}; + } + + message.translations![entry30.key] = entry30.value; + } + continue; + } + if ((tag & 7) == 4 || tag == 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): OptionalsTest { + return { + id: isSet(object.id) ? Number(object.id) : 0, + child: isSet(object.child) ? Child.fromJSON(object.child) : undefined, + state: isSet(object.state) ? stateEnumFromJSON(object.state) : 0, + long: isSet(object.long) ? Number(object.long) : 0, + truth: isSet(object.truth) ? Boolean(object.truth) : false, + description: isSet(object.description) ? String(object.description) : "", + data: isSet(object.data) ? bytesFromBase64(object.data) : new Uint8Array(), + repId: Array.isArray(object?.repId) ? object.repId.map((e: any) => Number(e)) : [], + repChild: Array.isArray(object?.repChild) ? object.repChild.map((e: any) => Child.fromJSON(e)) : [], + repState: Array.isArray(object?.repState) ? object.repState.map((e: any) => stateEnumFromJSON(e)) : [], + repLong: Array.isArray(object?.repLong) ? object.repLong.map((e: any) => Number(e)) : [], + repTruth: Array.isArray(object?.repTruth) ? object.repTruth.map((e: any) => Boolean(e)) : [], + repDescription: Array.isArray(object?.repDescription) ? object.repDescription.map((e: any) => String(e)) : [], + repData: Array.isArray(object?.repData) ? object.repData.map((e: any) => bytesFromBase64(e)) : [], + optId: isSet(object.optId) ? Number(object.optId) : undefined, + optChild: isSet(object.optChild) ? Child.fromJSON(object.optChild) : undefined, + optState: isSet(object.optState) ? stateEnumFromJSON(object.optState) : undefined, + optLong: isSet(object.optLong) ? Number(object.optLong) : undefined, + optTruth: isSet(object.optTruth) ? Boolean(object.optTruth) : undefined, + optDescription: isSet(object.optDescription) ? String(object.optDescription) : undefined, + optData: isSet(object.optData) ? bytesFromBase64(object.optData) : undefined, + translations: isObject(object.translations) + ? Object.entries(object.translations).reduce<{ [key: string]: string }>((acc, [key, value]) => { + acc[key] = String(value); + return acc; + }, {}) + : {}, + }; + }, + + toJSON(message: OptionalsTest): unknown { + const obj: any = {}; + message.id !== undefined && (obj.id = Math.round(message.id)); + message.child !== undefined && (obj.child = message.child ? Child.toJSON(message.child) : undefined); + message.state !== undefined && (obj.state = stateEnumToJSON(message.state)); + message.long !== undefined && (obj.long = Math.round(message.long)); + message.truth !== undefined && (obj.truth = message.truth); + message.description !== undefined && (obj.description = message.description); + message.data !== undefined && + (obj.data = base64FromBytes(message.data !== undefined ? message.data : new Uint8Array())); + if (message.repId) { + obj.repId = message.repId.map((e) => Math.round(e)); + } else { + obj.repId = []; + } + if (message.repChild) { + obj.repChild = message.repChild.map((e) => e ? Child.toJSON(e) : undefined); + } else { + obj.repChild = []; + } + if (message.repState) { + obj.repState = message.repState.map((e) => stateEnumToJSON(e)); + } else { + obj.repState = []; + } + if (message.repLong) { + obj.repLong = message.repLong.map((e) => Math.round(e)); + } else { + obj.repLong = []; + } + if (message.repTruth) { + obj.repTruth = message.repTruth.map((e) => e); + } else { + obj.repTruth = []; + } + if (message.repDescription) { + obj.repDescription = message.repDescription.map((e) => e); + } else { + obj.repDescription = []; + } + if (message.repData) { + obj.repData = message.repData.map((e) => base64FromBytes(e !== undefined ? e : new Uint8Array())); + } else { + obj.repData = []; + } + message.optId !== undefined && (obj.optId = Math.round(message.optId)); + message.optChild !== undefined && (obj.optChild = message.optChild ? Child.toJSON(message.optChild) : undefined); + message.optState !== undefined && + (obj.optState = message.optState !== undefined ? stateEnumToJSON(message.optState) : undefined); + message.optLong !== undefined && (obj.optLong = Math.round(message.optLong)); + message.optTruth !== undefined && (obj.optTruth = message.optTruth); + message.optDescription !== undefined && (obj.optDescription = message.optDescription); + message.optData !== undefined && + (obj.optData = message.optData !== undefined ? base64FromBytes(message.optData) : undefined); + obj.translations = {}; + if (message.translations) { + Object.entries(message.translations).forEach(([k, v]) => { + obj.translations[k] = v; + }); + } + return obj; + }, + + create, I>>(base?: I): OptionalsTest { + return OptionalsTest.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): OptionalsTest { + const message = createBaseOptionalsTest(); + message.id = object.id ?? 0; + message.child = (object.child !== undefined && object.child !== null) ? Child.fromPartial(object.child) : undefined; + message.state = object.state ?? 0; + message.long = object.long ?? 0; + message.truth = object.truth ?? false; + message.description = object.description ?? ""; + message.data = object.data ?? new Uint8Array(); + message.repId = object.repId?.map((e) => e) || []; + message.repChild = object.repChild?.map((e) => Child.fromPartial(e)) || []; + message.repState = object.repState?.map((e) => e) || []; + message.repLong = object.repLong?.map((e) => e) || []; + message.repTruth = object.repTruth?.map((e) => e) || []; + message.repDescription = object.repDescription?.map((e) => e) || []; + message.repData = object.repData?.map((e) => e) || []; + message.optId = object.optId ?? undefined; + message.optChild = (object.optChild !== undefined && object.optChild !== null) + ? Child.fromPartial(object.optChild) + : undefined; + message.optState = object.optState ?? undefined; + message.optLong = object.optLong ?? undefined; + message.optTruth = object.optTruth ?? undefined; + message.optDescription = object.optDescription ?? undefined; + message.optData = object.optData ?? undefined; + message.translations = Object.entries(object.translations ?? {}).reduce<{ [key: string]: string }>( + (acc, [key, value]) => { + if (value !== undefined) { + acc[key] = String(value); + } + return acc; + }, + {}, + ); + return message; + }, +}; + +function createBaseOptionalsTest_TranslationsEntry(): OptionalsTest_TranslationsEntry { + return { key: "", value: "" }; +} + +export const OptionalsTest_TranslationsEntry = { + encode(message: OptionalsTest_TranslationsEntry, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.key !== "") { + writer.uint32(10).string(message.key); + } + if (message.value !== "") { + writer.uint32(18).string(message.value); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): OptionalsTest_TranslationsEntry { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseOptionalsTest_TranslationsEntry(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag != 10) { + break; + } + + message.key = reader.string(); + continue; + case 2: + if (tag != 18) { + break; + } + + message.value = reader.string(); + continue; + } + if ((tag & 7) == 4 || tag == 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): OptionalsTest_TranslationsEntry { + return { key: isSet(object.key) ? String(object.key) : "", value: isSet(object.value) ? String(object.value) : "" }; + }, + + toJSON(message: OptionalsTest_TranslationsEntry): unknown { + const obj: any = {}; + message.key !== undefined && (obj.key = message.key); + message.value !== undefined && (obj.value = message.value); + return obj; + }, + + create, I>>(base?: I): OptionalsTest_TranslationsEntry { + return OptionalsTest_TranslationsEntry.fromPartial(base ?? {}); + }, + + fromPartial, I>>( + object: I, + ): OptionalsTest_TranslationsEntry { + const message = createBaseOptionalsTest_TranslationsEntry(); + message.key = object.key ?? ""; + message.value = object.value ?? ""; + return message; + }, +}; + +function createBaseChild(): Child { + return {}; +} + +export const Child = { + encode(_: Child, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): Child { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseChild(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + } + if ((tag & 7) == 4 || tag == 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(_: any): Child { + return {}; + }, + + toJSON(_: Child): unknown { + const obj: any = {}; + return obj; + }, + + create, I>>(base?: I): Child { + return Child.fromPartial(base ?? {}); + }, + + fromPartial, I>>(_: I): Child { + const message = createBaseChild(); + return message; + }, +}; + +declare var self: any | undefined; +declare var window: any | undefined; +declare var global: any | undefined; +var tsProtoGlobalThis: any = (() => { + if (typeof globalThis !== "undefined") { + return globalThis; + } + if (typeof self !== "undefined") { + return self; + } + if (typeof window !== "undefined") { + return window; + } + if (typeof global !== "undefined") { + return global; + } + throw "Unable to locate global object"; +})(); + +function bytesFromBase64(b64: string): Uint8Array { + if (tsProtoGlobalThis.Buffer) { + return Uint8Array.from(tsProtoGlobalThis.Buffer.from(b64, "base64")); + } else { + const bin = tsProtoGlobalThis.atob(b64); + const arr = new Uint8Array(bin.length); + for (let i = 0; i < bin.length; ++i) { + arr[i] = bin.charCodeAt(i); + } + return arr; + } +} + +function base64FromBytes(arr: Uint8Array): string { + if (tsProtoGlobalThis.Buffer) { + return tsProtoGlobalThis.Buffer.from(arr).toString("base64"); + } else { + const bin: string[] = []; + arr.forEach((byte) => { + bin.push(String.fromCharCode(byte)); + }); + return tsProtoGlobalThis.btoa(bin.join("")); + } +} + +type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; + +export type DeepPartial = T extends Builtin ? T + : T extends Array ? Array> : T extends ReadonlyArray ? ReadonlyArray> + : T extends {} ? { [K in keyof T]?: DeepPartial } + : Partial; + +type KeysOfUnion = T extends T ? keyof T : never; +export type Exact = P extends Builtin ? P + : P & { [K in keyof P]: Exact } & { [K in Exclude>]: never }; + +function longToNumber(long: Long): number { + if (long.gt(Number.MAX_SAFE_INTEGER)) { + throw new tsProtoGlobalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER"); + } + return long.toNumber(); +} + +// If you get a compile-error about 'Constructor and ... have no overlap', +// add '--ts_proto_opt=esModuleInterop=true' as a flag when calling 'protoc'. +if (_m0.util.Long !== Long) { + _m0.util.Long = Long as any; + _m0.configure(); +} + +function isObject(value: any): boolean { + return typeof value === "object" && value !== null; +} + +function isSet(value: any): boolean { + return value !== null && value !== undefined; +} diff --git a/src/main.ts b/src/main.ts index a2539a728..68d364f8d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1020,6 +1020,9 @@ function generateDecode(ctx: Context, fullName: string, messageDesc: DescriptorP } // and then use the snippet to handle repeated fields if necessary + const initializerNecessary = + !options.initializeFieldsAsUndefined && isOptionalProperty(field, messageDesc.options, options); + if (isRepeated(field)) { const maybeNonNullAssertion = ctx.options.useOptionals === "all" ? "!" : ""; @@ -1030,38 +1033,54 @@ function generateDecode(ctx: Context, fullName: string, messageDesc: DescriptorP const valueSetterSnippet = ctx.options.useMapType ? `message.${fieldName}${maybeNonNullAssertion}.set(${varName}.key, ${varName}.value)` : `message.${fieldName}${maybeNonNullAssertion}[${varName}.key] = ${varName}.value`; + const initializerSnippet = initializerNecessary + ? ` + if(message.${fieldName} === undefined) + message.${fieldName} = ${ctx.options.useMapType ? "new Map()" : "{}"}; + ` + : ""; chunks.push(code` ${tagCheck} const ${varName} = ${readSnippet}; if (${varName}.value !== undefined) { + ${initializerSnippet} ${valueSetterSnippet}; } `); - } else if (packedType(field.type) === undefined) { - chunks.push(code` - ${tagCheck} - message.${fieldName}${maybeNonNullAssertion}.push(${readSnippet}); - `); } else { - const packedTag = ((field.number << 3) | 2) >>> 0; - - chunks.push(code` - if(tag == ${tag}){ + const initializerSnippet = initializerNecessary + ? `if(message.${fieldName} === undefined) + message.${fieldName} = [];` + : ""; + if (packedType(field.type) === undefined) { + chunks.push(code` + ${tagCheck} + ${initializerSnippet} message.${fieldName}${maybeNonNullAssertion}.push(${readSnippet}); - continue; - } + `); + } else { + const packedTag = ((field.number << 3) | 2) >>> 0; - if(tag == ${packedTag}){ - const end2 = reader.uint32() + reader.pos; - while (reader.pos < end2) { + chunks.push(code` + if(tag == ${tag}){ + ${initializerSnippet} message.${fieldName}${maybeNonNullAssertion}.push(${readSnippet}); + continue; } - continue; - } + if(tag == ${packedTag}){ + ${initializerSnippet} + const end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) { + message.${fieldName}${maybeNonNullAssertion}.push(${readSnippet}); + } - break; - `); + continue; + } + + break; + `); + } } } else if (isWithinOneOfThatShouldBeUnion(options, field)) { let oneofName = maybeSnakeToCamel(messageDesc.oneofDecl[field.oneofIndex].name, options);