From 5249801b2d7aeab5af4f83f1db1664b18456e2ba Mon Sep 17 00:00:00 2001 From: Gil Date: Sun, 22 Jan 2023 18:49:15 +0200 Subject: [PATCH 1/9] feat: add support for Struct in NestJS --- integration/grpc-js/google/protobuf/struct.ts | 22 +- integration/nestjs-metadata-grpc-js/hero.ts | 24 ++ .../nestjs-metadata-observables/hero.ts | 24 ++ .../nestjs-metadata-restparameters/hero.ts | 24 ++ integration/nestjs-metadata/hero.ts | 24 ++ integration/nestjs-restparameters/hero.ts | 24 ++ integration/nestjs-simple-observables/hero.ts | 24 ++ .../google/protobuf/empty.ts | 6 + .../nestjs-simple-restparameters/hero.ts | 6 + .../google/protobuf/empty.ts | 6 + .../google/protobuf/timestamp.ts | 6 + integration/nestjs-simple-usedate/hero.ts | 24 ++ .../nestjs-simple/google/protobuf/empty.ts | 6 + .../nestjs-simple/google/protobuf/struct.ts | 206 ++++++++++++ .../google/protobuf/timestamp.ts | 6 + integration/nestjs-simple/hero.bin | Bin 10339 -> 14980 bytes integration/nestjs-simple/hero.proto | 4 +- integration/nestjs-simple/hero.ts | 55 +++ .../nestjs-project/hero.controller.ts | 4 +- .../nestjs-simple/nestjs-simple-test.ts | 4 +- integration/nestjs-simple/sample-service.ts | 2 +- .../nice-grpc/google/protobuf/struct.ts | 22 +- .../google/protobuf/struct.ts | 6 +- .../oneof-unions/google/protobuf/struct.ts | 6 +- .../simple-snake/google/protobuf/struct.ts | 22 +- .../google/protobuf/struct.ts | 22 +- integration/struct/google/protobuf/struct.ts | 22 +- .../type-registry/google/protobuf/struct.ts | 22 +- .../use-map-type/google/protobuf/struct.ts | 19 +- .../google/protobuf/struct.ts | 22 +- .../google/protobuf/struct.ts | 6 +- integration/value/google/protobuf/struct.ts | 22 +- package.json | 4 +- src/main.ts | 85 ++++- yarn.lock | 318 ++++++------------ 35 files changed, 786 insertions(+), 313 deletions(-) create mode 100644 integration/nestjs-simple/google/protobuf/struct.ts diff --git a/integration/grpc-js/google/protobuf/struct.ts b/integration/grpc-js/google/protobuf/struct.ts index 675831508..68e56dd6f 100644 --- a/integration/grpc-js/google/protobuf/struct.ts +++ b/integration/grpc-js/google/protobuf/struct.ts @@ -186,9 +186,13 @@ export const Struct = { }, unwrap(message: Struct): { [key: string]: any } { + if (!message.fields) { + return message; + } const object: { [key: string]: any } = {}; Object.keys(message.fields).forEach((key) => { - object[key] = message.fields[key]; + const unwrappedValue = Value.unwrap(message.fields[key]); + object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; }); return object; }, @@ -380,18 +384,18 @@ export const Value = { return result; }, - unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { - if (message?.stringValue !== undefined) { + unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { return message.stringValue; - } else if (message?.numberValue !== undefined) { + } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { return message.numberValue; - } else if (message?.boolValue !== undefined) { + } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; - } else if (message?.structValue !== undefined) { - return message.structValue; - } else if (message?.listValue !== undefined) { + } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + return Struct.unwrap(message.structValue as any); + } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { return message.listValue; - } else if (message?.nullValue !== undefined) { + } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } return undefined; diff --git a/integration/nestjs-metadata-grpc-js/hero.ts b/integration/nestjs-metadata-grpc-js/hero.ts index 54483ffd9..0424fcec7 100644 --- a/integration/nestjs-metadata-grpc-js/hero.ts +++ b/integration/nestjs-metadata-grpc-js/hero.ts @@ -25,6 +25,30 @@ export interface Villain { export const HERO_PACKAGE_NAME = "hero"; +function createBaseHeroById(): HeroById { + return { id: 0 }; +} + +export const HeroById = {}; + +function createBaseVillainById(): VillainById { + return { id: 0 }; +} + +export const VillainById = {}; + +function createBaseHero(): Hero { + return { id: 0, name: "" }; +} + +export const Hero = {}; + +function createBaseVillain(): Villain { + return { id: 0, name: "" }; +} + +export const Villain = {}; + export interface HeroServiceClient { findOneHero(request: HeroById, metadata?: Metadata): Observable; diff --git a/integration/nestjs-metadata-observables/hero.ts b/integration/nestjs-metadata-observables/hero.ts index 197aa85d4..517d27999 100644 --- a/integration/nestjs-metadata-observables/hero.ts +++ b/integration/nestjs-metadata-observables/hero.ts @@ -25,6 +25,30 @@ export interface Villain { export const HERO_PACKAGE_NAME = "hero"; +function createBaseHeroById(): HeroById { + return { id: 0 }; +} + +export const HeroById = {}; + +function createBaseVillainById(): VillainById { + return { id: 0 }; +} + +export const VillainById = {}; + +function createBaseHero(): Hero { + return { id: 0, name: "" }; +} + +export const Hero = {}; + +function createBaseVillain(): Villain { + return { id: 0, name: "" }; +} + +export const Villain = {}; + export interface HeroServiceClient { findOneHero(request: HeroById, metadata?: Metadata): Observable; diff --git a/integration/nestjs-metadata-restparameters/hero.ts b/integration/nestjs-metadata-restparameters/hero.ts index 6ef287bac..ac0262b69 100644 --- a/integration/nestjs-metadata-restparameters/hero.ts +++ b/integration/nestjs-metadata-restparameters/hero.ts @@ -25,6 +25,30 @@ export interface Villain { export const HERO_PACKAGE_NAME = "hero"; +function createBaseHeroById(): HeroById { + return { id: 0 }; +} + +export const HeroById = {}; + +function createBaseVillainById(): VillainById { + return { id: 0 }; +} + +export const VillainById = {}; + +function createBaseHero(): Hero { + return { id: 0, name: "" }; +} + +export const Hero = {}; + +function createBaseVillain(): Villain { + return { id: 0, name: "" }; +} + +export const Villain = {}; + export interface HeroServiceClient { findOneHero(request: HeroById, metadata: Metadata, ...rest: any): Observable; diff --git a/integration/nestjs-metadata/hero.ts b/integration/nestjs-metadata/hero.ts index 54483ffd9..0424fcec7 100644 --- a/integration/nestjs-metadata/hero.ts +++ b/integration/nestjs-metadata/hero.ts @@ -25,6 +25,30 @@ export interface Villain { export const HERO_PACKAGE_NAME = "hero"; +function createBaseHeroById(): HeroById { + return { id: 0 }; +} + +export const HeroById = {}; + +function createBaseVillainById(): VillainById { + return { id: 0 }; +} + +export const VillainById = {}; + +function createBaseHero(): Hero { + return { id: 0, name: "" }; +} + +export const Hero = {}; + +function createBaseVillain(): Villain { + return { id: 0, name: "" }; +} + +export const Villain = {}; + export interface HeroServiceClient { findOneHero(request: HeroById, metadata?: Metadata): Observable; diff --git a/integration/nestjs-restparameters/hero.ts b/integration/nestjs-restparameters/hero.ts index abf56feb9..c6237a7db 100644 --- a/integration/nestjs-restparameters/hero.ts +++ b/integration/nestjs-restparameters/hero.ts @@ -24,6 +24,30 @@ export interface Villain { export const HERO_PACKAGE_NAME = "hero"; +function createBaseHeroById(): HeroById { + return { id: 0 }; +} + +export const HeroById = {}; + +function createBaseVillainById(): VillainById { + return { id: 0 }; +} + +export const VillainById = {}; + +function createBaseHero(): Hero { + return { id: 0, name: "" }; +} + +export const Hero = {}; + +function createBaseVillain(): Villain { + return { id: 0, name: "" }; +} + +export const Villain = {}; + export interface HeroServiceClient { findOneHero(request: HeroById, ...rest: any): Observable; diff --git a/integration/nestjs-simple-observables/hero.ts b/integration/nestjs-simple-observables/hero.ts index 7c884baf4..463c98794 100644 --- a/integration/nestjs-simple-observables/hero.ts +++ b/integration/nestjs-simple-observables/hero.ts @@ -24,6 +24,30 @@ export interface Villain { export const HERO_PACKAGE_NAME = "hero"; +function createBaseHeroById(): HeroById { + return { id: 0 }; +} + +export const HeroById = {}; + +function createBaseVillainById(): VillainById { + return { id: 0 }; +} + +export const VillainById = {}; + +function createBaseHero(): Hero { + return { id: 0, name: "" }; +} + +export const Hero = {}; + +function createBaseVillain(): Villain { + return { id: 0, name: "" }; +} + +export const Villain = {}; + export interface HeroServiceClient { findOneHero(request: HeroById): Observable; diff --git a/integration/nestjs-simple-restparameters/google/protobuf/empty.ts b/integration/nestjs-simple-restparameters/google/protobuf/empty.ts index 642a965dc..c8dc970f5 100644 --- a/integration/nestjs-simple-restparameters/google/protobuf/empty.ts +++ b/integration/nestjs-simple-restparameters/google/protobuf/empty.ts @@ -17,3 +17,9 @@ export interface Empty { } export const GOOGLE_PROTOBUF_PACKAGE_NAME = "google.protobuf"; + +function createBaseEmpty(): Empty { + return {}; +} + +export const Empty = {}; diff --git a/integration/nestjs-simple-restparameters/hero.ts b/integration/nestjs-simple-restparameters/hero.ts index b7bb522a5..178e460c8 100644 --- a/integration/nestjs-simple-restparameters/hero.ts +++ b/integration/nestjs-simple-restparameters/hero.ts @@ -12,6 +12,12 @@ export interface User { export const HERO_PACKAGE_NAME = "hero"; +function createBaseUser(): User { + return { id: 0, name: "" }; +} + +export const User = {}; + export interface HeroServiceClient { findCurrentUser(request: Empty, ...rest: any): Observable; } diff --git a/integration/nestjs-simple-usedate/google/protobuf/empty.ts b/integration/nestjs-simple-usedate/google/protobuf/empty.ts index 642a965dc..c8dc970f5 100644 --- a/integration/nestjs-simple-usedate/google/protobuf/empty.ts +++ b/integration/nestjs-simple-usedate/google/protobuf/empty.ts @@ -17,3 +17,9 @@ export interface Empty { } export const GOOGLE_PROTOBUF_PACKAGE_NAME = "google.protobuf"; + +function createBaseEmpty(): Empty { + return {}; +} + +export const Empty = {}; diff --git a/integration/nestjs-simple-usedate/google/protobuf/timestamp.ts b/integration/nestjs-simple-usedate/google/protobuf/timestamp.ts index 229cba608..48d8e3e7e 100644 --- a/integration/nestjs-simple-usedate/google/protobuf/timestamp.ts +++ b/integration/nestjs-simple-usedate/google/protobuf/timestamp.ts @@ -110,3 +110,9 @@ export interface Timestamp { } export const GOOGLE_PROTOBUF_PACKAGE_NAME = "google.protobuf"; + +function createBaseTimestamp(): Timestamp { + return { seconds: 0, nanos: 0 }; +} + +export const Timestamp = {}; diff --git a/integration/nestjs-simple-usedate/hero.ts b/integration/nestjs-simple-usedate/hero.ts index cf606e35d..17044f590 100644 --- a/integration/nestjs-simple-usedate/hero.ts +++ b/integration/nestjs-simple-usedate/hero.ts @@ -36,6 +36,30 @@ wrappers[".google.protobuf.Timestamp"] = { }, } as any; +function createBaseHeroById(): HeroById { + return { id: 0 }; +} + +export const HeroById = {}; + +function createBaseVillainById(): VillainById { + return { id: 0 }; +} + +export const VillainById = {}; + +function createBaseHero(): Hero { + return { id: 0, name: "", birthDate: undefined }; +} + +export const Hero = {}; + +function createBaseVillain(): Villain { + return { id: 0, name: "" }; +} + +export const Villain = {}; + export interface HeroServiceClient { addOneHero(request: Hero): Observable; diff --git a/integration/nestjs-simple/google/protobuf/empty.ts b/integration/nestjs-simple/google/protobuf/empty.ts index 642a965dc..c8dc970f5 100644 --- a/integration/nestjs-simple/google/protobuf/empty.ts +++ b/integration/nestjs-simple/google/protobuf/empty.ts @@ -17,3 +17,9 @@ export interface Empty { } export const GOOGLE_PROTOBUF_PACKAGE_NAME = "google.protobuf"; + +function createBaseEmpty(): Empty { + return {}; +} + +export const Empty = {}; diff --git a/integration/nestjs-simple/google/protobuf/struct.ts b/integration/nestjs-simple/google/protobuf/struct.ts new file mode 100644 index 000000000..b57ff9d6f --- /dev/null +++ b/integration/nestjs-simple/google/protobuf/struct.ts @@ -0,0 +1,206 @@ +/* eslint-disable */ +import { wrappers } from "protobufjs"; + +export const protobufPackage = "google.protobuf"; + +/** + * `NullValue` is a singleton enumeration to represent the null value for the + * `Value` type union. + * + * The JSON representation for `NullValue` is JSON `null`. + */ +export enum NullValue { + /** NULL_VALUE - Null value. */ + NULL_VALUE = 0, + UNRECOGNIZED = -1, +} + +/** + * `Struct` represents a structured data value, consisting of fields + * which map to dynamically typed values. In some languages, `Struct` + * might be supported by a native representation. For example, in + * scripting languages like JS a struct is represented as an + * object. The details of that representation are described together + * with the proto support for the language. + * + * The JSON representation for `Struct` is JSON object. + */ +export interface Struct { + /** Unordered map of dynamically typed values. */ + fields: { [key: string]: any | undefined }; +} + +export interface Struct_FieldsEntry { + key: string; + value: any | undefined; +} + +/** + * `Value` represents a dynamically typed value which can be either + * null, a number, a string, a boolean, a recursive struct value, or a + * list of values. A producer of value is expected to set one of these + * variants. Absence of any variant indicates an error. + * + * The JSON representation for `Value` is JSON value. + */ +export interface Value { + /** Represents a null value. */ + nullValue?: + | NullValue + | undefined; + /** Represents a double value. */ + numberValue?: + | number + | undefined; + /** Represents a string value. */ + stringValue?: + | string + | undefined; + /** Represents a boolean value. */ + boolValue?: + | boolean + | undefined; + /** Represents a structured value. */ + structValue?: + | { [key: string]: any } + | undefined; + /** Represents a repeated `Value`. */ + listValue?: Array | undefined; +} + +/** + * `ListValue` is a wrapper around a repeated field of values. + * + * The JSON representation for `ListValue` is JSON array. + */ +export interface ListValue { + /** Repeated field of dynamically typed values. */ + values: any[]; +} + +export const GOOGLE_PROTOBUF_PACKAGE_NAME = "google.protobuf"; + +const wrapStruct = (value: any, nested = false): any => { + const valueType = typeof value; + const primitiveValueTypes = { number: "numberValue", string: "stringValue", boolean: "boolValue" }; + if (Object.keys(primitiveValueTypes).includes(valueType)) { + return Value.wrap(value); + } + if (Array.isArray(value)) { + return { listValue: { values: value.map((item) => wrapStruct(item)) } }; + } + if (valueType === "object") { + const res = nested ? { structValue: { fields: {} as any } } : { fields: {} as any }; + Object.keys(value).forEach((field) => { + if (nested) { + res.structValue!.fields[field] = wrapStruct(value[field], true); + } else { + res.fields![field] = wrapStruct(value[field], true); + } + }); + return res; + } +}; +wrappers[".google.protobuf.Struct"] = { + fromObject: wrapStruct, + toObject(message: Struct) { + return message ? Struct.unwrap(message) : message; + }, +} as any; + +function createBaseStruct(): Struct { + return { fields: {} }; +} + +export const Struct = { + wrap(object: { [key: string]: any } | undefined): Struct { + const struct = createBaseStruct(); + if (object !== undefined) { + Object.keys(object).forEach((key) => { + struct.fields[key] = object[key]; + }); + } + return struct; + }, + + unwrap(message: Struct): { [key: string]: any } { + if (!message.fields) { + return message; + } + const object: { [key: string]: any } = {}; + Object.keys(message.fields).forEach((key) => { + const unwrappedValue = Value.unwrap(message.fields[key]); + object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; + }); + return object; + }, +}; + +function createBaseStruct_FieldsEntry(): Struct_FieldsEntry { + return { key: "", value: undefined }; +} + +export const Struct_FieldsEntry = {}; + +function createBaseValue(): Value { + return {}; +} + +export const Value = { + wrap(value: any): Value { + const result = createBaseValue(); + + if (value === null) { + result.nullValue = NullValue.NULL_VALUE; + } else if (typeof value === "boolean") { + result.boolValue = value; + } else if (typeof value === "number") { + result.numberValue = value; + } else if (typeof value === "string") { + result.stringValue = value; + } else if (Array.isArray(value)) { + result.listValue = value; + } else if (typeof value === "object") { + result.structValue = value; + } else if (typeof value !== "undefined") { + throw new Error("Unsupported any value type: " + typeof value); + } + + return result; + }, + + unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { + return message.stringValue; + } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { + return message.numberValue; + } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { + return message.boolValue; + } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + return Struct.unwrap(message.structValue as any); + } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { + return message.listValue.values.map(Value.unwrap); + } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { + return null; + } + return undefined; + }, +}; + +function createBaseListValue(): ListValue { + return { values: [] }; +} + +export const ListValue = { + wrap(value: Array | undefined): ListValue { + const result = createBaseListValue(); + + result.values = value ?? []; + + return result; + }, + + unwrap(message: ListValue): Array { + return message.values; + }, +}; diff --git a/integration/nestjs-simple/google/protobuf/timestamp.ts b/integration/nestjs-simple/google/protobuf/timestamp.ts index 229cba608..48d8e3e7e 100644 --- a/integration/nestjs-simple/google/protobuf/timestamp.ts +++ b/integration/nestjs-simple/google/protobuf/timestamp.ts @@ -110,3 +110,9 @@ export interface Timestamp { } export const GOOGLE_PROTOBUF_PACKAGE_NAME = "google.protobuf"; + +function createBaseTimestamp(): Timestamp { + return { seconds: 0, nanos: 0 }; +} + +export const Timestamp = {}; diff --git a/integration/nestjs-simple/hero.bin b/integration/nestjs-simple/hero.bin index 3ce8c0002f7898aaeb78e40ea3d5a6a27c2c00c6..cf9d51c3e3cbf53935f5a2c887bc5537d93aaa62 100644 GIT binary patch delta 3786 zcmai0OK%*<5uVp>W_uqbhZ0E*msE4tN!RW<$d z<1a`5T5R~gG+2E4M8HEFdPCh^gxcJcqn%C8)IQOJ%Wj}zi(`o$X+=wvPw8Q zY>QaCQvfDR$~aANoLiwPy>MS!*%UfisZ(WinXz^hWpOw#ap^8PQwATi3hYr^jZ%O~ zd3pM^P*o-G8>z&Hy>dsM{oXKhE=uRu^W1=mw5PktUJ7@L%z4%eyN!=nDYx)itoWSj znvtsOo|S!jwAYf}o7(KHSysyH=+zi|w7s$M^vTM`_UgECCuNhJ=o9`<8T^@@;EQTUXhCJZvhEXiKyc;9|mw7gMCkltC37F*3 z9#m!uQ+qQ&o^HkR9eNV5Sg2#cEzbG5Q{)oYBQOX zg4>nZI(t)MLU-4x`}Nb9-DuSAi!-QZfoyeX7G-m{JgrepfZp|IHK^s;tFMD9o_U(p zM5bt2KwZsIEugOEs1{IHf%=vV6~aAd#-BSKs_vOHvD!er=eRmL8>sh6lS)c0n~ zAV17mD**Xn&RPM;4?)^@CbJ6YoGs&t>HpK@yZP5-ml__!gi-2?BtpMp!bGfg7PfM} z+*7%ZPP!)BP%H~bE^R&vY0IMB|M#*weZSmSyM(<9S2TTrns2L6V?J{Va$jwy)`VZ> zdnvG3HBk{#-d@|vFiR3wTYJAb!W6Z5QQN<=wyhR6YJ}vbFr}Pb1H-0jiSgWfA~N7vx?d z9TF`q-q3C^WX?O#ZQ^Jp3Yid8J%FYK`MTC{zsZ1i>44$hp6k09i z*8AEGLdChSRkSTCt|S0)(I%-}x=gy1M4(jo+nFhttNboYkM>IC<|i5x6jz;fZAg2f z>Pi%VIKZqfT+MWVtX_LJlK@h^wW>j2SaTj|RZ2Ud=5j3-;8$xbWfDTE-ME!WK&jnc zBXa1eH(^Xla^&-2!W}1c^?ZPiTu8uOo>R&sTt!4_9pJpNbX?-$J#f*OR(M3sMMbvy zKuu{pe64^trSTxakeDDmNWh!Ia8r1g?MueIf+NN*;d@8nq4z!8*KiODUJ6mgr>4Z$ zcxp;~;3+?V%sT2}V_Edon$`On66wlgG7LxvW7djj-P1Vq1} qlg4tSDlQ-hsv?xYThLkCRJw-F8Up+pI%`Oz(^*4;Tf>{oR?4rn*eTlp delta 969 zcmXw%&2G~`6otn#*Un^YlVlQ?IDz~k5vc_sC9R4mWdo?N>N6m99aO;*dDAyYc?MQU zNbGqT-hnmej_>U9>CX9lGI#F2{=NRSUgS@I;RvK853gD*+yd8_{L0+Pr`K=PcyY_>+{Q** { + const valueType = typeof value; + const primitiveValueTypes = { number: "numberValue", string: "stringValue", boolean: "boolValue" }; + if (Object.keys(primitiveValueTypes).includes(valueType)) { + return Value.wrap(value); + } + if (Array.isArray(value)) { + return { listValue: { values: value.map((item) => wrapStruct(item)) } }; + } + if (valueType === "object") { + const res = nested ? { structValue: { fields: {} as any } } : { fields: {} as any }; + Object.keys(value).forEach((field) => { + if (nested) { + res.structValue!.fields[field] = wrapStruct(value[field], true); + } else { + res.fields![field] = wrapStruct(value[field], true); + } + }); + return res; + } +}; +wrappers[".google.protobuf.Struct"] = { + fromObject: wrapStruct, + toObject(message: Struct) { + return message ? Struct.unwrap(message) : message; + }, +} as any; + +function createBaseHeroById(): HeroById { + return { id: 0 }; +} + +export const HeroById = {}; + +function createBaseVillainById(): VillainById { + return { id: 0 }; +} + +export const VillainById = {}; + +function createBaseHero(): Hero { + return { id: 0, name: "", birthDate: undefined, externalData: undefined }; +} + +export const Hero = {}; + +function createBaseVillain(): Villain { + return { id: 0, name: "" }; +} + +export const Villain = {}; + export interface HeroServiceClient { addOneHero(request: Hero): Observable; diff --git a/integration/nestjs-simple/nestjs-project/hero.controller.ts b/integration/nestjs-simple/nestjs-project/hero.controller.ts index ff1543604..69fafb9a8 100644 --- a/integration/nestjs-simple/nestjs-project/hero.controller.ts +++ b/integration/nestjs-simple/nestjs-project/hero.controller.ts @@ -6,8 +6,8 @@ import { Hero, HeroById, HeroServiceController, HeroServiceControllerMethods, Vi @HeroServiceControllerMethods() export class HeroController implements HeroServiceController { private readonly heroes: Hero[] = [ - { id: 1, name: 'Stephenh', birthDate: { seconds: 1, nanos: 2 } }, - { id: 2, name: 'Iangregsondev', birthDate: { seconds: 1, nanos: 3 } }, + { id: 1, name: 'Stephenh', birthDate: { seconds: 1, nanos: 2 }, externalData: { foo: 'bar', fizz: 1, nested: { isFailing: false, arr: [1,'foo',['bar']] } } }, + { id: 2, name: 'Iangregsondev', birthDate: { seconds: 1, nanos: 3 }, externalData: { bar: 10, baz: 'foo', isPassing: true } }, ]; private readonly villains: Villain[] = [{ id: 1, name: 'John' }, { id: 2, name: 'Doe' }]; diff --git a/integration/nestjs-simple/nestjs-simple-test.ts b/integration/nestjs-simple/nestjs-simple-test.ts index 5670966f6..47e07c294 100644 --- a/integration/nestjs-simple/nestjs-simple-test.ts +++ b/integration/nestjs-simple/nestjs-simple-test.ts @@ -37,13 +37,13 @@ describe('nestjs-simple-test nestjs', () => { }); it('should addOneHero', async () => { - const emptyResponse = await heroService.addOneHero({ id: 3, name: 'Toon', birthDate: undefined }).toPromise(); + const emptyResponse = await heroService.addOneHero({ id: 3, name: 'Toon', birthDate: undefined, externalData: { some: 'data' } }).toPromise(); expect(emptyResponse).toEqual({}); }); it('should findOneHero', async () => { const hero = await heroService.findOneHero({ id: 1 }).toPromise(); - expect(hero).toEqual({ id: 1, name: 'Stephenh', birthDate: { seconds: 1, nanos: 2 } }); + expect(hero).toEqual({ id: 1, name: 'Stephenh', birthDate: { seconds: 1, nanos: 2 }, externalData: { foo: 'bar', fizz: 1, nested: { isFailing: false, arr: [1,'foo',['bar']] } } }); }); it('should findOneVillain', async () => { diff --git a/integration/nestjs-simple/sample-service.ts b/integration/nestjs-simple/sample-service.ts index 1999780ee..b1774713a 100644 --- a/integration/nestjs-simple/sample-service.ts +++ b/integration/nestjs-simple/sample-service.ts @@ -5,7 +5,7 @@ export class SampleService implements HeroServiceController { addOneHero(request: Hero): void {} findOneHero(request: HeroById): Promise { - return Promise.resolve({ id: 1, name: 'test', birthDate: undefined }); + return Promise.resolve({ id: 1, name: 'test', birthDate: undefined, externalData: { foo: 'bar', fizz: 1, nested: { isFailing: false, array: [1, 'foo', ['bar']] } } }); } findOneVillain(request: VillainById): Promise { diff --git a/integration/nice-grpc/google/protobuf/struct.ts b/integration/nice-grpc/google/protobuf/struct.ts index 05fcd4f06..ca416404c 100644 --- a/integration/nice-grpc/google/protobuf/struct.ts +++ b/integration/nice-grpc/google/protobuf/struct.ts @@ -186,9 +186,13 @@ export const Struct = { }, unwrap(message: Struct): { [key: string]: any } { + if (!message.fields) { + return message; + } const object: { [key: string]: any } = {}; Object.keys(message.fields).forEach((key) => { - object[key] = message.fields[key]; + const unwrappedValue = Value.unwrap(message.fields[key]); + object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; }); return object; }, @@ -380,18 +384,18 @@ export const Value = { return result; }, - unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { - if (message?.stringValue !== undefined) { + unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { return message.stringValue; - } else if (message?.numberValue !== undefined) { + } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { return message.numberValue; - } else if (message?.boolValue !== undefined) { + } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; - } else if (message?.structValue !== undefined) { - return message.structValue; - } else if (message?.listValue !== undefined) { + } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + return Struct.unwrap(message.structValue as any); + } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { return message.listValue; - } else if (message?.nullValue !== undefined) { + } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } return undefined; diff --git a/integration/oneof-unions-snake/google/protobuf/struct.ts b/integration/oneof-unions-snake/google/protobuf/struct.ts index fa4e1e60e..8ba75d535 100644 --- a/integration/oneof-unions-snake/google/protobuf/struct.ts +++ b/integration/oneof-unions-snake/google/protobuf/struct.ts @@ -171,9 +171,13 @@ export const Struct = { }, unwrap(message: Struct): { [key: string]: any } { + if (!message.fields) { + return message; + } const object: { [key: string]: any } = {}; Object.keys(message.fields).forEach((key) => { - object[key] = message.fields[key]; + const unwrappedValue = Value.unwrap(message.fields[key]); + object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; }); return object; }, diff --git a/integration/oneof-unions/google/protobuf/struct.ts b/integration/oneof-unions/google/protobuf/struct.ts index edc0424c4..777b2ccf9 100644 --- a/integration/oneof-unions/google/protobuf/struct.ts +++ b/integration/oneof-unions/google/protobuf/struct.ts @@ -171,9 +171,13 @@ export const Struct = { }, unwrap(message: Struct): { [key: string]: any } { + if (!message.fields) { + return message; + } const object: { [key: string]: any } = {}; Object.keys(message.fields).forEach((key) => { - object[key] = message.fields[key]; + const unwrappedValue = Value.unwrap(message.fields[key]); + object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; }); return object; }, diff --git a/integration/simple-snake/google/protobuf/struct.ts b/integration/simple-snake/google/protobuf/struct.ts index 26f96d343..9b4932e8d 100644 --- a/integration/simple-snake/google/protobuf/struct.ts +++ b/integration/simple-snake/google/protobuf/struct.ts @@ -186,9 +186,13 @@ export const Struct = { }, unwrap(message: Struct): { [key: string]: any } { + if (!message.fields) { + return message; + } const object: { [key: string]: any } = {}; Object.keys(message.fields).forEach((key) => { - object[key] = message.fields[key]; + const unwrappedValue = Value.unwrap(message.fields[key]); + object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; }); return object; }, @@ -380,18 +384,18 @@ export const Value = { return result; }, - unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { - if (message?.string_value !== undefined) { + unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty("string_value") && message?.string_value !== undefined) { return message.string_value; - } else if (message?.number_value !== undefined) { + } else if (message?.hasOwnProperty("number_value") && message?.number_value !== undefined) { return message.number_value; - } else if (message?.bool_value !== undefined) { + } else if (message?.hasOwnProperty("bool_value") && message?.bool_value !== undefined) { return message.bool_value; - } else if (message?.struct_value !== undefined) { - return message.struct_value; - } else if (message?.list_value !== undefined) { + } else if (message?.hasOwnProperty("struct_value") && message?.struct_value !== undefined) { + return Struct.unwrap(message.struct_value as any); + } else if (message?.hasOwnProperty("list_value") && message?.list_value !== undefined) { return message.list_value; - } else if (message?.null_value !== undefined) { + } else if (message?.hasOwnProperty("null_value") && message?.null_value !== undefined) { return null; } return undefined; diff --git a/integration/simple-string-enums/google/protobuf/struct.ts b/integration/simple-string-enums/google/protobuf/struct.ts index 532be4633..46084f1bf 100644 --- a/integration/simple-string-enums/google/protobuf/struct.ts +++ b/integration/simple-string-enums/google/protobuf/struct.ts @@ -196,9 +196,13 @@ export const Struct = { }, unwrap(message: Struct): { [key: string]: any } { + if (!message.fields) { + return message; + } const object: { [key: string]: any } = {}; Object.keys(message.fields).forEach((key) => { - object[key] = message.fields[key]; + const unwrappedValue = Value.unwrap(message.fields[key]); + object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; }); return object; }, @@ -390,18 +394,18 @@ export const Value = { return result; }, - unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { - if (message?.stringValue !== undefined) { + unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { return message.stringValue; - } else if (message?.numberValue !== undefined) { + } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { return message.numberValue; - } else if (message?.boolValue !== undefined) { + } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; - } else if (message?.structValue !== undefined) { - return message.structValue; - } else if (message?.listValue !== undefined) { + } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + return Struct.unwrap(message.structValue as any); + } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { return message.listValue; - } else if (message?.nullValue !== undefined) { + } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } return undefined; diff --git a/integration/struct/google/protobuf/struct.ts b/integration/struct/google/protobuf/struct.ts index 675831508..68e56dd6f 100644 --- a/integration/struct/google/protobuf/struct.ts +++ b/integration/struct/google/protobuf/struct.ts @@ -186,9 +186,13 @@ export const Struct = { }, unwrap(message: Struct): { [key: string]: any } { + if (!message.fields) { + return message; + } const object: { [key: string]: any } = {}; Object.keys(message.fields).forEach((key) => { - object[key] = message.fields[key]; + const unwrappedValue = Value.unwrap(message.fields[key]); + object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; }); return object; }, @@ -380,18 +384,18 @@ export const Value = { return result; }, - unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { - if (message?.stringValue !== undefined) { + unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { return message.stringValue; - } else if (message?.numberValue !== undefined) { + } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { return message.numberValue; - } else if (message?.boolValue !== undefined) { + } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; - } else if (message?.structValue !== undefined) { - return message.structValue; - } else if (message?.listValue !== undefined) { + } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + return Struct.unwrap(message.structValue as any); + } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { return message.listValue; - } else if (message?.nullValue !== undefined) { + } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } return undefined; diff --git a/integration/type-registry/google/protobuf/struct.ts b/integration/type-registry/google/protobuf/struct.ts index 419bdfa1a..6c6703e07 100644 --- a/integration/type-registry/google/protobuf/struct.ts +++ b/integration/type-registry/google/protobuf/struct.ts @@ -197,9 +197,13 @@ export const Struct = { }, unwrap(message: Struct): { [key: string]: any } { + if (!message.fields) { + return message; + } const object: { [key: string]: any } = {}; Object.keys(message.fields).forEach((key) => { - object[key] = message.fields[key]; + const unwrappedValue = Value.unwrap(message.fields[key]); + object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; }); return object; }, @@ -405,18 +409,18 @@ export const Value = { return result; }, - unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { - if (message?.stringValue !== undefined) { + unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { return message.stringValue; - } else if (message?.numberValue !== undefined) { + } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { return message.numberValue; - } else if (message?.boolValue !== undefined) { + } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; - } else if (message?.structValue !== undefined) { - return message.structValue; - } else if (message?.listValue !== undefined) { + } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + return Struct.unwrap(message.structValue as any); + } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { return message.listValue; - } else if (message?.nullValue !== undefined) { + } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } return undefined; diff --git a/integration/use-map-type/google/protobuf/struct.ts b/integration/use-map-type/google/protobuf/struct.ts index 815bfb055..e552c6ef7 100644 --- a/integration/use-map-type/google/protobuf/struct.ts +++ b/integration/use-map-type/google/protobuf/struct.ts @@ -188,7 +188,8 @@ export const Struct = { unwrap(message: Struct): { [key: string]: any } { const object: { [key: string]: any } = {}; [...message.fields.keys()].forEach((key) => { - object[key] = message.fields.get(key); + const unwrappedValue = Value.unwrap(message.fields.get(key)); + object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields.get(key); }); return object; }, @@ -380,18 +381,18 @@ export const Value = { return result; }, - unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { - if (message?.stringValue !== undefined) { + unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { return message.stringValue; - } else if (message?.numberValue !== undefined) { + } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { return message.numberValue; - } else if (message?.boolValue !== undefined) { + } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; - } else if (message?.structValue !== undefined) { - return message.structValue; - } else if (message?.listValue !== undefined) { + } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + return Struct.unwrap(message.structValue as any); + } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { return message.listValue; - } else if (message?.nullValue !== undefined) { + } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } return undefined; diff --git a/integration/use-numeric-enum-json/google/protobuf/struct.ts b/integration/use-numeric-enum-json/google/protobuf/struct.ts index c2655202a..56d3e8d96 100644 --- a/integration/use-numeric-enum-json/google/protobuf/struct.ts +++ b/integration/use-numeric-enum-json/google/protobuf/struct.ts @@ -186,9 +186,13 @@ export const Struct = { }, unwrap(message: Struct): { [key: string]: any } { + if (!message.fields) { + return message; + } const object: { [key: string]: any } = {}; Object.keys(message.fields).forEach((key) => { - object[key] = message.fields[key]; + const unwrappedValue = Value.unwrap(message.fields[key]); + object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; }); return object; }, @@ -380,18 +384,18 @@ export const Value = { return result; }, - unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { - if (message?.stringValue !== undefined) { + unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { return message.stringValue; - } else if (message?.numberValue !== undefined) { + } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { return message.numberValue; - } else if (message?.boolValue !== undefined) { + } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; - } else if (message?.structValue !== undefined) { - return message.structValue; - } else if (message?.listValue !== undefined) { + } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + return Struct.unwrap(message.structValue as any); + } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { return message.listValue; - } else if (message?.nullValue !== undefined) { + } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } return undefined; diff --git a/integration/use-readonly-types/google/protobuf/struct.ts b/integration/use-readonly-types/google/protobuf/struct.ts index a1a5fc0ae..584ea58f3 100644 --- a/integration/use-readonly-types/google/protobuf/struct.ts +++ b/integration/use-readonly-types/google/protobuf/struct.ts @@ -171,9 +171,13 @@ export const Struct = { }, unwrap(message: Struct): { [key: string]: any } { + if (!message.fields) { + return message; + } const object: { [key: string]: any } = {}; Object.keys(message.fields).forEach((key) => { - object[key] = message.fields[key]; + const unwrappedValue = Value.unwrap(message.fields[key]); + object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; }); return object; }, diff --git a/integration/value/google/protobuf/struct.ts b/integration/value/google/protobuf/struct.ts index 675831508..68e56dd6f 100644 --- a/integration/value/google/protobuf/struct.ts +++ b/integration/value/google/protobuf/struct.ts @@ -186,9 +186,13 @@ export const Struct = { }, unwrap(message: Struct): { [key: string]: any } { + if (!message.fields) { + return message; + } const object: { [key: string]: any } = {}; Object.keys(message.fields).forEach((key) => { - object[key] = message.fields[key]; + const unwrappedValue = Value.unwrap(message.fields[key]); + object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; }); return object; }, @@ -380,18 +384,18 @@ export const Value = { return result; }, - unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { - if (message?.stringValue !== undefined) { + unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { return message.stringValue; - } else if (message?.numberValue !== undefined) { + } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { return message.numberValue; - } else if (message?.boolValue !== undefined) { + } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; - } else if (message?.structValue !== undefined) { - return message.structValue; - } else if (message?.listValue !== undefined) { + } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + return Struct.unwrap(message.structValue as any); + } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { return message.listValue; - } else if (message?.nullValue !== undefined) { + } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } return undefined; diff --git a/package.json b/package.json index c8f5a6b36..7b3e77b4e 100644 --- a/package.json +++ b/package.json @@ -28,8 +28,8 @@ "author": "", "license": "ISC", "devDependencies": { - "@grpc/grpc-js": "^1.2.12", - "@grpc/proto-loader": "^0.5.6", + "@grpc/grpc-js": "^1.3.0", + "@grpc/proto-loader": "^0.6.0", "@improbable-eng/grpc-web": "^0.14.0", "@improbable-eng/grpc-web-node-http-transport": "^0.14.0", "@nestjs/common": "^8.2.2", diff --git a/src/main.ts b/src/main.ts index 67926acc8..a0cacb775 100644 --- a/src/main.ts +++ b/src/main.ts @@ -154,9 +154,25 @@ export function generateFile(ctx: Context, fileDesc: FileDescriptorProto): [stri ) { chunks.push(makeProtobufTimestampWrapper()); } + + if ( + fileDesc.messageType.find((message) => + message.field.find((field) => field.typeName === ".google.protobuf.Struct") + ) + ) { + const structFieldNames = { + nullValue: maybeSnakeToCamel("null_value", ctx.options), + numberValue: maybeSnakeToCamel("number_value", ctx.options), + stringValue: maybeSnakeToCamel("string_value", ctx.options), + boolValue: maybeSnakeToCamel("bool_value", ctx.options), + structValue: maybeSnakeToCamel("struct_value", ctx.options), + listValue: maybeSnakeToCamel("list_value", ctx.options), + }; + chunks.push(makeProtobufStructWrapper(options, structFieldNames)); + } } - if (options.outputEncodeMethods || options.outputJsonMethods || options.outputTypeRegistry) { + if (options.outputEncodeMethods || options.outputJsonMethods || options.outputTypeRegistry || options.nestJs) { // then add the encoder/decoder/base instance visit( fileDesc, @@ -360,6 +376,48 @@ function makeProtobufTimestampWrapper() { } as any;`; } +function makeProtobufStructWrapper(options: Options, fieldNames: StructFieldNames) { + const wrappers = imp("wrappers@protobufjs"); + const Struct = impProto(options, "google/protobuf/struct", "Struct"); + const Value = impProto(options, "google/protobuf/struct", "Value"); + return code` + const wrapStruct = (value: any, nested = false): any => { + const valueType = typeof value; + const primitiveValueTypes = { + number: 'numberValue', + string: 'stringValue', + boolean: 'boolValue' + } + if (Object.keys(primitiveValueTypes).includes(valueType)) { + return ${Value}.wrap(value); + } + if (Array.isArray(value)) { + return { + listValue: { + values: value.map((item) => wrapStruct(item)) + } + }; + } + if (valueType === 'object') { + const res = nested ? { structValue: { fields: {} as any } } : { fields: {} as any }; + Object.keys(value).forEach((field) => { + if (nested) { + res.structValue!.fields[field] = wrapStruct(value[field], true) + } else { + res.fields![field] = wrapStruct(value[field], true) + } + }) + return res; + } + } + ${wrappers}['.google.protobuf.Struct'] = { + fromObject: wrapStruct, + toObject(message: Struct) { + return message ? ${Struct}.unwrap(message) : message; + }, + } as any;`; +} + function makeLongUtils(options: Options, bytes: ReturnType) { // Regardless of which `forceLong` config option we're using, we always use // the `long` library to either represent or at least sanity-check 64-bit values @@ -1867,15 +1925,20 @@ function generateUnwrap(ctx: Context, fullProtoTypeName: string, fieldNames: Str chunks.push(code`unwrap(message: Struct): {[key: string]: any} { const object: { [key: string]: any } = {}; [...message.fields.keys()].forEach((key) => { - object[key] = message.fields.get(key); + const unwrappedValue = Value.unwrap(message.fields.get(key)); + object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields.get(key); }); return object; }`); } else { chunks.push(code`unwrap(message: Struct): {[key: string]: any} { + if (!message.fields) { + return message; + } const object: { [key: string]: any } = {}; Object.keys(message.fields).forEach(key => { - object[key] = message.fields[key]; + const unwrappedValue = Value.unwrap(message.fields[key]); + object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; }); return object; }`); @@ -1902,18 +1965,18 @@ function generateUnwrap(ctx: Context, fullProtoTypeName: string, fieldNames: Str } }`); } else { - chunks.push(code`unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { - if (message?.${fieldNames.stringValue} !== undefined) { + chunks.push(code`unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty('${fieldNames.stringValue}') && message?.${fieldNames.stringValue} !== undefined) { return message.${fieldNames.stringValue}; - } else if (message?.${fieldNames.numberValue} !== undefined) { + } else if (message?.hasOwnProperty('${fieldNames.numberValue}') && message?.${fieldNames.numberValue} !== undefined) { return message.${fieldNames.numberValue}; - } else if (message?.${fieldNames.boolValue} !== undefined) { + } else if (message?.hasOwnProperty('${fieldNames.boolValue}') && message?.${fieldNames.boolValue} !== undefined) { return message.${fieldNames.boolValue}; - } else if (message?.${fieldNames.structValue} !== undefined) { - return message.${fieldNames.structValue}; - } else if (message?.${fieldNames.listValue} !== undefined) { + } else if (message?.hasOwnProperty('${fieldNames.structValue}') && message?.${fieldNames.structValue} !== undefined) { + return Struct.unwrap(message.${fieldNames.structValue} as any); + } else if (message?.hasOwnProperty('${fieldNames.listValue}') && message?.${fieldNames.listValue} !== undefined) { return message.${fieldNames.listValue}; - } else if (message?.${fieldNames.nullValue} !== undefined) { + } else if (message?.hasOwnProperty('${fieldNames.nullValue}') && message?.${fieldNames.nullValue} !== undefined) { return null; } return undefined; diff --git a/yarn.lock b/yarn.lock index b8a63353a..eaae7939c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -530,14 +530,13 @@ __metadata: languageName: node linkType: hard -"@grpc/grpc-js@npm:^1.2.12": - version: 1.2.12 - resolution: "@grpc/grpc-js@npm:1.2.12" +"@grpc/grpc-js@npm:^1.3.0": + version: 1.8.4 + resolution: "@grpc/grpc-js@npm:1.8.4" dependencies: + "@grpc/proto-loader": ^0.7.0 "@types/node": ">=12.12.47" - google-auth-library: ^6.1.1 - semver: ^6.2.0 - checksum: 366ecbfab45d7e59fb071c7ca064ba9fb12cfa24abc6c9d65b1dd9842b3b2bbcfb975b17987a92c7aa00f36389305758099bda284e57d7a95ea89637ae22222c + checksum: dfec3a47dab85eb92e7d1f42c8ad336dd465d3b7d3af08d7c189cc2b267dc4ca45d95e4885c94a9be41a2114dbad04ea839ed2252ccc051882a6856c8f0dc641 languageName: node linkType: hard @@ -551,13 +550,18 @@ __metadata: languageName: node linkType: hard -"@grpc/proto-loader@npm:^0.5.6": - version: 0.5.6 - resolution: "@grpc/proto-loader@npm:0.5.6" +"@grpc/proto-loader@npm:^0.6.0": + version: 0.6.13 + resolution: "@grpc/proto-loader@npm:0.6.13" dependencies: + "@types/long": ^4.0.1 lodash.camelcase: ^4.3.0 - protobufjs: ^6.8.6 - checksum: 13fe76d84ab1a516f3dc47d06df4dd682f6f1515a7a4aa3f8cddcc8f8256f33cbf529bd0b6729946f548f7459acfcd9b5b026c10572e21d40213a358115658b5 + long: ^4.0.0 + protobufjs: ^6.11.3 + yargs: ^16.2.0 + bin: + proto-loader-gen-types: build/bin/proto-loader-gen-types.js + checksum: 863417e961cfa3acb579124f5c2bbfbeaee4d507c33470dc0af3b6792892c68706c6c61e26629f5ff3d28cb631dc4f0a00233323135e322406e3cb19a0b92823 languageName: node linkType: hard @@ -576,6 +580,21 @@ __metadata: languageName: node linkType: hard +"@grpc/proto-loader@npm:^0.7.0": + version: 0.7.4 + resolution: "@grpc/proto-loader@npm:0.7.4" + dependencies: + "@types/long": ^4.0.1 + lodash.camelcase: ^4.3.0 + long: ^4.0.0 + protobufjs: ^7.0.0 + yargs: ^16.2.0 + bin: + proto-loader-gen-types: build/bin/proto-loader-gen-types.js + checksum: 7789a959060535287a74cef8e13783e9a1506ae22365a48e0cfb29f48697ac946b461fe12ee711d280c4690a333c705f504076303a806f2fef81cc3e532637ac + languageName: node + linkType: hard + "@improbable-eng/grpc-web-node-http-transport@npm:^0.14.0": version: 0.14.0 resolution: "@improbable-eng/grpc-web-node-http-transport@npm:0.14.0" @@ -920,12 +939,12 @@ __metadata: linkType: hard "@nestjs/common@npm:^8.2.2": - version: 8.2.2 - resolution: "@nestjs/common@npm:8.2.2" + version: 8.4.7 + resolution: "@nestjs/common@npm:8.4.7" dependencies: - axios: 0.24.0 + axios: 0.27.2 iterare: 1.2.1 - tslib: 2.3.1 + tslib: 2.4.0 uuid: 8.3.2 peerDependencies: cache-manager: "*" @@ -940,20 +959,20 @@ __metadata: optional: true class-validator: optional: true - checksum: 5d74143630d9bbe28d18bb9c47a948f84c2b62aed0974de0963ec3e94da9964b9b214da3622b4b6970456dfe03dc12439728c57570ffca5e2283b4fe3ac6daee + checksum: b3fa20618d4e60f9f5089215c800f2deb5d08b9f88443102b066036d7bacf17ff5926ad5ff0ef7ace42feb8e0ca561dc7e75fd05dbd028f5e675d5e7062eb685 languageName: node linkType: hard "@nestjs/core@npm:^8.2.2": - version: 8.2.2 - resolution: "@nestjs/core@npm:8.2.2" + version: 8.4.7 + resolution: "@nestjs/core@npm:8.4.7" dependencies: "@nuxtjs/opencollective": 0.3.2 fast-safe-stringify: 2.1.1 iterare: 1.2.1 - object-hash: 2.2.0 + object-hash: 3.0.0 path-to-regexp: 3.2.0 - tslib: 2.3.1 + tslib: 2.4.0 uuid: 8.3.2 peerDependencies: "@nestjs/common": ^8.0.0 @@ -969,17 +988,16 @@ __metadata: optional: true "@nestjs/websockets": optional: true - checksum: 5dee8d70b9c8e09c3810f028fdaa91b0025fd11bf2fd47b74d44ee44b6cce9245709f3b69a1661be23ba67688ed67eeb85770a2d0c1812534429976ba103d8e8 + checksum: 58d18b04e03cdae4b06e06f1a60705cdbe2e81824e0a85d0be422cf8dbd39c263287196b85939718659d7eeedc2856f29744487931dbe5c2695fcd374a5fbe40 languageName: node linkType: hard "@nestjs/microservices@npm:^8.2.2": - version: 8.2.2 - resolution: "@nestjs/microservices@npm:8.2.2" + version: 8.4.7 + resolution: "@nestjs/microservices@npm:8.4.7" dependencies: iterare: 1.2.1 - json-socket: 0.3.0 - tslib: 2.3.1 + tslib: 2.4.0 peerDependencies: "@grpc/grpc-js": "*" "@nestjs/common": ^8.0.0 @@ -1013,7 +1031,7 @@ __metadata: optional: true redis: optional: true - checksum: f81987a1773ddf76d89bacfb95c199a1a63753f009aa3df5d2b087ee047001373c136d73afda67ed692295128c23c15a70d1f4ef1fbc53e7c083db1ed26e9911 + checksum: 830946c2c9e696a0fc9e17f96702b6ec43651f327df43636fd32efeb3e9252869a8dc12b822e0f5598524b0b88b7cf497c9ccf1902de6fa3a481de06702e09d8 languageName: node linkType: hard @@ -2114,15 +2132,6 @@ __metadata: languageName: node linkType: hard -"abort-controller@npm:^3.0.0": - version: 3.0.0 - resolution: "abort-controller@npm:3.0.0" - dependencies: - event-target-shim: ^5.0.0 - checksum: 170bdba9b47b7e65906a28c8ce4f38a7a369d78e2271706f020849c1bfe0ee2067d4261df8bbb66eb84f79208fd5b710df759d64191db58cfba7ce8ef9c54b75 - languageName: node - linkType: hard - "agent-base@npm:6, agent-base@npm:^6.0.2": version: 6.0.2 resolution: "agent-base@npm:6.0.2" @@ -2352,13 +2361,6 @@ __metadata: languageName: node linkType: hard -"arrify@npm:^2.0.0": - version: 2.0.1 - resolution: "arrify@npm:2.0.1" - checksum: 067c4c1afd182806a82e4c1cb8acee16ab8b5284fbca1ce29408e6e91281c36bb5b612f6ddfbd40a0f7a7e0c75bf2696eb94c027f6e328d6e9c52465c98e4209 - languageName: node - linkType: hard - "asap@npm:^2.0.0": version: 2.0.6 resolution: "asap@npm:2.0.6" @@ -2410,12 +2412,13 @@ __metadata: languageName: node linkType: hard -"axios@npm:0.24.0": - version: 0.24.0 - resolution: "axios@npm:0.24.0" +"axios@npm:0.27.2": + version: 0.27.2 + resolution: "axios@npm:0.27.2" dependencies: - follow-redirects: ^1.14.4 - checksum: 468cf496c08a6aadfb7e699bebdac02851e3043d4e7d282350804ea8900e30d368daa6e3cd4ab83b8ddb5a3b1e17a5a21ada13fc9cebd27b74828f47a4236316 + follow-redirects: ^1.14.9 + form-data: ^4.0.0 + checksum: 38cb7540465fe8c4102850c4368053c21683af85c5fdf0ea619f9628abbcb59415d1e22ebc8a6390d2bbc9b58a9806c874f139767389c862ec9b772235f06854 languageName: node linkType: hard @@ -2502,7 +2505,7 @@ __metadata: languageName: node linkType: hard -"base64-js@npm:^1.3.0, base64-js@npm:^1.3.1": +"base64-js@npm:^1.3.1": version: 1.5.1 resolution: "base64-js@npm:1.5.1" checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 @@ -2525,13 +2528,6 @@ __metadata: languageName: node linkType: hard -"bignumber.js@npm:^9.0.0": - version: 9.0.1 - resolution: "bignumber.js@npm:9.0.1" - checksum: 6e72f6069d9db32fc8d27561164de9f811b15f9144be61f323d8b36150a239eea50c92e20ba38af2ba5e717af10b8ef12db8f9948fe2ff02bf17ede5239d15d3 - languageName: node - linkType: hard - "bin-links@npm:^2.2.1": version: 2.2.1 resolution: "bin-links@npm:2.2.1" @@ -2650,13 +2646,6 @@ __metadata: languageName: node linkType: hard -"buffer-equal-constant-time@npm:1.0.1": - version: 1.0.1 - resolution: "buffer-equal-constant-time@npm:1.0.1" - checksum: 80bb945f5d782a56f374b292770901065bad21420e34936ecbe949e57724b4a13874f735850dd1cc61f078773c4fb5493a41391e7bda40d1fa388d6bd80daaab - languageName: node - linkType: hard - "buffer-from@npm:^1.0.0": version: 1.1.1 resolution: "buffer-from@npm:1.1.1" @@ -3093,7 +3082,7 @@ __metadata: languageName: node linkType: hard -"combined-stream@npm:^1.0.6, combined-stream@npm:~1.0.6": +"combined-stream@npm:^1.0.6, combined-stream@npm:^1.0.8, combined-stream@npm:~1.0.6": version: 1.0.8 resolution: "combined-stream@npm:1.0.8" dependencies: @@ -3512,15 +3501,6 @@ __metadata: languageName: node linkType: hard -"ecdsa-sig-formatter@npm:1.0.11, ecdsa-sig-formatter@npm:^1.0.11": - version: 1.0.11 - resolution: "ecdsa-sig-formatter@npm:1.0.11" - dependencies: - safe-buffer: ^5.0.1 - checksum: 207f9ab1c2669b8e65540bce29506134613dd5f122cccf1e6a560f4d63f2732d427d938f8481df175505aad94583bcb32c688737bb39a6df0625f903d6d93c03 - languageName: node - linkType: hard - "electron-to-chromium@npm:^1.4.172": version: 1.4.177 resolution: "electron-to-chromium@npm:1.4.177" @@ -3838,13 +3818,6 @@ __metadata: languageName: node linkType: hard -"event-target-shim@npm:^5.0.0": - version: 5.0.1 - resolution: "event-target-shim@npm:5.0.1" - checksum: 1ffe3bb22a6d51bdeb6bf6f7cf97d2ff4a74b017ad12284cc9e6a279e727dc30a5de6bb613e5596ff4dc3e517841339ad09a7eec44266eccb1aa201a30448166 - languageName: node - linkType: hard - "execa@npm:^4.0.0": version: 4.1.0 resolution: "execa@npm:4.1.0" @@ -3899,7 +3872,7 @@ __metadata: languageName: node linkType: hard -"extend@npm:^3.0.2, extend@npm:~3.0.2": +"extend@npm:~3.0.2": version: 3.0.2 resolution: "extend@npm:3.0.2" checksum: a50a8309ca65ea5d426382ff09f33586527882cf532931cb08ca786ea3146c0553310bda688710ff61d7668eba9f96b923fe1420cdf56a2c3eaf30fcab87b515 @@ -3948,13 +3921,6 @@ __metadata: languageName: node linkType: hard -"fast-text-encoding@npm:^1.0.0": - version: 1.0.3 - resolution: "fast-text-encoding@npm:1.0.3" - checksum: 3e51365896f06d0dcab128092d095a0037d274deec419fecbd2388bc236d7b387610e0c72f920c6126e00c885ab096fbfaa3645712f5b98f721bef6b064916a8 - languageName: node - linkType: hard - "fastest-levenshtein@npm:^1.0.12": version: 1.0.12 resolution: "fastest-levenshtein@npm:1.0.12" @@ -4035,13 +4001,13 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.14.4": - version: 1.14.8 - resolution: "follow-redirects@npm:1.14.8" +"follow-redirects@npm:^1.14.9": + version: 1.15.2 + resolution: "follow-redirects@npm:1.15.2" peerDependenciesMeta: debug: optional: true - checksum: 40c67899c2e3149a27e8b6498a338ff27f39fe138fde8d7f0756cb44b073ba0bfec3d52af28f20c5bdd67263d564d0d8d7b5efefd431de95c18c42f7b4aef457 + checksum: faa66059b66358ba65c234c2f2a37fcec029dc22775f35d9ad6abac56003268baf41e55f9ee645957b32c7d9f62baf1f0b906e68267276f54ec4b4c597c2b190 languageName: node linkType: hard @@ -4052,6 +4018,17 @@ __metadata: languageName: node linkType: hard +"form-data@npm:^4.0.0": + version: 4.0.0 + resolution: "form-data@npm:4.0.0" + dependencies: + asynckit: ^0.4.0 + combined-stream: ^1.0.8 + mime-types: ^2.1.12 + checksum: 01135bf8675f9d5c61ff18e2e2932f719ca4de964e3be90ef4c36aacfc7b9cb2fceb5eca0b7e0190e3383fe51c5b37f4cb80b62ca06a99aaabfcfd6ac7c9328c + languageName: node + linkType: hard + "form-data@npm:~2.3.2": version: 2.3.3 resolution: "form-data@npm:2.3.3" @@ -4170,29 +4147,6 @@ __metadata: languageName: node linkType: hard -"gaxios@npm:^4.0.0": - version: 4.2.0 - resolution: "gaxios@npm:4.2.0" - dependencies: - abort-controller: ^3.0.0 - extend: ^3.0.2 - https-proxy-agent: ^5.0.0 - is-stream: ^2.0.0 - node-fetch: ^2.3.0 - checksum: 85b45adcf8eaee849d74816987bcf74fb777d97408e546c76d373a349a727dd7e2694e6d2de77963cf2ae12a76db203dba066e9a4c2069793a4ce8a29323da52 - languageName: node - linkType: hard - -"gcp-metadata@npm:^4.2.0": - version: 4.2.1 - resolution: "gcp-metadata@npm:4.2.1" - dependencies: - gaxios: ^4.0.0 - json-bigint: ^1.0.0 - checksum: 970908f7c74684787f1e76f82b1303f13a65882be8946144cbaf7b9236d5315d045bdba6a1bc15b26b2ac70303511bd9f05dcb23023e8c9241486abc6ceac619 - languageName: node - linkType: hard - "gensync@npm:^1.0.0-beta.2": version: 1.0.0-beta.2 resolution: "gensync@npm:1.0.0-beta.2" @@ -4317,34 +4271,6 @@ __metadata: languageName: node linkType: hard -"google-auth-library@npm:^6.1.1": - version: 6.1.6 - resolution: "google-auth-library@npm:6.1.6" - dependencies: - arrify: ^2.0.0 - base64-js: ^1.3.0 - ecdsa-sig-formatter: ^1.0.11 - fast-text-encoding: ^1.0.0 - gaxios: ^4.0.0 - gcp-metadata: ^4.2.0 - gtoken: ^5.0.4 - jws: ^4.0.0 - lru-cache: ^6.0.0 - checksum: d65fcb43c8c43763dbe086e374675fbef6d55630d68726110f3f96ce3876c5cf36d3de7362b4421efa76979509f92de38268a65486c076055099a5104d4b73db - languageName: node - linkType: hard - -"google-p12-pem@npm:^3.0.3": - version: 3.0.3 - resolution: "google-p12-pem@npm:3.0.3" - dependencies: - node-forge: ^0.10.0 - bin: - gp12-pem: build/src/bin/gp12-pem.js - checksum: b4698748bb14356ce19fdcfe5d58922704a1719f34063e0a2c2533624cd47a0d329bab17464b8f7f21ac1b221e1c5e24aaaa5fe53f5433d6ffa2bcb2d0baf1a2 - languageName: node - linkType: hard - "graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.3, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": version: 4.2.6 resolution: "graceful-fs@npm:4.2.6" @@ -4359,17 +4285,6 @@ __metadata: languageName: node linkType: hard -"gtoken@npm:^5.0.4": - version: 5.2.1 - resolution: "gtoken@npm:5.2.1" - dependencies: - gaxios: ^4.0.0 - google-p12-pem: ^3.0.3 - jws: ^4.0.0 - checksum: fcf476535cc698fb96b8a9438a0396b434294aa5120f39b32dfc49856ef947088764c6c3c5d0b79dbe374dea4cf5cb8ba328e366753f70e3cea607a34fe8d8dd - languageName: node - linkType: hard - "handlebars@npm:^4.7.6, handlebars@npm:^4.7.7": version: 4.7.7 resolution: "handlebars@npm:4.7.7" @@ -5526,15 +5441,6 @@ __metadata: languageName: node linkType: hard -"json-bigint@npm:^1.0.0": - version: 1.0.0 - resolution: "json-bigint@npm:1.0.0" - dependencies: - bignumber.js: ^9.0.0 - checksum: c67bb93ccb3c291e60eb4b62931403e378906aab113ec1c2a8dd0f9a7f065ad6fd9713d627b732abefae2e244ac9ce1721c7a3142b2979532f12b258634ce6f6 - languageName: node - linkType: hard - "json-parse-better-errors@npm:^1.0.1": version: 1.0.2 resolution: "json-parse-better-errors@npm:1.0.2" @@ -5563,13 +5469,6 @@ __metadata: languageName: node linkType: hard -"json-socket@npm:0.3.0": - version: 0.3.0 - resolution: "json-socket@npm:0.3.0" - checksum: 43e112523547c26a7f54259ac2cc222276d59a619d4d467554d8903f4d56752fd5ed6e23f27b14767dbe55bf0d8eab98640e0c09825fdf329cb8257e38eb6a45 - languageName: node - linkType: hard - "json-stringify-nice@npm:^1.1.2": version: 1.1.3 resolution: "json-stringify-nice@npm:1.1.3" @@ -5660,27 +5559,6 @@ __metadata: languageName: node linkType: hard -"jwa@npm:^2.0.0": - version: 2.0.0 - resolution: "jwa@npm:2.0.0" - dependencies: - buffer-equal-constant-time: 1.0.1 - ecdsa-sig-formatter: 1.0.11 - safe-buffer: ^5.0.1 - checksum: 8f00b71ad5fe94cb55006d0d19202f8f56889109caada2f7eeb63ca81755769ce87f4f48101967f398462e3b8ae4faebfbd5a0269cb755dead5d63c77ba4d2f1 - languageName: node - linkType: hard - -"jws@npm:^4.0.0": - version: 4.0.0 - resolution: "jws@npm:4.0.0" - dependencies: - jwa: ^2.0.0 - safe-buffer: ^5.0.1 - checksum: d68d07aa6d1b8cb35c363a9bd2b48f15064d342a5d9dc18a250dbbce8dc06bd7e4792516c50baa16b8d14f61167c19e851fd7f66b59ecc68b7f6a013759765f7 - languageName: node - linkType: hard - "kind-of@npm:^6.0.3": version: 6.0.3 resolution: "kind-of@npm:6.0.3" @@ -6056,6 +5934,13 @@ __metadata: languageName: node linkType: hard +"long@npm:^5.0.0": + version: 5.2.1 + resolution: "long@npm:5.2.1" + checksum: 9264da12d1b7df67e5aa6da4498144293caf1ad12e7f092efe4e9a2d32c53f0bbf7334f7cef997080a2a3af061142558ab366efa71698d98b1cdb883477445a7 + languageName: node + linkType: hard + "lru-cache@npm:^6.0.0": version: 6.0.0 resolution: "lru-cache@npm:6.0.0" @@ -6589,7 +6474,7 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:^2.3.0, node-fetch@npm:^2.6.1": +"node-fetch@npm:^2.6.1": version: 2.6.7 resolution: "node-fetch@npm:2.6.7" dependencies: @@ -6603,13 +6488,6 @@ __metadata: languageName: node linkType: hard -"node-forge@npm:^0.10.0": - version: 0.10.0 - resolution: "node-forge@npm:0.10.0" - checksum: 5aa6dc9922e424a20ef101d2f517418e2bc9cfc0255dd22e0701c0fad1568445f510ee67f6f3fcdf085812c4ca1b847b8ba45683b34776828e41f5c1794e42e1 - languageName: node - linkType: hard - "node-gyp@npm:^7.1.0, node-gyp@npm:^7.1.2": version: 7.1.2 resolution: "node-gyp@npm:7.1.2" @@ -7168,10 +7046,10 @@ __metadata: languageName: node linkType: hard -"object-hash@npm:2.2.0": - version: 2.2.0 - resolution: "object-hash@npm:2.2.0" - checksum: 55ba841e3adce9c4f1b9b46b41983eda40f854e0d01af2802d3ae18a7085a17168d6b81731d43fdf1d6bcbb3c9f9c56d22c8fea992203ad90a38d7d919bc28f1 +"object-hash@npm:3.0.0": + version: 3.0.0 + resolution: "object-hash@npm:3.0.0" + checksum: 80b4904bb3857c52cc1bfd0b52c0352532ca12ed3b8a6ff06a90cd209dfda1b95cee059a7625eb9da29537027f68ac4619363491eedb2f5d3dddbba97494fd6c languageName: node linkType: hard @@ -7695,7 +7573,7 @@ __metadata: languageName: node linkType: hard -"protobufjs@npm:^6.8.6, protobufjs@npm:^6.8.8": +"protobufjs@npm:^6.8.8": version: 6.10.2 resolution: "protobufjs@npm:6.10.2" dependencies: @@ -7719,6 +7597,26 @@ __metadata: languageName: node linkType: hard +"protobufjs@npm:^7.0.0": + version: 7.1.2 + resolution: "protobufjs@npm:7.1.2" + dependencies: + "@protobufjs/aspromise": ^1.1.2 + "@protobufjs/base64": ^1.1.2 + "@protobufjs/codegen": ^2.0.4 + "@protobufjs/eventemitter": ^1.1.0 + "@protobufjs/fetch": ^1.1.0 + "@protobufjs/float": ^1.0.2 + "@protobufjs/inquire": ^1.1.0 + "@protobufjs/path": ^1.1.2 + "@protobufjs/pool": ^1.1.0 + "@protobufjs/utf8": ^1.1.0 + "@types/node": ">=13.7.0" + long: ^5.0.0 + checksum: ae41669b1b0372fb1d49f506f2d1f2b0fb3dc3cece85987b17bcb544e4cef7c8d27f480486cdec324146ad0a5d22a327166a7ea864a9b3e49cc3c92a5d3f6500 + languageName: node + linkType: hard + "psl@npm:^1.1.28": version: 1.8.0 resolution: "psl@npm:1.8.0" @@ -8212,7 +8110,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^6.0.0, semver@npm:^6.2.0, semver@npm:^6.3.0": +"semver@npm:^6.0.0, semver@npm:^6.3.0": version: 6.3.0 resolution: "semver@npm:6.3.0" bin: @@ -8947,8 +8845,8 @@ __metadata: version: 0.0.0-use.local resolution: "ts-proto@workspace:." dependencies: - "@grpc/grpc-js": ^1.2.12 - "@grpc/proto-loader": ^0.5.6 + "@grpc/grpc-js": ^1.3.0 + "@grpc/proto-loader": ^0.6.0 "@improbable-eng/grpc-web": ^0.14.0 "@improbable-eng/grpc-web-node-http-transport": ^0.14.0 "@nestjs/common": ^8.2.2 @@ -8988,10 +8886,10 @@ __metadata: languageName: unknown linkType: soft -"tslib@npm:2.3.1": - version: 2.3.1 - resolution: "tslib@npm:2.3.1" - checksum: de17a98d4614481f7fcb5cd53ffc1aaf8654313be0291e1bfaee4b4bb31a20494b7d218ff2e15017883e8ea9626599b3b0e0229c18383ba9dce89da2adf15cb9 +"tslib@npm:2.4.0": + version: 2.4.0 + resolution: "tslib@npm:2.4.0" + checksum: 8c4aa6a3c5a754bf76aefc38026134180c053b7bd2f81338cb5e5ebf96fefa0f417bff221592bf801077f5bf990562f6264fecbc42cd3309b33872cb6fc3b113 languageName: node linkType: hard From 301ebb0f92149f5ec6ca43976cb7312e9c0064f8 Mon Sep 17 00:00:00 2001 From: Stephen Haberman Date: Sun, 29 Jan 2023 08:28:59 -0600 Subject: [PATCH 2/9] Add another codegen update. --- integration/nestjs-simple/google/protobuf/struct.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration/nestjs-simple/google/protobuf/struct.ts b/integration/nestjs-simple/google/protobuf/struct.ts index b57ff9d6f..9c0c3314a 100644 --- a/integration/nestjs-simple/google/protobuf/struct.ts +++ b/integration/nestjs-simple/google/protobuf/struct.ts @@ -179,7 +179,7 @@ export const Value = { } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { return Struct.unwrap(message.structValue as any); } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return message.listValue.values.map(Value.unwrap); + return message.listValue; } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } From 13d1ce9153dd40e2313161f4e5302bec4d5a649c Mon Sep 17 00:00:00 2001 From: Gil Date: Mon, 30 Jan 2023 15:24:43 +0200 Subject: [PATCH 3/9] Fix tests --- integration/grpc-js/google/protobuf/struct.ts | 8 ++++++-- integration/nestjs-simple/google/protobuf/struct.ts | 8 ++++++-- integration/nice-grpc/google/protobuf/struct.ts | 8 ++++++-- integration/oneof-unions-snake/google/protobuf/struct.ts | 6 +++++- integration/oneof-unions/google/protobuf/struct.ts | 6 +++++- integration/simple-snake/google/protobuf/struct.ts | 8 ++++++-- integration/simple-string-enums/google/protobuf/struct.ts | 8 ++++++-- integration/struct/google/protobuf/struct.ts | 8 ++++++-- integration/type-registry/google/protobuf/struct.ts | 8 ++++++-- integration/use-map-type/google/protobuf/struct.ts | 8 ++++++-- .../use-numeric-enum-json/google/protobuf/struct.ts | 8 ++++++-- integration/use-readonly-types/google/protobuf/struct.ts | 6 +++++- integration/value/google/protobuf/struct.ts | 8 ++++++-- src/main.ts | 8 ++++++-- 14 files changed, 81 insertions(+), 25 deletions(-) diff --git a/integration/grpc-js/google/protobuf/struct.ts b/integration/grpc-js/google/protobuf/struct.ts index 68e56dd6f..d39a490ef 100644 --- a/integration/grpc-js/google/protobuf/struct.ts +++ b/integration/grpc-js/google/protobuf/struct.ts @@ -394,7 +394,7 @@ export const Value = { } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { return Struct.unwrap(message.structValue as any); } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return message.listValue; + return ListValue.unwrap(message.listValue); } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -465,7 +465,11 @@ export const ListValue = { }, unwrap(message: ListValue): Array { - return message.values; + if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { + return message.values.map((value: any) => Value.unwrap(value) || value); + } else { + return message as any; + } }, }; diff --git a/integration/nestjs-simple/google/protobuf/struct.ts b/integration/nestjs-simple/google/protobuf/struct.ts index 9c0c3314a..581f5c70c 100644 --- a/integration/nestjs-simple/google/protobuf/struct.ts +++ b/integration/nestjs-simple/google/protobuf/struct.ts @@ -179,7 +179,7 @@ export const Value = { } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { return Struct.unwrap(message.structValue as any); } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return message.listValue; + return ListValue.unwrap(message.listValue); } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -201,6 +201,10 @@ export const ListValue = { }, unwrap(message: ListValue): Array { - return message.values; + if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { + return message.values.map((value: any) => Value.unwrap(value) || value); + } else { + return message as any; + } }, }; diff --git a/integration/nice-grpc/google/protobuf/struct.ts b/integration/nice-grpc/google/protobuf/struct.ts index ca416404c..bcf042992 100644 --- a/integration/nice-grpc/google/protobuf/struct.ts +++ b/integration/nice-grpc/google/protobuf/struct.ts @@ -394,7 +394,7 @@ export const Value = { } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { return Struct.unwrap(message.structValue as any); } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return message.listValue; + return ListValue.unwrap(message.listValue); } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -465,7 +465,11 @@ export const ListValue = { }, unwrap(message: ListValue): Array { - return message.values; + if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { + return message.values.map((value: any) => Value.unwrap(value) || value); + } else { + return message as any; + } }, }; diff --git a/integration/oneof-unions-snake/google/protobuf/struct.ts b/integration/oneof-unions-snake/google/protobuf/struct.ts index 8ba75d535..633295700 100644 --- a/integration/oneof-unions-snake/google/protobuf/struct.ts +++ b/integration/oneof-unions-snake/google/protobuf/struct.ts @@ -484,7 +484,11 @@ export const ListValue = { }, unwrap(message: ListValue): Array { - return message.values; + if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { + return message.values.map((value: any) => Value.unwrap(value) || value); + } else { + return message as any; + } }, }; diff --git a/integration/oneof-unions/google/protobuf/struct.ts b/integration/oneof-unions/google/protobuf/struct.ts index 777b2ccf9..71748ec83 100644 --- a/integration/oneof-unions/google/protobuf/struct.ts +++ b/integration/oneof-unions/google/protobuf/struct.ts @@ -475,7 +475,11 @@ export const ListValue = { }, unwrap(message: ListValue): Array { - return message.values; + if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { + return message.values.map((value: any) => Value.unwrap(value) || value); + } else { + return message as any; + } }, }; diff --git a/integration/simple-snake/google/protobuf/struct.ts b/integration/simple-snake/google/protobuf/struct.ts index 9b4932e8d..f25f91190 100644 --- a/integration/simple-snake/google/protobuf/struct.ts +++ b/integration/simple-snake/google/protobuf/struct.ts @@ -394,7 +394,7 @@ export const Value = { } else if (message?.hasOwnProperty("struct_value") && message?.struct_value !== undefined) { return Struct.unwrap(message.struct_value as any); } else if (message?.hasOwnProperty("list_value") && message?.list_value !== undefined) { - return message.list_value; + return ListValue.unwrap(message.list_value); } else if (message?.hasOwnProperty("null_value") && message?.null_value !== undefined) { return null; } @@ -465,7 +465,11 @@ export const ListValue = { }, unwrap(message: ListValue): Array { - return message.values; + if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { + return message.values.map((value: any) => Value.unwrap(value) || value); + } else { + return message as any; + } }, }; diff --git a/integration/simple-string-enums/google/protobuf/struct.ts b/integration/simple-string-enums/google/protobuf/struct.ts index 46084f1bf..2a96a6f7e 100644 --- a/integration/simple-string-enums/google/protobuf/struct.ts +++ b/integration/simple-string-enums/google/protobuf/struct.ts @@ -404,7 +404,7 @@ export const Value = { } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { return Struct.unwrap(message.structValue as any); } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return message.listValue; + return ListValue.unwrap(message.listValue); } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -475,7 +475,11 @@ export const ListValue = { }, unwrap(message: ListValue): Array { - return message.values; + if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { + return message.values.map((value: any) => Value.unwrap(value) || value); + } else { + return message as any; + } }, }; diff --git a/integration/struct/google/protobuf/struct.ts b/integration/struct/google/protobuf/struct.ts index 68e56dd6f..d39a490ef 100644 --- a/integration/struct/google/protobuf/struct.ts +++ b/integration/struct/google/protobuf/struct.ts @@ -394,7 +394,7 @@ export const Value = { } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { return Struct.unwrap(message.structValue as any); } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return message.listValue; + return ListValue.unwrap(message.listValue); } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -465,7 +465,11 @@ export const ListValue = { }, unwrap(message: ListValue): Array { - return message.values; + if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { + return message.values.map((value: any) => Value.unwrap(value) || value); + } else { + return message as any; + } }, }; diff --git a/integration/type-registry/google/protobuf/struct.ts b/integration/type-registry/google/protobuf/struct.ts index 6c6703e07..1cb812108 100644 --- a/integration/type-registry/google/protobuf/struct.ts +++ b/integration/type-registry/google/protobuf/struct.ts @@ -419,7 +419,7 @@ export const Value = { } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { return Struct.unwrap(message.structValue as any); } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return message.listValue; + return ListValue.unwrap(message.listValue); } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -494,7 +494,11 @@ export const ListValue = { }, unwrap(message: ListValue): Array { - return message.values; + if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { + return message.values.map((value: any) => Value.unwrap(value) || value); + } else { + return message as any; + } }, }; diff --git a/integration/use-map-type/google/protobuf/struct.ts b/integration/use-map-type/google/protobuf/struct.ts index e552c6ef7..f135866ce 100644 --- a/integration/use-map-type/google/protobuf/struct.ts +++ b/integration/use-map-type/google/protobuf/struct.ts @@ -391,7 +391,7 @@ export const Value = { } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { return Struct.unwrap(message.structValue as any); } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return message.listValue; + return ListValue.unwrap(message.listValue); } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -462,7 +462,11 @@ export const ListValue = { }, unwrap(message: ListValue): Array { - return message.values; + if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { + return message.values.map((value: any) => Value.unwrap(value) || value); + } else { + return message as any; + } }, }; diff --git a/integration/use-numeric-enum-json/google/protobuf/struct.ts b/integration/use-numeric-enum-json/google/protobuf/struct.ts index 56d3e8d96..74ccf3c01 100644 --- a/integration/use-numeric-enum-json/google/protobuf/struct.ts +++ b/integration/use-numeric-enum-json/google/protobuf/struct.ts @@ -394,7 +394,7 @@ export const Value = { } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { return Struct.unwrap(message.structValue as any); } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return message.listValue; + return ListValue.unwrap(message.listValue); } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -465,7 +465,11 @@ export const ListValue = { }, unwrap(message: ListValue): Array { - return message.values; + if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { + return message.values.map((value: any) => Value.unwrap(value) || value); + } else { + return message as any; + } }, }; diff --git a/integration/use-readonly-types/google/protobuf/struct.ts b/integration/use-readonly-types/google/protobuf/struct.ts index 584ea58f3..8a708bbff 100644 --- a/integration/use-readonly-types/google/protobuf/struct.ts +++ b/integration/use-readonly-types/google/protobuf/struct.ts @@ -475,7 +475,11 @@ export const ListValue = { }, unwrap(message: any): Array { - return message.values; + if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { + return message.values.map((value: any) => Value.unwrap(value) || value); + } else { + return message as any; + } }, }; diff --git a/integration/value/google/protobuf/struct.ts b/integration/value/google/protobuf/struct.ts index 68e56dd6f..d39a490ef 100644 --- a/integration/value/google/protobuf/struct.ts +++ b/integration/value/google/protobuf/struct.ts @@ -394,7 +394,7 @@ export const Value = { } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { return Struct.unwrap(message.structValue as any); } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return message.listValue; + return ListValue.unwrap(message.listValue); } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -465,7 +465,11 @@ export const ListValue = { }, unwrap(message: ListValue): Array { - return message.values; + if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { + return message.values.map((value: any) => Value.unwrap(value) || value); + } else { + return message as any; + } }, }; diff --git a/src/main.ts b/src/main.ts index a0cacb775..f75c0a087 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1975,7 +1975,7 @@ function generateUnwrap(ctx: Context, fullProtoTypeName: string, fieldNames: Str } else if (message?.hasOwnProperty('${fieldNames.structValue}') && message?.${fieldNames.structValue} !== undefined) { return Struct.unwrap(message.${fieldNames.structValue} as any); } else if (message?.hasOwnProperty('${fieldNames.listValue}') && message?.${fieldNames.listValue} !== undefined) { - return message.${fieldNames.listValue}; + return ListValue.unwrap(message.${fieldNames.listValue}); } else if (message?.hasOwnProperty('${fieldNames.nullValue}') && message?.${fieldNames.nullValue} !== undefined) { return null; } @@ -1986,7 +1986,11 @@ function generateUnwrap(ctx: Context, fullProtoTypeName: string, fieldNames: Str if (isListValueTypeName(fullProtoTypeName)) { chunks.push(code`unwrap(message: ${ctx.options.useReadonlyTypes ? "any" : "ListValue"}): Array { - return message.values; + if (message?.hasOwnProperty('values') && Array.isArray(message.values)) { + return message.values.map((value: any) => Value.unwrap(value) || value); + } else { + return message as any; + } }`); } From 0253e482b8ceed0f562fa1673c4696adf4f0dd79 Mon Sep 17 00:00:00 2001 From: Stephen Haberman Date: Mon, 30 Jan 2023 15:32:13 -0600 Subject: [PATCH 4/9] Format. --- .../nestjs-simple/nestjs-simple-test.ts | 47 +++++++++++-------- integration/nestjs-simple/sample-service.ts | 19 +++++--- 2 files changed, 39 insertions(+), 27 deletions(-) diff --git a/integration/nestjs-simple/nestjs-simple-test.ts b/integration/nestjs-simple/nestjs-simple-test.ts index 47e07c294..8c988fae8 100644 --- a/integration/nestjs-simple/nestjs-simple-test.ts +++ b/integration/nestjs-simple/nestjs-simple-test.ts @@ -1,18 +1,18 @@ -import { SampleService } from './sample-service'; -import { createApp } from './nestjs-project/main'; -import { INestMicroservice } from '@nestjs/common'; -import { ClientGrpc } from '@nestjs/microservices'; -import { HeroServiceClient, VillainById, Villain, HERO_SERVICE_NAME, HERO_PACKAGE_NAME } from './hero'; -import { Subject } from 'rxjs'; +import { SampleService } from "./sample-service"; +import { createApp } from "./nestjs-project/main"; +import { INestMicroservice } from "@nestjs/common"; +import { ClientGrpc } from "@nestjs/microservices"; +import { HeroServiceClient, VillainById, Villain, HERO_SERVICE_NAME, HERO_PACKAGE_NAME } from "./hero"; +import { Subject } from "rxjs"; -describe('nestjs-simple-test', () => { - it('compiles', () => { +describe("nestjs-simple-test", () => { + it("compiles", () => { const service = new SampleService(); expect(service).not.toBeUndefined(); }); }); -describe('nestjs-simple-test nestjs', () => { +describe("nestjs-simple-test nestjs", () => { let app: INestMicroservice; let client: ClientGrpc; let heroService: HeroServiceClient; @@ -28,30 +28,37 @@ describe('nestjs-simple-test nestjs', () => { await app.close(); }); - it('should get grpc client', async () => { + it("should get grpc client", async () => { expect(client).not.toBeUndefined(); }); - it('should get heroService', async () => { + it("should get heroService", async () => { expect(heroService).not.toBeUndefined(); }); - it('should addOneHero', async () => { - const emptyResponse = await heroService.addOneHero({ id: 3, name: 'Toon', birthDate: undefined, externalData: { some: 'data' } }).toPromise(); + it("should addOneHero", async () => { + const emptyResponse = await heroService + .addOneHero({ id: 3, name: "Toon", birthDate: undefined, externalData: { some: "data" } }) + .toPromise(); expect(emptyResponse).toEqual({}); }); - it('should findOneHero', async () => { + it("should findOneHero", async () => { const hero = await heroService.findOneHero({ id: 1 }).toPromise(); - expect(hero).toEqual({ id: 1, name: 'Stephenh', birthDate: { seconds: 1, nanos: 2 }, externalData: { foo: 'bar', fizz: 1, nested: { isFailing: false, arr: [1,'foo',['bar']] } } }); + expect(hero).toEqual({ + id: 1, + name: "Stephenh", + birthDate: { seconds: 1, nanos: 2 }, + externalData: { foo: "bar", fizz: 1, nested: { isFailing: false, arr: [1, "foo", ["bar"]] } }, + }); }); - it('should findOneVillain', async () => { + it("should findOneVillain", async () => { const villain = await heroService.findOneVillain({ id: 1 }).toPromise(); - expect(villain).toEqual({ id: 1, name: 'John' }); + expect(villain).toEqual({ id: 1, name: "John" }); }); - it('should findManyVillain', (done) => { + it("should findManyVillain", (done) => { const villainIdSubject = new Subject(); const villains: Villain[] = []; @@ -61,8 +68,8 @@ describe('nestjs-simple-test nestjs', () => { }, complete: () => { expect(villains).toEqual([ - { id: 1, name: 'John' }, - { id: 2, name: 'Doe' }, + { id: 1, name: "John" }, + { id: 2, name: "Doe" }, ]); done(); }, diff --git a/integration/nestjs-simple/sample-service.ts b/integration/nestjs-simple/sample-service.ts index b1774713a..f08de8259 100644 --- a/integration/nestjs-simple/sample-service.ts +++ b/integration/nestjs-simple/sample-service.ts @@ -1,22 +1,27 @@ -import { HeroServiceController, HeroById, Hero, Villain, VillainById } from './hero'; -import { Observable, Subject } from 'rxjs'; +import { HeroServiceController, HeroById, Hero, Villain, VillainById } from "./hero"; +import { Observable, Subject } from "rxjs"; export class SampleService implements HeroServiceController { addOneHero(request: Hero): void {} findOneHero(request: HeroById): Promise { - return Promise.resolve({ id: 1, name: 'test', birthDate: undefined, externalData: { foo: 'bar', fizz: 1, nested: { isFailing: false, array: [1, 'foo', ['bar']] } } }); + return Promise.resolve({ + id: 1, + name: "test", + birthDate: undefined, + externalData: { foo: "bar", fizz: 1, nested: { isFailing: false, array: [1, "foo", ["bar"]] } }, + }); } findOneVillain(request: VillainById): Promise { - return Promise.resolve({ id: 1, name: 'test' }); + return Promise.resolve({ id: 1, name: "test" }); } findManyVillain(request: Observable): Observable { const hero$ = new Subject(); const onNext = (villainById: VillainById) => { - hero$.next({ id: 1, name: 'test' }); + hero$.next({ id: 1, name: "test" }); }; const onComplete = () => hero$.complete(); request.subscribe(onNext, null, onComplete); @@ -25,13 +30,13 @@ export class SampleService implements HeroServiceController { } async findManyVillainStreamIn(request: Observable): Promise { - return { id: 1, name: 'test' }; + return { id: 1, name: "test" }; } findManyVillainStreamOut(request: VillainById): Observable { // Kinda making this up const hero$ = new Subject(); - hero$.next({ id: 1, name: 'test' }); + hero$.next({ id: 1, name: "test" }); hero$.complete(); return hero$.asObservable(); } From 9956fed27649ac1228992fe0fb78266e92a36f09 Mon Sep 17 00:00:00 2001 From: Stephen Haberman Date: Mon, 30 Jan 2023 15:55:57 -0600 Subject: [PATCH 5/9] Make const/base output more conditional. --- integration/nestjs-metadata-grpc-js/hero.ts | 24 -------------- .../nestjs-metadata-observables/hero.ts | 24 -------------- .../nestjs-metadata-restparameters/hero.ts | 24 -------------- integration/nestjs-metadata/hero.ts | 24 -------------- integration/nestjs-restparameters/hero.ts | 24 -------------- integration/nestjs-simple-observables/hero.ts | 24 -------------- .../google/protobuf/empty.ts | 6 ---- .../nestjs-simple-restparameters/hero.ts | 6 ---- .../google/protobuf/empty.ts | 6 ---- .../google/protobuf/timestamp.ts | 6 ---- integration/nestjs-simple-usedate/hero.ts | 24 -------------- .../nestjs-simple/google/protobuf/empty.ts | 6 ---- .../nestjs-simple/google/protobuf/struct.ts | 6 ---- .../google/protobuf/timestamp.ts | 6 ---- integration/nestjs-simple/hero.ts | 24 -------------- src/main.ts | 32 +++++++++++++++---- 16 files changed, 25 insertions(+), 241 deletions(-) diff --git a/integration/nestjs-metadata-grpc-js/hero.ts b/integration/nestjs-metadata-grpc-js/hero.ts index 0424fcec7..54483ffd9 100644 --- a/integration/nestjs-metadata-grpc-js/hero.ts +++ b/integration/nestjs-metadata-grpc-js/hero.ts @@ -25,30 +25,6 @@ export interface Villain { export const HERO_PACKAGE_NAME = "hero"; -function createBaseHeroById(): HeroById { - return { id: 0 }; -} - -export const HeroById = {}; - -function createBaseVillainById(): VillainById { - return { id: 0 }; -} - -export const VillainById = {}; - -function createBaseHero(): Hero { - return { id: 0, name: "" }; -} - -export const Hero = {}; - -function createBaseVillain(): Villain { - return { id: 0, name: "" }; -} - -export const Villain = {}; - export interface HeroServiceClient { findOneHero(request: HeroById, metadata?: Metadata): Observable; diff --git a/integration/nestjs-metadata-observables/hero.ts b/integration/nestjs-metadata-observables/hero.ts index 517d27999..197aa85d4 100644 --- a/integration/nestjs-metadata-observables/hero.ts +++ b/integration/nestjs-metadata-observables/hero.ts @@ -25,30 +25,6 @@ export interface Villain { export const HERO_PACKAGE_NAME = "hero"; -function createBaseHeroById(): HeroById { - return { id: 0 }; -} - -export const HeroById = {}; - -function createBaseVillainById(): VillainById { - return { id: 0 }; -} - -export const VillainById = {}; - -function createBaseHero(): Hero { - return { id: 0, name: "" }; -} - -export const Hero = {}; - -function createBaseVillain(): Villain { - return { id: 0, name: "" }; -} - -export const Villain = {}; - export interface HeroServiceClient { findOneHero(request: HeroById, metadata?: Metadata): Observable; diff --git a/integration/nestjs-metadata-restparameters/hero.ts b/integration/nestjs-metadata-restparameters/hero.ts index ac0262b69..6ef287bac 100644 --- a/integration/nestjs-metadata-restparameters/hero.ts +++ b/integration/nestjs-metadata-restparameters/hero.ts @@ -25,30 +25,6 @@ export interface Villain { export const HERO_PACKAGE_NAME = "hero"; -function createBaseHeroById(): HeroById { - return { id: 0 }; -} - -export const HeroById = {}; - -function createBaseVillainById(): VillainById { - return { id: 0 }; -} - -export const VillainById = {}; - -function createBaseHero(): Hero { - return { id: 0, name: "" }; -} - -export const Hero = {}; - -function createBaseVillain(): Villain { - return { id: 0, name: "" }; -} - -export const Villain = {}; - export interface HeroServiceClient { findOneHero(request: HeroById, metadata: Metadata, ...rest: any): Observable; diff --git a/integration/nestjs-metadata/hero.ts b/integration/nestjs-metadata/hero.ts index 0424fcec7..54483ffd9 100644 --- a/integration/nestjs-metadata/hero.ts +++ b/integration/nestjs-metadata/hero.ts @@ -25,30 +25,6 @@ export interface Villain { export const HERO_PACKAGE_NAME = "hero"; -function createBaseHeroById(): HeroById { - return { id: 0 }; -} - -export const HeroById = {}; - -function createBaseVillainById(): VillainById { - return { id: 0 }; -} - -export const VillainById = {}; - -function createBaseHero(): Hero { - return { id: 0, name: "" }; -} - -export const Hero = {}; - -function createBaseVillain(): Villain { - return { id: 0, name: "" }; -} - -export const Villain = {}; - export interface HeroServiceClient { findOneHero(request: HeroById, metadata?: Metadata): Observable; diff --git a/integration/nestjs-restparameters/hero.ts b/integration/nestjs-restparameters/hero.ts index c6237a7db..abf56feb9 100644 --- a/integration/nestjs-restparameters/hero.ts +++ b/integration/nestjs-restparameters/hero.ts @@ -24,30 +24,6 @@ export interface Villain { export const HERO_PACKAGE_NAME = "hero"; -function createBaseHeroById(): HeroById { - return { id: 0 }; -} - -export const HeroById = {}; - -function createBaseVillainById(): VillainById { - return { id: 0 }; -} - -export const VillainById = {}; - -function createBaseHero(): Hero { - return { id: 0, name: "" }; -} - -export const Hero = {}; - -function createBaseVillain(): Villain { - return { id: 0, name: "" }; -} - -export const Villain = {}; - export interface HeroServiceClient { findOneHero(request: HeroById, ...rest: any): Observable; diff --git a/integration/nestjs-simple-observables/hero.ts b/integration/nestjs-simple-observables/hero.ts index 463c98794..7c884baf4 100644 --- a/integration/nestjs-simple-observables/hero.ts +++ b/integration/nestjs-simple-observables/hero.ts @@ -24,30 +24,6 @@ export interface Villain { export const HERO_PACKAGE_NAME = "hero"; -function createBaseHeroById(): HeroById { - return { id: 0 }; -} - -export const HeroById = {}; - -function createBaseVillainById(): VillainById { - return { id: 0 }; -} - -export const VillainById = {}; - -function createBaseHero(): Hero { - return { id: 0, name: "" }; -} - -export const Hero = {}; - -function createBaseVillain(): Villain { - return { id: 0, name: "" }; -} - -export const Villain = {}; - export interface HeroServiceClient { findOneHero(request: HeroById): Observable; diff --git a/integration/nestjs-simple-restparameters/google/protobuf/empty.ts b/integration/nestjs-simple-restparameters/google/protobuf/empty.ts index c8dc970f5..642a965dc 100644 --- a/integration/nestjs-simple-restparameters/google/protobuf/empty.ts +++ b/integration/nestjs-simple-restparameters/google/protobuf/empty.ts @@ -17,9 +17,3 @@ export interface Empty { } export const GOOGLE_PROTOBUF_PACKAGE_NAME = "google.protobuf"; - -function createBaseEmpty(): Empty { - return {}; -} - -export const Empty = {}; diff --git a/integration/nestjs-simple-restparameters/hero.ts b/integration/nestjs-simple-restparameters/hero.ts index 178e460c8..b7bb522a5 100644 --- a/integration/nestjs-simple-restparameters/hero.ts +++ b/integration/nestjs-simple-restparameters/hero.ts @@ -12,12 +12,6 @@ export interface User { export const HERO_PACKAGE_NAME = "hero"; -function createBaseUser(): User { - return { id: 0, name: "" }; -} - -export const User = {}; - export interface HeroServiceClient { findCurrentUser(request: Empty, ...rest: any): Observable; } diff --git a/integration/nestjs-simple-usedate/google/protobuf/empty.ts b/integration/nestjs-simple-usedate/google/protobuf/empty.ts index c8dc970f5..642a965dc 100644 --- a/integration/nestjs-simple-usedate/google/protobuf/empty.ts +++ b/integration/nestjs-simple-usedate/google/protobuf/empty.ts @@ -17,9 +17,3 @@ export interface Empty { } export const GOOGLE_PROTOBUF_PACKAGE_NAME = "google.protobuf"; - -function createBaseEmpty(): Empty { - return {}; -} - -export const Empty = {}; diff --git a/integration/nestjs-simple-usedate/google/protobuf/timestamp.ts b/integration/nestjs-simple-usedate/google/protobuf/timestamp.ts index 48d8e3e7e..229cba608 100644 --- a/integration/nestjs-simple-usedate/google/protobuf/timestamp.ts +++ b/integration/nestjs-simple-usedate/google/protobuf/timestamp.ts @@ -110,9 +110,3 @@ export interface Timestamp { } export const GOOGLE_PROTOBUF_PACKAGE_NAME = "google.protobuf"; - -function createBaseTimestamp(): Timestamp { - return { seconds: 0, nanos: 0 }; -} - -export const Timestamp = {}; diff --git a/integration/nestjs-simple-usedate/hero.ts b/integration/nestjs-simple-usedate/hero.ts index 17044f590..cf606e35d 100644 --- a/integration/nestjs-simple-usedate/hero.ts +++ b/integration/nestjs-simple-usedate/hero.ts @@ -36,30 +36,6 @@ wrappers[".google.protobuf.Timestamp"] = { }, } as any; -function createBaseHeroById(): HeroById { - return { id: 0 }; -} - -export const HeroById = {}; - -function createBaseVillainById(): VillainById { - return { id: 0 }; -} - -export const VillainById = {}; - -function createBaseHero(): Hero { - return { id: 0, name: "", birthDate: undefined }; -} - -export const Hero = {}; - -function createBaseVillain(): Villain { - return { id: 0, name: "" }; -} - -export const Villain = {}; - export interface HeroServiceClient { addOneHero(request: Hero): Observable; diff --git a/integration/nestjs-simple/google/protobuf/empty.ts b/integration/nestjs-simple/google/protobuf/empty.ts index c8dc970f5..642a965dc 100644 --- a/integration/nestjs-simple/google/protobuf/empty.ts +++ b/integration/nestjs-simple/google/protobuf/empty.ts @@ -17,9 +17,3 @@ export interface Empty { } export const GOOGLE_PROTOBUF_PACKAGE_NAME = "google.protobuf"; - -function createBaseEmpty(): Empty { - return {}; -} - -export const Empty = {}; diff --git a/integration/nestjs-simple/google/protobuf/struct.ts b/integration/nestjs-simple/google/protobuf/struct.ts index 581f5c70c..7035644da 100644 --- a/integration/nestjs-simple/google/protobuf/struct.ts +++ b/integration/nestjs-simple/google/protobuf/struct.ts @@ -136,12 +136,6 @@ export const Struct = { }, }; -function createBaseStruct_FieldsEntry(): Struct_FieldsEntry { - return { key: "", value: undefined }; -} - -export const Struct_FieldsEntry = {}; - function createBaseValue(): Value { return {}; } diff --git a/integration/nestjs-simple/google/protobuf/timestamp.ts b/integration/nestjs-simple/google/protobuf/timestamp.ts index 48d8e3e7e..229cba608 100644 --- a/integration/nestjs-simple/google/protobuf/timestamp.ts +++ b/integration/nestjs-simple/google/protobuf/timestamp.ts @@ -110,9 +110,3 @@ export interface Timestamp { } export const GOOGLE_PROTOBUF_PACKAGE_NAME = "google.protobuf"; - -function createBaseTimestamp(): Timestamp { - return { seconds: 0, nanos: 0 }; -} - -export const Timestamp = {}; diff --git a/integration/nestjs-simple/hero.ts b/integration/nestjs-simple/hero.ts index 78bfd92cc..269102aba 100644 --- a/integration/nestjs-simple/hero.ts +++ b/integration/nestjs-simple/hero.ts @@ -58,30 +58,6 @@ wrappers[".google.protobuf.Struct"] = { }, } as any; -function createBaseHeroById(): HeroById { - return { id: 0 }; -} - -export const HeroById = {}; - -function createBaseVillainById(): VillainById { - return { id: 0 }; -} - -export const VillainById = {}; - -function createBaseHero(): Hero { - return { id: 0, name: "", birthDate: undefined, externalData: undefined }; -} - -export const Hero = {}; - -function createBaseVillain(): Villain { - return { id: 0, name: "" }; -} - -export const Villain = {}; - export interface HeroServiceClient { addOneHero(request: Hero): Observable; diff --git a/src/main.ts b/src/main.ts index f75c0a087..495eba3c2 100644 --- a/src/main.ts +++ b/src/main.ts @@ -172,6 +172,9 @@ export function generateFile(ctx: Context, fileDesc: FileDescriptorProto): [stri } } + // We add `nestJs` here because enough though it doesn't use our encode/decode methods + // for most/vanilla messages, we do generate static wrap/unwrap methods for the special + // Struct/Value/wrapper types and use the `wrappers[...]` to have NestJS know about them. if (options.outputEncodeMethods || options.outputJsonMethods || options.outputTypeRegistry || options.nestJs) { // then add the encoder/decoder/base instance visit( @@ -179,8 +182,12 @@ export function generateFile(ctx: Context, fileDesc: FileDescriptorProto): [stri sourceInfo, (fullName, message, _sInfo, fullProtoTypeName) => { const fullTypeName = maybePrefixPackage(fileDesc, fullProtoTypeName); + const outputWrapAndUnwrap = isWrapperType(fullTypeName); - chunks.push(generateBaseInstanceFactory(ctx, fullName, message, fullTypeName)); + // Only decode, fromPartial, and wrap use the createBase method + if (options.outputEncodeMethods || options.outputPartialMethods || outputWrapAndUnwrap) { + chunks.push(generateBaseInstanceFactory(ctx, fullName, message, fullTypeName)); + } const staticMembers: Code[] = []; @@ -215,15 +222,16 @@ export function generateFile(ctx: Context, fileDesc: FileDescriptorProto): [stri staticMembers.push(...generateWrap(ctx, fullTypeName, structFieldNames)); staticMembers.push(...generateUnwrap(ctx, fullTypeName, structFieldNames)); - chunks.push(code` - export const ${def(fullName)} = { - ${joinCode(staticMembers, { on: ",\n\n" })} - }; - `); + if (staticMembers.length > 0) { + chunks.push(code` + export const ${def(fullName)} = { + ${joinCode(staticMembers, { on: ",\n\n" })} + }; + `); + } if (options.outputTypeRegistry) { const messageTypeRegistry = impFile(options, "messageTypeRegistry@./typeRegistry"); - chunks.push(code` ${messageTypeRegistry}.set(${fullName}.$type, ${fullName}); `); @@ -1826,6 +1834,16 @@ type StructFieldNames = { listValue: string; }; +/** Whether we need to generate `.wrap` and `.unwrap` methods for the given type. */ +function isWrapperType(fullProtoTypeName: string): boolean { + return ( + isStructTypeName(fullProtoTypeName) || + isAnyValueTypeName(fullProtoTypeName) || + isListValueTypeName(fullProtoTypeName) || + isFieldMaskTypeName(fullProtoTypeName) + ); +} + function generateWrap(ctx: Context, fullProtoTypeName: string, fieldNames: StructFieldNames): Code[] { const chunks: Code[] = []; if (isStructTypeName(fullProtoTypeName)) { From 6c76cf66b5f4235147c35a852a83e70ba09d1e26 Mon Sep 17 00:00:00 2001 From: Stephen Haberman Date: Mon, 30 Jan 2023 16:12:49 -0600 Subject: [PATCH 6/9] Use isStructType. --- src/main.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main.ts b/src/main.ts index 495eba3c2..bf8d08e95 100644 --- a/src/main.ts +++ b/src/main.ts @@ -155,11 +155,7 @@ export function generateFile(ctx: Context, fileDesc: FileDescriptorProto): [stri chunks.push(makeProtobufTimestampWrapper()); } - if ( - fileDesc.messageType.find((message) => - message.field.find((field) => field.typeName === ".google.protobuf.Struct") - ) - ) { + if (fileDesc.messageType.find((message) => message.field.find(isStructType))) { const structFieldNames = { nullValue: maybeSnakeToCamel("null_value", ctx.options), numberValue: maybeSnakeToCamel("number_value", ctx.options), From 6aa03ccf0e8930c047123b12e875d7dbb1e6c90a Mon Sep 17 00:00:00 2001 From: Stephen Haberman Date: Mon, 30 Jan 2023 17:09:59 -0600 Subject: [PATCH 7/9] Consistently wrap & unwrap. --- .../fieldmask/google/protobuf/field_mask.ts | 2 - integration/grpc-js/google/protobuf/struct.ts | 34 ++- .../nestjs-simple/google/protobuf/struct.ts | 64 ++---- integration/nestjs-simple/hero.ts | 30 +-- .../nestjs-project/hero.controller.ts | 27 ++- .../nice-grpc/google/protobuf/struct.ts | 34 ++- .../google/protobuf/struct.ts | 67 +++--- .../oneof-unions/google/protobuf/struct.ts | 67 +++--- .../simple-snake/google/protobuf/struct.ts | 34 ++- .../google/protobuf/struct.ts | 34 ++- integration/struct/google/protobuf/struct.ts | 34 ++- .../type-registry/google/protobuf/struct.ts | 34 ++- .../use-map-type/google/protobuf/struct.ts | 25 +-- .../google/protobuf/struct.ts | 34 ++- .../google/protobuf/field_mask.ts | 2 - .../google/protobuf/struct.ts | 67 +++--- integration/value/google/protobuf/struct.ts | 34 ++- src/main.ts | 211 +++++------------- 18 files changed, 296 insertions(+), 538 deletions(-) diff --git a/integration/fieldmask/google/protobuf/field_mask.ts b/integration/fieldmask/google/protobuf/field_mask.ts index 9a6b703f5..37ec28306 100644 --- a/integration/fieldmask/google/protobuf/field_mask.ts +++ b/integration/fieldmask/google/protobuf/field_mask.ts @@ -264,9 +264,7 @@ export const FieldMask = { wrap(paths: string[]): FieldMask { const result = createBaseFieldMask(); - result.paths = paths; - return result; }, diff --git a/integration/grpc-js/google/protobuf/struct.ts b/integration/grpc-js/google/protobuf/struct.ts index d39a490ef..999445bd5 100644 --- a/integration/grpc-js/google/protobuf/struct.ts +++ b/integration/grpc-js/google/protobuf/struct.ts @@ -179,21 +179,19 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = object[key]; + struct.fields[key] = Value.wrap(object[key]); }); } return struct; }, unwrap(message: Struct): { [key: string]: any } { - if (!message.fields) { - return message; - } const object: { [key: string]: any } = {}; - Object.keys(message.fields).forEach((key) => { - const unwrappedValue = Value.unwrap(message.fields[key]); - object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; - }); + if (message.fields) { + Object.keys(message.fields).forEach((key) => { + object[key] = Value.unwrap(message.fields[key]); + }); + } return object; }, }; @@ -363,8 +361,7 @@ export const Value = { }, wrap(value: any): Value { - const result = createBaseValue(); - + const result = {} as any; if (value === null) { result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -374,18 +371,17 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = value; + result.listValue = ListValue.wrap(value); } else if (typeof value === "object") { - result.structValue = value; + result.structValue = Struct.wrap(value); } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } - return result; }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { + if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { return message.stringValue; } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { return message.numberValue; @@ -456,17 +452,13 @@ export const ListValue = { return message; }, - wrap(value: Array | undefined): ListValue { - const result = createBaseListValue(); - - result.values = value ?? []; - - return result; + wrap(array: Array | undefined): ListValue { + return { values: (array ?? []).map(Value.wrap) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map((value: any) => Value.unwrap(value) || value); + return message.values.map(Value.unwrap); } else { return message as any; } diff --git a/integration/nestjs-simple/google/protobuf/struct.ts b/integration/nestjs-simple/google/protobuf/struct.ts index 7035644da..44aaaf4dc 100644 --- a/integration/nestjs-simple/google/protobuf/struct.ts +++ b/integration/nestjs-simple/google/protobuf/struct.ts @@ -80,34 +80,6 @@ export interface ListValue { export const GOOGLE_PROTOBUF_PACKAGE_NAME = "google.protobuf"; -const wrapStruct = (value: any, nested = false): any => { - const valueType = typeof value; - const primitiveValueTypes = { number: "numberValue", string: "stringValue", boolean: "boolValue" }; - if (Object.keys(primitiveValueTypes).includes(valueType)) { - return Value.wrap(value); - } - if (Array.isArray(value)) { - return { listValue: { values: value.map((item) => wrapStruct(item)) } }; - } - if (valueType === "object") { - const res = nested ? { structValue: { fields: {} as any } } : { fields: {} as any }; - Object.keys(value).forEach((field) => { - if (nested) { - res.structValue!.fields[field] = wrapStruct(value[field], true); - } else { - res.fields![field] = wrapStruct(value[field], true); - } - }); - return res; - } -}; -wrappers[".google.protobuf.Struct"] = { - fromObject: wrapStruct, - toObject(message: Struct) { - return message ? Struct.unwrap(message) : message; - }, -} as any; - function createBaseStruct(): Struct { return { fields: {} }; } @@ -117,21 +89,19 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = object[key]; + struct.fields[key] = Value.wrap(object[key]); }); } return struct; }, unwrap(message: Struct): { [key: string]: any } { - if (!message.fields) { - return message; - } const object: { [key: string]: any } = {}; - Object.keys(message.fields).forEach((key) => { - const unwrappedValue = Value.unwrap(message.fields[key]); - object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; - }); + if (message.fields) { + Object.keys(message.fields).forEach((key) => { + object[key] = Value.unwrap(message.fields[key]); + }); + } return object; }, }; @@ -142,8 +112,7 @@ function createBaseValue(): Value { export const Value = { wrap(value: any): Value { - const result = createBaseValue(); - + const result = {} as any; if (value === null) { result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -153,18 +122,17 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = value; + result.listValue = ListValue.wrap(value); } else if (typeof value === "object") { - result.structValue = value; + result.structValue = Struct.wrap(value); } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } - return result; }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { + if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { return message.stringValue; } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { return message.numberValue; @@ -186,19 +154,17 @@ function createBaseListValue(): ListValue { } export const ListValue = { - wrap(value: Array | undefined): ListValue { - const result = createBaseListValue(); - - result.values = value ?? []; - - return result; + wrap(array: Array | undefined): ListValue { + return { values: (array ?? []).map(Value.wrap) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map((value: any) => Value.unwrap(value) || value); + return message.values.map(Value.unwrap); } else { return message as any; } }, }; + +wrappers[".google.protobuf.Struct"] = { fromObject: Struct.wrap, toObject: Struct.unwrap } as any; diff --git a/integration/nestjs-simple/hero.ts b/integration/nestjs-simple/hero.ts index 269102aba..a6d0e0788 100644 --- a/integration/nestjs-simple/hero.ts +++ b/integration/nestjs-simple/hero.ts @@ -3,7 +3,7 @@ import { GrpcMethod, GrpcStreamMethod } from "@nestjs/microservices"; import { wrappers } from "protobufjs"; import { Observable } from "rxjs"; import { Empty } from "./google/protobuf/empty"; -import { Struct, Value } from "./google/protobuf/struct"; +import { Struct } from "./google/protobuf/struct"; import { Timestamp } from "./google/protobuf/timestamp"; export const protobufPackage = "hero"; @@ -30,33 +30,7 @@ export interface Villain { export const HERO_PACKAGE_NAME = "hero"; -const wrapStruct = (value: any, nested = false): any => { - const valueType = typeof value; - const primitiveValueTypes = { number: "numberValue", string: "stringValue", boolean: "boolValue" }; - if (Object.keys(primitiveValueTypes).includes(valueType)) { - return Value.wrap(value); - } - if (Array.isArray(value)) { - return { listValue: { values: value.map((item) => wrapStruct(item)) } }; - } - if (valueType === "object") { - const res = nested ? { structValue: { fields: {} as any } } : { fields: {} as any }; - Object.keys(value).forEach((field) => { - if (nested) { - res.structValue!.fields[field] = wrapStruct(value[field], true); - } else { - res.fields![field] = wrapStruct(value[field], true); - } - }); - return res; - } -}; -wrappers[".google.protobuf.Struct"] = { - fromObject: wrapStruct, - toObject(message: Struct) { - return message ? Struct.unwrap(message) : message; - }, -} as any; +wrappers[".google.protobuf.Struct"] = { fromObject: Struct.wrap, toObject: Struct.unwrap } as any; export interface HeroServiceClient { addOneHero(request: Hero): Observable; diff --git a/integration/nestjs-simple/nestjs-project/hero.controller.ts b/integration/nestjs-simple/nestjs-project/hero.controller.ts index 69fafb9a8..bd026fc8b 100644 --- a/integration/nestjs-simple/nestjs-project/hero.controller.ts +++ b/integration/nestjs-simple/nestjs-project/hero.controller.ts @@ -1,16 +1,29 @@ -import { Controller } from '@nestjs/common'; -import { Observable, Subject } from 'rxjs'; -import { Hero, HeroById, HeroServiceController, HeroServiceControllerMethods, Villain, VillainById } from '../hero'; +import { Controller } from "@nestjs/common"; +import { Observable, Subject } from "rxjs"; +import { Hero, HeroById, HeroServiceController, HeroServiceControllerMethods, Villain, VillainById } from "../hero"; -@Controller('hero') +@Controller("hero") @HeroServiceControllerMethods() export class HeroController implements HeroServiceController { private readonly heroes: Hero[] = [ - { id: 1, name: 'Stephenh', birthDate: { seconds: 1, nanos: 2 }, externalData: { foo: 'bar', fizz: 1, nested: { isFailing: false, arr: [1,'foo',['bar']] } } }, - { id: 2, name: 'Iangregsondev', birthDate: { seconds: 1, nanos: 3 }, externalData: { bar: 10, baz: 'foo', isPassing: true } }, + { + id: 1, + name: "Stephenh", + birthDate: { seconds: 1, nanos: 2 }, + externalData: { foo: "bar", fizz: 1, nested: { isFailing: false, arr: [1, "foo", ["bar"]] } }, + }, + { + id: 2, + name: "Iangregsondev", + birthDate: { seconds: 1, nanos: 3 }, + externalData: { bar: 10, baz: "foo", isPassing: true }, + }, ]; - private readonly villains: Villain[] = [{ id: 1, name: 'John' }, { id: 2, name: 'Doe' }]; + private readonly villains: Villain[] = [ + { id: 1, name: "John" }, + { id: 2, name: "Doe" }, + ]; addOneHero(request: Hero) { this.heroes.push(request); diff --git a/integration/nice-grpc/google/protobuf/struct.ts b/integration/nice-grpc/google/protobuf/struct.ts index bcf042992..ff02b8b85 100644 --- a/integration/nice-grpc/google/protobuf/struct.ts +++ b/integration/nice-grpc/google/protobuf/struct.ts @@ -179,21 +179,19 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = object[key]; + struct.fields[key] = Value.wrap(object[key]); }); } return struct; }, unwrap(message: Struct): { [key: string]: any } { - if (!message.fields) { - return message; - } const object: { [key: string]: any } = {}; - Object.keys(message.fields).forEach((key) => { - const unwrappedValue = Value.unwrap(message.fields[key]); - object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; - }); + if (message.fields) { + Object.keys(message.fields).forEach((key) => { + object[key] = Value.unwrap(message.fields[key]); + }); + } return object; }, }; @@ -363,8 +361,7 @@ export const Value = { }, wrap(value: any): Value { - const result = createBaseValue(); - + const result = {} as any; if (value === null) { result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -374,18 +371,17 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = value; + result.listValue = ListValue.wrap(value); } else if (typeof value === "object") { - result.structValue = value; + result.structValue = Struct.wrap(value); } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } - return result; }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { + if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { return message.stringValue; } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { return message.numberValue; @@ -456,17 +452,13 @@ export const ListValue = { return message; }, - wrap(value: Array | undefined): ListValue { - const result = createBaseListValue(); - - result.values = value ?? []; - - return result; + wrap(array: Array | undefined): ListValue { + return { values: (array ?? []).map(Value.wrap) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map((value: any) => Value.unwrap(value) || value); + return message.values.map(Value.unwrap); } else { return message as any; } diff --git a/integration/oneof-unions-snake/google/protobuf/struct.ts b/integration/oneof-unions-snake/google/protobuf/struct.ts index 633295700..cb947bd3f 100644 --- a/integration/oneof-unions-snake/google/protobuf/struct.ts +++ b/integration/oneof-unions-snake/google/protobuf/struct.ts @@ -164,21 +164,19 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = object[key]; + struct.fields[key] = Value.wrap(object[key]); }); } return struct; }, unwrap(message: Struct): { [key: string]: any } { - if (!message.fields) { - return message; - } const object: { [key: string]: any } = {}; - Object.keys(message.fields).forEach((key) => { - const unwrappedValue = Value.unwrap(message.fields[key]); - object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; - }); + if (message.fields) { + Object.keys(message.fields).forEach((key) => { + object[key] = Value.unwrap(message.fields[key]); + }); + } return object; }, }; @@ -381,43 +379,40 @@ export const Value = { }, wrap(value: any): Value { - const result = createBaseValue(); - + const result = {} as any; if (value === null) { - result.kind = { $case: "null_value", null_value: NullValue.NULL_VALUE }; + result.null_value = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { - result.kind = { $case: "bool_value", bool_value: value }; + result.bool_value = value; } else if (typeof value === "number") { - result.kind = { $case: "number_value", number_value: value }; + result.number_value = value; } else if (typeof value === "string") { - result.kind = { $case: "string_value", string_value: value }; + result.string_value = value; } else if (Array.isArray(value)) { - result.kind = { $case: "list_value", list_value: value }; + result.list_value = ListValue.wrap(value); } else if (typeof value === "object") { - result.kind = { $case: "struct_value", struct_value: value }; + result.struct_value = Struct.wrap(value); } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } - return result; }, - unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { - if (message.kind?.$case === "null_value") { + unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty("string_value") && message.string_value !== undefined) { + return message.string_value; + } else if (message?.hasOwnProperty("number_value") && message?.number_value !== undefined) { + return message.number_value; + } else if (message?.hasOwnProperty("bool_value") && message?.bool_value !== undefined) { + return message.bool_value; + } else if (message?.hasOwnProperty("struct_value") && message?.struct_value !== undefined) { + return Struct.unwrap(message.struct_value as any); + } else if (message?.hasOwnProperty("list_value") && message?.list_value !== undefined) { + return ListValue.unwrap(message.list_value); + } else if (message?.hasOwnProperty("null_value") && message?.null_value !== undefined) { return null; - } else if (message.kind?.$case === "number_value") { - return message.kind?.number_value; - } else if (message.kind?.$case === "string_value") { - return message.kind?.string_value; - } else if (message.kind?.$case === "bool_value") { - return message.kind?.bool_value; - } else if (message.kind?.$case === "struct_value") { - return message.kind?.struct_value; - } else if (message.kind?.$case === "list_value") { - return message.kind?.list_value; - } else { - return undefined; } + return undefined; }, }; @@ -475,17 +470,13 @@ export const ListValue = { return message; }, - wrap(value: Array | undefined): ListValue { - const result = createBaseListValue(); - - result.values = value ?? []; - - return result; + wrap(array: Array | undefined): ListValue { + return { values: (array ?? []).map(Value.wrap) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map((value: any) => Value.unwrap(value) || value); + return message.values.map(Value.unwrap); } else { return message as any; } diff --git a/integration/oneof-unions/google/protobuf/struct.ts b/integration/oneof-unions/google/protobuf/struct.ts index 71748ec83..e3d71bdcb 100644 --- a/integration/oneof-unions/google/protobuf/struct.ts +++ b/integration/oneof-unions/google/protobuf/struct.ts @@ -164,21 +164,19 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = object[key]; + struct.fields[key] = Value.wrap(object[key]); }); } return struct; }, unwrap(message: Struct): { [key: string]: any } { - if (!message.fields) { - return message; - } const object: { [key: string]: any } = {}; - Object.keys(message.fields).forEach((key) => { - const unwrappedValue = Value.unwrap(message.fields[key]); - object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; - }); + if (message.fields) { + Object.keys(message.fields).forEach((key) => { + object[key] = Value.unwrap(message.fields[key]); + }); + } return object; }, }; @@ -372,43 +370,40 @@ export const Value = { }, wrap(value: any): Value { - const result = createBaseValue(); - + const result = {} as any; if (value === null) { - result.kind = { $case: "nullValue", nullValue: NullValue.NULL_VALUE }; + result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { - result.kind = { $case: "boolValue", boolValue: value }; + result.boolValue = value; } else if (typeof value === "number") { - result.kind = { $case: "numberValue", numberValue: value }; + result.numberValue = value; } else if (typeof value === "string") { - result.kind = { $case: "stringValue", stringValue: value }; + result.stringValue = value; } else if (Array.isArray(value)) { - result.kind = { $case: "listValue", listValue: value }; + result.listValue = ListValue.wrap(value); } else if (typeof value === "object") { - result.kind = { $case: "structValue", structValue: value }; + result.structValue = Struct.wrap(value); } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } - return result; }, - unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { - if (message.kind?.$case === "nullValue") { + unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { + return message.stringValue; + } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { + return message.numberValue; + } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { + return message.boolValue; + } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + return Struct.unwrap(message.structValue as any); + } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { + return ListValue.unwrap(message.listValue); + } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; - } else if (message.kind?.$case === "numberValue") { - return message.kind?.numberValue; - } else if (message.kind?.$case === "stringValue") { - return message.kind?.stringValue; - } else if (message.kind?.$case === "boolValue") { - return message.kind?.boolValue; - } else if (message.kind?.$case === "structValue") { - return message.kind?.structValue; - } else if (message.kind?.$case === "listValue") { - return message.kind?.listValue; - } else { - return undefined; } + return undefined; }, }; @@ -466,17 +461,13 @@ export const ListValue = { return message; }, - wrap(value: Array | undefined): ListValue { - const result = createBaseListValue(); - - result.values = value ?? []; - - return result; + wrap(array: Array | undefined): ListValue { + return { values: (array ?? []).map(Value.wrap) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map((value: any) => Value.unwrap(value) || value); + return message.values.map(Value.unwrap); } else { return message as any; } diff --git a/integration/simple-snake/google/protobuf/struct.ts b/integration/simple-snake/google/protobuf/struct.ts index f25f91190..6cbad2725 100644 --- a/integration/simple-snake/google/protobuf/struct.ts +++ b/integration/simple-snake/google/protobuf/struct.ts @@ -179,21 +179,19 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = object[key]; + struct.fields[key] = Value.wrap(object[key]); }); } return struct; }, unwrap(message: Struct): { [key: string]: any } { - if (!message.fields) { - return message; - } const object: { [key: string]: any } = {}; - Object.keys(message.fields).forEach((key) => { - const unwrappedValue = Value.unwrap(message.fields[key]); - object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; - }); + if (message.fields) { + Object.keys(message.fields).forEach((key) => { + object[key] = Value.unwrap(message.fields[key]); + }); + } return object; }, }; @@ -363,8 +361,7 @@ export const Value = { }, wrap(value: any): Value { - const result = createBaseValue(); - + const result = {} as any; if (value === null) { result.null_value = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -374,18 +371,17 @@ export const Value = { } else if (typeof value === "string") { result.string_value = value; } else if (Array.isArray(value)) { - result.list_value = value; + result.list_value = ListValue.wrap(value); } else if (typeof value === "object") { - result.struct_value = value; + result.struct_value = Struct.wrap(value); } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } - return result; }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("string_value") && message?.string_value !== undefined) { + if (message?.hasOwnProperty("string_value") && message.string_value !== undefined) { return message.string_value; } else if (message?.hasOwnProperty("number_value") && message?.number_value !== undefined) { return message.number_value; @@ -456,17 +452,13 @@ export const ListValue = { return message; }, - wrap(value: Array | undefined): ListValue { - const result = createBaseListValue(); - - result.values = value ?? []; - - return result; + wrap(array: Array | undefined): ListValue { + return { values: (array ?? []).map(Value.wrap) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map((value: any) => Value.unwrap(value) || value); + return message.values.map(Value.unwrap); } else { return message as any; } diff --git a/integration/simple-string-enums/google/protobuf/struct.ts b/integration/simple-string-enums/google/protobuf/struct.ts index 2a96a6f7e..5f444e6bc 100644 --- a/integration/simple-string-enums/google/protobuf/struct.ts +++ b/integration/simple-string-enums/google/protobuf/struct.ts @@ -189,21 +189,19 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = object[key]; + struct.fields[key] = Value.wrap(object[key]); }); } return struct; }, unwrap(message: Struct): { [key: string]: any } { - if (!message.fields) { - return message; - } const object: { [key: string]: any } = {}; - Object.keys(message.fields).forEach((key) => { - const unwrappedValue = Value.unwrap(message.fields[key]); - object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; - }); + if (message.fields) { + Object.keys(message.fields).forEach((key) => { + object[key] = Value.unwrap(message.fields[key]); + }); + } return object; }, }; @@ -373,8 +371,7 @@ export const Value = { }, wrap(value: any): Value { - const result = createBaseValue(); - + const result = {} as any; if (value === null) { result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -384,18 +381,17 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = value; + result.listValue = ListValue.wrap(value); } else if (typeof value === "object") { - result.structValue = value; + result.structValue = Struct.wrap(value); } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } - return result; }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { + if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { return message.stringValue; } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { return message.numberValue; @@ -466,17 +462,13 @@ export const ListValue = { return message; }, - wrap(value: Array | undefined): ListValue { - const result = createBaseListValue(); - - result.values = value ?? []; - - return result; + wrap(array: Array | undefined): ListValue { + return { values: (array ?? []).map(Value.wrap) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map((value: any) => Value.unwrap(value) || value); + return message.values.map(Value.unwrap); } else { return message as any; } diff --git a/integration/struct/google/protobuf/struct.ts b/integration/struct/google/protobuf/struct.ts index d39a490ef..999445bd5 100644 --- a/integration/struct/google/protobuf/struct.ts +++ b/integration/struct/google/protobuf/struct.ts @@ -179,21 +179,19 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = object[key]; + struct.fields[key] = Value.wrap(object[key]); }); } return struct; }, unwrap(message: Struct): { [key: string]: any } { - if (!message.fields) { - return message; - } const object: { [key: string]: any } = {}; - Object.keys(message.fields).forEach((key) => { - const unwrappedValue = Value.unwrap(message.fields[key]); - object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; - }); + if (message.fields) { + Object.keys(message.fields).forEach((key) => { + object[key] = Value.unwrap(message.fields[key]); + }); + } return object; }, }; @@ -363,8 +361,7 @@ export const Value = { }, wrap(value: any): Value { - const result = createBaseValue(); - + const result = {} as any; if (value === null) { result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -374,18 +371,17 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = value; + result.listValue = ListValue.wrap(value); } else if (typeof value === "object") { - result.structValue = value; + result.structValue = Struct.wrap(value); } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } - return result; }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { + if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { return message.stringValue; } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { return message.numberValue; @@ -456,17 +452,13 @@ export const ListValue = { return message; }, - wrap(value: Array | undefined): ListValue { - const result = createBaseListValue(); - - result.values = value ?? []; - - return result; + wrap(array: Array | undefined): ListValue { + return { values: (array ?? []).map(Value.wrap) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map((value: any) => Value.unwrap(value) || value); + return message.values.map(Value.unwrap); } else { return message as any; } diff --git a/integration/type-registry/google/protobuf/struct.ts b/integration/type-registry/google/protobuf/struct.ts index 1cb812108..d135e5059 100644 --- a/integration/type-registry/google/protobuf/struct.ts +++ b/integration/type-registry/google/protobuf/struct.ts @@ -190,21 +190,19 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = object[key]; + struct.fields[key] = Value.wrap(object[key]); }); } return struct; }, unwrap(message: Struct): { [key: string]: any } { - if (!message.fields) { - return message; - } const object: { [key: string]: any } = {}; - Object.keys(message.fields).forEach((key) => { - const unwrappedValue = Value.unwrap(message.fields[key]); - object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; - }); + if (message.fields) { + Object.keys(message.fields).forEach((key) => { + object[key] = Value.unwrap(message.fields[key]); + }); + } return object; }, }; @@ -388,8 +386,7 @@ export const Value = { }, wrap(value: any): Value { - const result = createBaseValue(); - + const result = {} as any; if (value === null) { result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -399,18 +396,17 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = value; + result.listValue = ListValue.wrap(value); } else if (typeof value === "object") { - result.structValue = value; + result.structValue = Struct.wrap(value); } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } - return result; }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { + if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { return message.stringValue; } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { return message.numberValue; @@ -485,17 +481,13 @@ export const ListValue = { return message; }, - wrap(value: Array | undefined): ListValue { - const result = createBaseListValue(); - - result.values = value ?? []; - - return result; + wrap(array: Array | undefined): ListValue { + return { values: (array ?? []).map(Value.wrap) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map((value: any) => Value.unwrap(value) || value); + return message.values.map(Value.unwrap); } else { return message as any; } diff --git a/integration/use-map-type/google/protobuf/struct.ts b/integration/use-map-type/google/protobuf/struct.ts index f135866ce..fa7fd5b6d 100644 --- a/integration/use-map-type/google/protobuf/struct.ts +++ b/integration/use-map-type/google/protobuf/struct.ts @@ -179,7 +179,7 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields.set(key, object[key]); + struct.fields.set(key, Value.wrap(object[key])); }); } return struct; @@ -188,8 +188,7 @@ export const Struct = { unwrap(message: Struct): { [key: string]: any } { const object: { [key: string]: any } = {}; [...message.fields.keys()].forEach((key) => { - const unwrappedValue = Value.unwrap(message.fields.get(key)); - object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields.get(key); + object[key] = Value.unwrap(message.fields.get(key)); }); return object; }, @@ -360,8 +359,7 @@ export const Value = { }, wrap(value: any): Value { - const result = createBaseValue(); - + const result = {} as any; if (value === null) { result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -371,18 +369,17 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = value; + result.listValue = ListValue.wrap(value); } else if (typeof value === "object") { - result.structValue = value; + result.structValue = Struct.wrap(value); } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } - return result; }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { + if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { return message.stringValue; } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { return message.numberValue; @@ -453,17 +450,13 @@ export const ListValue = { return message; }, - wrap(value: Array | undefined): ListValue { - const result = createBaseListValue(); - - result.values = value ?? []; - - return result; + wrap(array: Array | undefined): ListValue { + return { values: (array ?? []).map(Value.wrap) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map((value: any) => Value.unwrap(value) || value); + return message.values.map(Value.unwrap); } else { return message as any; } diff --git a/integration/use-numeric-enum-json/google/protobuf/struct.ts b/integration/use-numeric-enum-json/google/protobuf/struct.ts index 74ccf3c01..af47ae145 100644 --- a/integration/use-numeric-enum-json/google/protobuf/struct.ts +++ b/integration/use-numeric-enum-json/google/protobuf/struct.ts @@ -179,21 +179,19 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = object[key]; + struct.fields[key] = Value.wrap(object[key]); }); } return struct; }, unwrap(message: Struct): { [key: string]: any } { - if (!message.fields) { - return message; - } const object: { [key: string]: any } = {}; - Object.keys(message.fields).forEach((key) => { - const unwrappedValue = Value.unwrap(message.fields[key]); - object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; - }); + if (message.fields) { + Object.keys(message.fields).forEach((key) => { + object[key] = Value.unwrap(message.fields[key]); + }); + } return object; }, }; @@ -363,8 +361,7 @@ export const Value = { }, wrap(value: any): Value { - const result = createBaseValue(); - + const result = {} as any; if (value === null) { result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -374,18 +371,17 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = value; + result.listValue = ListValue.wrap(value); } else if (typeof value === "object") { - result.structValue = value; + result.structValue = Struct.wrap(value); } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } - return result; }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { + if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { return message.stringValue; } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { return message.numberValue; @@ -456,17 +452,13 @@ export const ListValue = { return message; }, - wrap(value: Array | undefined): ListValue { - const result = createBaseListValue(); - - result.values = value ?? []; - - return result; + wrap(array: Array | undefined): ListValue { + return { values: (array ?? []).map(Value.wrap) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map((value: any) => Value.unwrap(value) || value); + return message.values.map(Value.unwrap); } else { return message as any; } diff --git a/integration/use-readonly-types/google/protobuf/field_mask.ts b/integration/use-readonly-types/google/protobuf/field_mask.ts index 850752961..7f2e0b019 100644 --- a/integration/use-readonly-types/google/protobuf/field_mask.ts +++ b/integration/use-readonly-types/google/protobuf/field_mask.ts @@ -264,9 +264,7 @@ export const FieldMask = { wrap(paths: readonly string[]): FieldMask { const result = createBaseFieldMask() as any; - result.paths = paths; - return result; }, diff --git a/integration/use-readonly-types/google/protobuf/struct.ts b/integration/use-readonly-types/google/protobuf/struct.ts index 8a708bbff..cb7086db1 100644 --- a/integration/use-readonly-types/google/protobuf/struct.ts +++ b/integration/use-readonly-types/google/protobuf/struct.ts @@ -164,21 +164,19 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = object[key]; + struct.fields[key] = Value.wrap(object[key]); }); } return struct; }, unwrap(message: Struct): { [key: string]: any } { - if (!message.fields) { - return message; - } const object: { [key: string]: any } = {}; - Object.keys(message.fields).forEach((key) => { - const unwrappedValue = Value.unwrap(message.fields[key]); - object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; - }); + if (message.fields) { + Object.keys(message.fields).forEach((key) => { + object[key] = Value.unwrap(message.fields[key]); + }); + } return object; }, }; @@ -372,43 +370,40 @@ export const Value = { }, wrap(value: any): Value { - const result = createBaseValue() as any; - + const result = {} as any; if (value === null) { - result.kind = { $case: "nullValue", nullValue: NullValue.NULL_VALUE }; + result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { - result.kind = { $case: "boolValue", boolValue: value }; + result.boolValue = value; } else if (typeof value === "number") { - result.kind = { $case: "numberValue", numberValue: value }; + result.numberValue = value; } else if (typeof value === "string") { - result.kind = { $case: "stringValue", stringValue: value }; + result.stringValue = value; } else if (Array.isArray(value)) { - result.kind = { $case: "listValue", listValue: value }; + result.listValue = ListValue.wrap(value); } else if (typeof value === "object") { - result.kind = { $case: "structValue", structValue: value }; + result.structValue = Struct.wrap(value); } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } - return result; }, - unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { - if (message.kind?.$case === "nullValue") { + unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { + return message.stringValue; + } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { + return message.numberValue; + } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { + return message.boolValue; + } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + return Struct.unwrap(message.structValue as any); + } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { + return ListValue.unwrap(message.listValue); + } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; - } else if (message.kind?.$case === "numberValue") { - return message.kind?.numberValue; - } else if (message.kind?.$case === "stringValue") { - return message.kind?.stringValue; - } else if (message.kind?.$case === "boolValue") { - return message.kind?.boolValue; - } else if (message.kind?.$case === "structValue") { - return message.kind?.structValue; - } else if (message.kind?.$case === "listValue") { - return message.kind?.listValue; - } else { - return undefined; } + return undefined; }, }; @@ -466,17 +461,13 @@ export const ListValue = { return message; }, - wrap(value: ReadonlyArray | undefined): ListValue { - const result = createBaseListValue() as any; - - result.values = value ?? []; - - return result; + wrap(array: ReadonlyArray | undefined): ListValue { + return { values: (array ?? []).map(Value.wrap) }; }, unwrap(message: any): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map((value: any) => Value.unwrap(value) || value); + return message.values.map(Value.unwrap); } else { return message as any; } diff --git a/integration/value/google/protobuf/struct.ts b/integration/value/google/protobuf/struct.ts index d39a490ef..999445bd5 100644 --- a/integration/value/google/protobuf/struct.ts +++ b/integration/value/google/protobuf/struct.ts @@ -179,21 +179,19 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = object[key]; + struct.fields[key] = Value.wrap(object[key]); }); } return struct; }, unwrap(message: Struct): { [key: string]: any } { - if (!message.fields) { - return message; - } const object: { [key: string]: any } = {}; - Object.keys(message.fields).forEach((key) => { - const unwrappedValue = Value.unwrap(message.fields[key]); - object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; - }); + if (message.fields) { + Object.keys(message.fields).forEach((key) => { + object[key] = Value.unwrap(message.fields[key]); + }); + } return object; }, }; @@ -363,8 +361,7 @@ export const Value = { }, wrap(value: any): Value { - const result = createBaseValue(); - + const result = {} as any; if (value === null) { result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -374,18 +371,17 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = value; + result.listValue = ListValue.wrap(value); } else if (typeof value === "object") { - result.structValue = value; + result.structValue = Struct.wrap(value); } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } - return result; }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message?.stringValue !== undefined) { + if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { return message.stringValue; } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { return message.numberValue; @@ -456,17 +452,13 @@ export const ListValue = { return message; }, - wrap(value: Array | undefined): ListValue { - const result = createBaseListValue(); - - result.values = value ?? []; - - return result; + wrap(array: Array | undefined): ListValue { + return { values: (array ?? []).map(Value.wrap) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map((value: any) => Value.unwrap(value) || value); + return message.values.map(Value.unwrap); } else { return message as any; } diff --git a/src/main.ts b/src/main.ts index bf8d08e95..5e17907b5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -154,18 +154,6 @@ export function generateFile(ctx: Context, fileDesc: FileDescriptorProto): [stri ) { chunks.push(makeProtobufTimestampWrapper()); } - - if (fileDesc.messageType.find((message) => message.field.find(isStructType))) { - const structFieldNames = { - nullValue: maybeSnakeToCamel("null_value", ctx.options), - numberValue: maybeSnakeToCamel("number_value", ctx.options), - stringValue: maybeSnakeToCamel("string_value", ctx.options), - boolValue: maybeSnakeToCamel("bool_value", ctx.options), - structValue: maybeSnakeToCamel("struct_value", ctx.options), - listValue: maybeSnakeToCamel("list_value", ctx.options), - }; - chunks.push(makeProtobufStructWrapper(options, structFieldNames)); - } } // We add `nestJs` here because enough though it doesn't use our encode/decode methods @@ -237,6 +225,12 @@ export function generateFile(ctx: Context, fileDesc: FileDescriptorProto): [stri ); } + if (options.nestJs) { + if (fileDesc.messageType.find((message) => message.field.find(isStructType))) { + chunks.push(makeProtobufStructWrapper(options)); + } + } + let hasServerStreamingMethods = false; let hasStreamingMethods = false; @@ -380,46 +374,14 @@ function makeProtobufTimestampWrapper() { } as any;`; } -function makeProtobufStructWrapper(options: Options, fieldNames: StructFieldNames) { +function makeProtobufStructWrapper(options: Options) { const wrappers = imp("wrappers@protobufjs"); const Struct = impProto(options, "google/protobuf/struct", "Struct"); - const Value = impProto(options, "google/protobuf/struct", "Value"); return code` - const wrapStruct = (value: any, nested = false): any => { - const valueType = typeof value; - const primitiveValueTypes = { - number: 'numberValue', - string: 'stringValue', - boolean: 'boolValue' - } - if (Object.keys(primitiveValueTypes).includes(valueType)) { - return ${Value}.wrap(value); - } - if (Array.isArray(value)) { - return { - listValue: { - values: value.map((item) => wrapStruct(item)) - } - }; - } - if (valueType === 'object') { - const res = nested ? { structValue: { fields: {} as any } } : { fields: {} as any }; - Object.keys(value).forEach((field) => { - if (nested) { - res.structValue!.fields[field] = wrapStruct(value[field], true) - } else { - res.fields![field] = wrapStruct(value[field], true) - } - }) - return res; - } - } - ${wrappers}['.google.protobuf.Struct'] = { - fromObject: wrapStruct, - toObject(message: Struct) { - return message ? ${Struct}.unwrap(message) : message; - }, - } as any;`; + ${wrappers}['.google.protobuf.Struct'] = { + fromObject: ${Struct}.wrap, + toObject: ${Struct}.unwrap, + } as any;`; } function makeLongUtils(options: Options, bytes: ReturnType) { @@ -1843,11 +1805,10 @@ function isWrapperType(fullProtoTypeName: string): boolean { function generateWrap(ctx: Context, fullProtoTypeName: string, fieldNames: StructFieldNames): Code[] { const chunks: Code[] = []; if (isStructTypeName(fullProtoTypeName)) { - let setStatement = "struct.fields[key] = object[key];"; + let setStatement = "struct.fields[key] = Value.wrap(object[key]);"; if (ctx.options.useMapType) { - setStatement = "struct.fields.set(key, object[key]);"; + setStatement = "struct.fields.set(key, Value.wrap(object[key]));"; } - chunks.push(code`wrap(object: {[key: string]: any} | undefined): Struct { const struct = createBaseStruct(); if (object !== undefined) { @@ -1860,71 +1821,39 @@ function generateWrap(ctx: Context, fullProtoTypeName: string, fieldNames: Struc } if (isAnyValueTypeName(fullProtoTypeName)) { - if (ctx.options.oneof === OneofOption.UNIONS) { - chunks.push(code`wrap(value: any): Value { - const result = createBaseValue()${maybeAsAny(ctx.options)}; - - if (value === null) { - result.kind = {$case: '${fieldNames.nullValue}', ${fieldNames.nullValue}: NullValue.NULL_VALUE}; - } else if (typeof value === 'boolean') { - result.kind = {$case: '${fieldNames.boolValue}', ${fieldNames.boolValue}: value}; - } else if (typeof value === 'number') { - result.kind = {$case: '${fieldNames.numberValue}', ${fieldNames.numberValue}: value}; - } else if (typeof value === 'string') { - result.kind = {$case: '${fieldNames.stringValue}', ${fieldNames.stringValue}: value}; - } else if (Array.isArray(value)) { - result.kind = {$case: '${fieldNames.listValue}', ${fieldNames.listValue}: value}; - } else if (typeof value === 'object') { - result.kind = {$case: '${fieldNames.structValue}', ${fieldNames.structValue}: value}; - } else if (typeof value !== 'undefined') { - throw new Error('Unsupported any value type: ' + typeof value); - } - - return result; - }`); - } else { - chunks.push(code`wrap(value: any): Value { - const result = createBaseValue()${maybeAsAny(ctx.options)}; - - if (value === null) { - result.${fieldNames.nullValue} = NullValue.NULL_VALUE; - } else if (typeof value === 'boolean') { - result.${fieldNames.boolValue} = value; - } else if (typeof value === 'number') { - result.${fieldNames.numberValue} = value; - } else if (typeof value === 'string') { - result.${fieldNames.stringValue} = value; - } else if (Array.isArray(value)) { - result.${fieldNames.listValue} = value; - } else if (typeof value === 'object') { - result.${fieldNames.structValue} = value; - } else if (typeof value !== 'undefined') { - throw new Error('Unsupported any value type: ' + typeof value); - } - - return result; + // Turn ts-proto representation --> proto representation + chunks.push(code`wrap(value: any): Value { + const result = {} as any; + if (value === null) { + result.${fieldNames.nullValue} = NullValue.NULL_VALUE; + } else if (typeof value === 'boolean') { + result.${fieldNames.boolValue} = value; + } else if (typeof value === 'number') { + result.${fieldNames.numberValue} = value; + } else if (typeof value === 'string') { + result.${fieldNames.stringValue} = value; + } else if (Array.isArray(value)) { + result.${fieldNames.listValue} = ListValue.wrap(value); + } else if (typeof value === 'object') { + result.${fieldNames.structValue} = Struct.wrap(value); + } else if (typeof value !== 'undefined') { + throw new Error('Unsupported any value type: ' + typeof value); + } + return result; }`); - } } if (isListValueTypeName(fullProtoTypeName)) { - chunks.push(code`wrap(value: ${ - ctx.options.useReadonlyTypes ? "ReadonlyArray" : "Array" - } | undefined): ListValue { - const result = createBaseListValue()${maybeAsAny(ctx.options)}; - - result.values = value ?? []; - - return result; + const maybeReadyOnly = ctx.options.useReadonlyTypes ? "Readonly" : ""; + chunks.push(code`wrap(array: ${maybeReadyOnly}Array | undefined): ListValue { + return { values: (array ?? []).map(Value.wrap) }; }`); } if (isFieldMaskTypeName(fullProtoTypeName)) { chunks.push(code`wrap(paths: ${maybeReadonly(ctx.options)} string[]): FieldMask { const result = createBaseFieldMask()${maybeAsAny(ctx.options)}; - result.paths = paths; - return result; }`); } @@ -1939,69 +1868,47 @@ function generateUnwrap(ctx: Context, fullProtoTypeName: string, fieldNames: Str chunks.push(code`unwrap(message: Struct): {[key: string]: any} { const object: { [key: string]: any } = {}; [...message.fields.keys()].forEach((key) => { - const unwrappedValue = Value.unwrap(message.fields.get(key)); - object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields.get(key); + object[key] = Value.unwrap(message.fields.get(key)); }); return object; }`); } else { chunks.push(code`unwrap(message: Struct): {[key: string]: any} { - if (!message.fields) { - return message; - } const object: { [key: string]: any } = {}; - Object.keys(message.fields).forEach(key => { - const unwrappedValue = Value.unwrap(message.fields[key]); - object[key] = unwrappedValue !== undefined ? unwrappedValue : message.fields[key]; - }); + if (message.fields) { + Object.keys(message.fields).forEach(key => { + object[key] = Value.unwrap(message.fields[key]); + }); + } return object; }`); } } if (isAnyValueTypeName(fullProtoTypeName)) { - if (ctx.options.oneof === OneofOption.UNIONS) { - chunks.push(code`unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { - if (message.kind?.$case === '${fieldNames.nullValue}') { - return null; - } else if (message.kind?.$case === '${fieldNames.numberValue}') { - return message.kind?.${fieldNames.numberValue}; - } else if (message.kind?.$case === '${fieldNames.stringValue}') { - return message.kind?.${fieldNames.stringValue}; - } else if (message.kind?.$case === '${fieldNames.boolValue}') { - return message.kind?.${fieldNames.boolValue}; - } else if (message.kind?.$case === '${fieldNames.structValue}') { - return message.kind?.${fieldNames.structValue}; - } else if (message.kind?.$case === '${fieldNames.listValue}') { - return message.kind?.${fieldNames.listValue}; - } else { - return undefined; - } - }`); - } else { - chunks.push(code`unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty('${fieldNames.stringValue}') && message?.${fieldNames.stringValue} !== undefined) { - return message.${fieldNames.stringValue}; - } else if (message?.hasOwnProperty('${fieldNames.numberValue}') && message?.${fieldNames.numberValue} !== undefined) { - return message.${fieldNames.numberValue}; - } else if (message?.hasOwnProperty('${fieldNames.boolValue}') && message?.${fieldNames.boolValue} !== undefined) { - return message.${fieldNames.boolValue}; - } else if (message?.hasOwnProperty('${fieldNames.structValue}') && message?.${fieldNames.structValue} !== undefined) { - return Struct.unwrap(message.${fieldNames.structValue} as any); - } else if (message?.hasOwnProperty('${fieldNames.listValue}') && message?.${fieldNames.listValue} !== undefined) { - return ListValue.unwrap(message.${fieldNames.listValue}); - } else if (message?.hasOwnProperty('${fieldNames.nullValue}') && message?.${fieldNames.nullValue} !== undefined) { - return null; - } - return undefined; - }`); - } + // Put proto encoding into idiomatic ts-proto + chunks.push(code`unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty('${fieldNames.stringValue}') && message.${fieldNames.stringValue} !== undefined) { + return message.${fieldNames.stringValue}; + } else if (message?.hasOwnProperty('${fieldNames.numberValue}') && message?.${fieldNames.numberValue} !== undefined) { + return message.${fieldNames.numberValue}; + } else if (message?.hasOwnProperty('${fieldNames.boolValue}') && message?.${fieldNames.boolValue} !== undefined) { + return message.${fieldNames.boolValue}; + } else if (message?.hasOwnProperty('${fieldNames.structValue}') && message?.${fieldNames.structValue} !== undefined) { + return Struct.unwrap(message.${fieldNames.structValue} as any); + } else if (message?.hasOwnProperty('${fieldNames.listValue}') && message?.${fieldNames.listValue} !== undefined) { + return ListValue.unwrap(message.${fieldNames.listValue}); + } else if (message?.hasOwnProperty('${fieldNames.nullValue}') && message?.${fieldNames.nullValue} !== undefined) { + return null; + } + return undefined; + }`); } if (isListValueTypeName(fullProtoTypeName)) { chunks.push(code`unwrap(message: ${ctx.options.useReadonlyTypes ? "any" : "ListValue"}): Array { if (message?.hasOwnProperty('values') && Array.isArray(message.values)) { - return message.values.map((value: any) => Value.unwrap(value) || value); + return message.values.map(Value.unwrap); } else { return message as any; } From 1bfd10dd66f6a77b262ac07f8b32d11b175a55de Mon Sep 17 00:00:00 2001 From: Stephen Haberman Date: Mon, 30 Jan 2023 18:21:03 -0600 Subject: [PATCH 8/9] Use conditional shallow/deep wrapping. --- integration/grpc-js/google/protobuf/struct.ts | 16 +- .../nice-grpc/google/protobuf/struct.ts | 16 +- .../google/protobuf/struct.ts | 16 +- .../oneof-unions/google/protobuf/struct.ts | 16 +- .../simple-snake/google/protobuf/struct.ts | 16 +- .../google/protobuf/struct.ts | 16 +- integration/struct/google/protobuf/struct.ts | 16 +- .../type-registry/google/protobuf/struct.ts | 16 +- .../use-map-type/google/protobuf/struct.ts | 16 +- .../google/protobuf/struct.ts | 16 +- .../google/protobuf/struct.ts | 16 +- integration/value/google/protobuf/struct.ts | 16 +- src/generate-struct-wrappers.ts | 295 ++++++++++++++++++ src/main.ts | 159 +--------- 14 files changed, 407 insertions(+), 239 deletions(-) create mode 100644 src/generate-struct-wrappers.ts diff --git a/integration/grpc-js/google/protobuf/struct.ts b/integration/grpc-js/google/protobuf/struct.ts index 999445bd5..40dad0b5e 100644 --- a/integration/grpc-js/google/protobuf/struct.ts +++ b/integration/grpc-js/google/protobuf/struct.ts @@ -179,7 +179,7 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = Value.wrap(object[key]); + struct.fields[key] = object[key]; }); } return struct; @@ -189,7 +189,7 @@ export const Struct = { const object: { [key: string]: any } = {}; if (message.fields) { Object.keys(message.fields).forEach((key) => { - object[key] = Value.unwrap(message.fields[key]); + object[key] = message.fields[key]; }); } return object; @@ -371,9 +371,9 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = ListValue.wrap(value); + result.listValue = value; } else if (typeof value === "object") { - result.structValue = Struct.wrap(value); + result.structValue = value; } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } @@ -388,9 +388,9 @@ export const Value = { } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { - return Struct.unwrap(message.structValue as any); + return message.structValue as any; } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return ListValue.unwrap(message.listValue); + return message.listValue; } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -453,12 +453,12 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []).map(Value.wrap) }; + return { values: (array ?? []) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map(Value.unwrap); + return message.values; } else { return message as any; } diff --git a/integration/nice-grpc/google/protobuf/struct.ts b/integration/nice-grpc/google/protobuf/struct.ts index ff02b8b85..23cf0d31d 100644 --- a/integration/nice-grpc/google/protobuf/struct.ts +++ b/integration/nice-grpc/google/protobuf/struct.ts @@ -179,7 +179,7 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = Value.wrap(object[key]); + struct.fields[key] = object[key]; }); } return struct; @@ -189,7 +189,7 @@ export const Struct = { const object: { [key: string]: any } = {}; if (message.fields) { Object.keys(message.fields).forEach((key) => { - object[key] = Value.unwrap(message.fields[key]); + object[key] = message.fields[key]; }); } return object; @@ -371,9 +371,9 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = ListValue.wrap(value); + result.listValue = value; } else if (typeof value === "object") { - result.structValue = Struct.wrap(value); + result.structValue = value; } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } @@ -388,9 +388,9 @@ export const Value = { } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { - return Struct.unwrap(message.structValue as any); + return message.structValue as any; } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return ListValue.unwrap(message.listValue); + return message.listValue; } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -453,12 +453,12 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []).map(Value.wrap) }; + return { values: (array ?? []) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map(Value.unwrap); + return message.values; } else { return message as any; } diff --git a/integration/oneof-unions-snake/google/protobuf/struct.ts b/integration/oneof-unions-snake/google/protobuf/struct.ts index cb947bd3f..bedc7ef90 100644 --- a/integration/oneof-unions-snake/google/protobuf/struct.ts +++ b/integration/oneof-unions-snake/google/protobuf/struct.ts @@ -164,7 +164,7 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = Value.wrap(object[key]); + struct.fields[key] = object[key]; }); } return struct; @@ -174,7 +174,7 @@ export const Struct = { const object: { [key: string]: any } = {}; if (message.fields) { Object.keys(message.fields).forEach((key) => { - object[key] = Value.unwrap(message.fields[key]); + object[key] = message.fields[key]; }); } return object; @@ -389,9 +389,9 @@ export const Value = { } else if (typeof value === "string") { result.string_value = value; } else if (Array.isArray(value)) { - result.list_value = ListValue.wrap(value); + result.list_value = value; } else if (typeof value === "object") { - result.struct_value = Struct.wrap(value); + result.struct_value = value; } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } @@ -406,9 +406,9 @@ export const Value = { } else if (message?.hasOwnProperty("bool_value") && message?.bool_value !== undefined) { return message.bool_value; } else if (message?.hasOwnProperty("struct_value") && message?.struct_value !== undefined) { - return Struct.unwrap(message.struct_value as any); + return message.struct_value as any; } else if (message?.hasOwnProperty("list_value") && message?.list_value !== undefined) { - return ListValue.unwrap(message.list_value); + return message.list_value; } else if (message?.hasOwnProperty("null_value") && message?.null_value !== undefined) { return null; } @@ -471,12 +471,12 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []).map(Value.wrap) }; + return { values: (array ?? []) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map(Value.unwrap); + return message.values; } else { return message as any; } diff --git a/integration/oneof-unions/google/protobuf/struct.ts b/integration/oneof-unions/google/protobuf/struct.ts index e3d71bdcb..014c90c41 100644 --- a/integration/oneof-unions/google/protobuf/struct.ts +++ b/integration/oneof-unions/google/protobuf/struct.ts @@ -164,7 +164,7 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = Value.wrap(object[key]); + struct.fields[key] = object[key]; }); } return struct; @@ -174,7 +174,7 @@ export const Struct = { const object: { [key: string]: any } = {}; if (message.fields) { Object.keys(message.fields).forEach((key) => { - object[key] = Value.unwrap(message.fields[key]); + object[key] = message.fields[key]; }); } return object; @@ -380,9 +380,9 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = ListValue.wrap(value); + result.listValue = value; } else if (typeof value === "object") { - result.structValue = Struct.wrap(value); + result.structValue = value; } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } @@ -397,9 +397,9 @@ export const Value = { } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { - return Struct.unwrap(message.structValue as any); + return message.structValue as any; } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return ListValue.unwrap(message.listValue); + return message.listValue; } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -462,12 +462,12 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []).map(Value.wrap) }; + return { values: (array ?? []) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map(Value.unwrap); + return message.values; } else { return message as any; } diff --git a/integration/simple-snake/google/protobuf/struct.ts b/integration/simple-snake/google/protobuf/struct.ts index 6cbad2725..8d360819f 100644 --- a/integration/simple-snake/google/protobuf/struct.ts +++ b/integration/simple-snake/google/protobuf/struct.ts @@ -179,7 +179,7 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = Value.wrap(object[key]); + struct.fields[key] = object[key]; }); } return struct; @@ -189,7 +189,7 @@ export const Struct = { const object: { [key: string]: any } = {}; if (message.fields) { Object.keys(message.fields).forEach((key) => { - object[key] = Value.unwrap(message.fields[key]); + object[key] = message.fields[key]; }); } return object; @@ -371,9 +371,9 @@ export const Value = { } else if (typeof value === "string") { result.string_value = value; } else if (Array.isArray(value)) { - result.list_value = ListValue.wrap(value); + result.list_value = value; } else if (typeof value === "object") { - result.struct_value = Struct.wrap(value); + result.struct_value = value; } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } @@ -388,9 +388,9 @@ export const Value = { } else if (message?.hasOwnProperty("bool_value") && message?.bool_value !== undefined) { return message.bool_value; } else if (message?.hasOwnProperty("struct_value") && message?.struct_value !== undefined) { - return Struct.unwrap(message.struct_value as any); + return message.struct_value as any; } else if (message?.hasOwnProperty("list_value") && message?.list_value !== undefined) { - return ListValue.unwrap(message.list_value); + return message.list_value; } else if (message?.hasOwnProperty("null_value") && message?.null_value !== undefined) { return null; } @@ -453,12 +453,12 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []).map(Value.wrap) }; + return { values: (array ?? []) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map(Value.unwrap); + return message.values; } else { return message as any; } diff --git a/integration/simple-string-enums/google/protobuf/struct.ts b/integration/simple-string-enums/google/protobuf/struct.ts index 5f444e6bc..55f74d501 100644 --- a/integration/simple-string-enums/google/protobuf/struct.ts +++ b/integration/simple-string-enums/google/protobuf/struct.ts @@ -189,7 +189,7 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = Value.wrap(object[key]); + struct.fields[key] = object[key]; }); } return struct; @@ -199,7 +199,7 @@ export const Struct = { const object: { [key: string]: any } = {}; if (message.fields) { Object.keys(message.fields).forEach((key) => { - object[key] = Value.unwrap(message.fields[key]); + object[key] = message.fields[key]; }); } return object; @@ -381,9 +381,9 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = ListValue.wrap(value); + result.listValue = value; } else if (typeof value === "object") { - result.structValue = Struct.wrap(value); + result.structValue = value; } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } @@ -398,9 +398,9 @@ export const Value = { } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { - return Struct.unwrap(message.structValue as any); + return message.structValue as any; } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return ListValue.unwrap(message.listValue); + return message.listValue; } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -463,12 +463,12 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []).map(Value.wrap) }; + return { values: (array ?? []) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map(Value.unwrap); + return message.values; } else { return message as any; } diff --git a/integration/struct/google/protobuf/struct.ts b/integration/struct/google/protobuf/struct.ts index 999445bd5..40dad0b5e 100644 --- a/integration/struct/google/protobuf/struct.ts +++ b/integration/struct/google/protobuf/struct.ts @@ -179,7 +179,7 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = Value.wrap(object[key]); + struct.fields[key] = object[key]; }); } return struct; @@ -189,7 +189,7 @@ export const Struct = { const object: { [key: string]: any } = {}; if (message.fields) { Object.keys(message.fields).forEach((key) => { - object[key] = Value.unwrap(message.fields[key]); + object[key] = message.fields[key]; }); } return object; @@ -371,9 +371,9 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = ListValue.wrap(value); + result.listValue = value; } else if (typeof value === "object") { - result.structValue = Struct.wrap(value); + result.structValue = value; } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } @@ -388,9 +388,9 @@ export const Value = { } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { - return Struct.unwrap(message.structValue as any); + return message.structValue as any; } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return ListValue.unwrap(message.listValue); + return message.listValue; } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -453,12 +453,12 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []).map(Value.wrap) }; + return { values: (array ?? []) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map(Value.unwrap); + return message.values; } else { return message as any; } diff --git a/integration/type-registry/google/protobuf/struct.ts b/integration/type-registry/google/protobuf/struct.ts index d135e5059..9fbad3cf0 100644 --- a/integration/type-registry/google/protobuf/struct.ts +++ b/integration/type-registry/google/protobuf/struct.ts @@ -190,7 +190,7 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = Value.wrap(object[key]); + struct.fields[key] = object[key]; }); } return struct; @@ -200,7 +200,7 @@ export const Struct = { const object: { [key: string]: any } = {}; if (message.fields) { Object.keys(message.fields).forEach((key) => { - object[key] = Value.unwrap(message.fields[key]); + object[key] = message.fields[key]; }); } return object; @@ -396,9 +396,9 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = ListValue.wrap(value); + result.listValue = value; } else if (typeof value === "object") { - result.structValue = Struct.wrap(value); + result.structValue = value; } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } @@ -413,9 +413,9 @@ export const Value = { } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { - return Struct.unwrap(message.structValue as any); + return message.structValue as any; } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return ListValue.unwrap(message.listValue); + return message.listValue; } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -482,12 +482,12 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []).map(Value.wrap) }; + return { values: (array ?? []) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map(Value.unwrap); + return message.values; } else { return message as any; } diff --git a/integration/use-map-type/google/protobuf/struct.ts b/integration/use-map-type/google/protobuf/struct.ts index fa7fd5b6d..855f4e6a1 100644 --- a/integration/use-map-type/google/protobuf/struct.ts +++ b/integration/use-map-type/google/protobuf/struct.ts @@ -179,7 +179,7 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields.set(key, Value.wrap(object[key])); + struct.fields.set(key, object[key]); }); } return struct; @@ -188,7 +188,7 @@ export const Struct = { unwrap(message: Struct): { [key: string]: any } { const object: { [key: string]: any } = {}; [...message.fields.keys()].forEach((key) => { - object[key] = Value.unwrap(message.fields.get(key)); + object[key] = message.fields.get(key); }); return object; }, @@ -369,9 +369,9 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = ListValue.wrap(value); + result.listValue = value; } else if (typeof value === "object") { - result.structValue = Struct.wrap(value); + result.structValue = value; } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } @@ -386,9 +386,9 @@ export const Value = { } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { - return Struct.unwrap(message.structValue as any); + return message.structValue as any; } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return ListValue.unwrap(message.listValue); + return message.listValue; } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -451,12 +451,12 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []).map(Value.wrap) }; + return { values: (array ?? []) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map(Value.unwrap); + return message.values; } else { return message as any; } diff --git a/integration/use-numeric-enum-json/google/protobuf/struct.ts b/integration/use-numeric-enum-json/google/protobuf/struct.ts index af47ae145..06599f4b2 100644 --- a/integration/use-numeric-enum-json/google/protobuf/struct.ts +++ b/integration/use-numeric-enum-json/google/protobuf/struct.ts @@ -179,7 +179,7 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = Value.wrap(object[key]); + struct.fields[key] = object[key]; }); } return struct; @@ -189,7 +189,7 @@ export const Struct = { const object: { [key: string]: any } = {}; if (message.fields) { Object.keys(message.fields).forEach((key) => { - object[key] = Value.unwrap(message.fields[key]); + object[key] = message.fields[key]; }); } return object; @@ -371,9 +371,9 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = ListValue.wrap(value); + result.listValue = value; } else if (typeof value === "object") { - result.structValue = Struct.wrap(value); + result.structValue = value; } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } @@ -388,9 +388,9 @@ export const Value = { } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { - return Struct.unwrap(message.structValue as any); + return message.structValue as any; } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return ListValue.unwrap(message.listValue); + return message.listValue; } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -453,12 +453,12 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []).map(Value.wrap) }; + return { values: (array ?? []) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map(Value.unwrap); + return message.values; } else { return message as any; } diff --git a/integration/use-readonly-types/google/protobuf/struct.ts b/integration/use-readonly-types/google/protobuf/struct.ts index cb7086db1..409e38cbc 100644 --- a/integration/use-readonly-types/google/protobuf/struct.ts +++ b/integration/use-readonly-types/google/protobuf/struct.ts @@ -164,7 +164,7 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = Value.wrap(object[key]); + struct.fields[key] = object[key]; }); } return struct; @@ -174,7 +174,7 @@ export const Struct = { const object: { [key: string]: any } = {}; if (message.fields) { Object.keys(message.fields).forEach((key) => { - object[key] = Value.unwrap(message.fields[key]); + object[key] = message.fields[key]; }); } return object; @@ -380,9 +380,9 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = ListValue.wrap(value); + result.listValue = value; } else if (typeof value === "object") { - result.structValue = Struct.wrap(value); + result.structValue = value; } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } @@ -397,9 +397,9 @@ export const Value = { } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { - return Struct.unwrap(message.structValue as any); + return message.structValue as any; } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return ListValue.unwrap(message.listValue); + return message.listValue; } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -462,12 +462,12 @@ export const ListValue = { }, wrap(array: ReadonlyArray | undefined): ListValue { - return { values: (array ?? []).map(Value.wrap) }; + return { values: (array ?? []) }; }, unwrap(message: any): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map(Value.unwrap); + return message.values; } else { return message as any; } diff --git a/integration/value/google/protobuf/struct.ts b/integration/value/google/protobuf/struct.ts index 999445bd5..40dad0b5e 100644 --- a/integration/value/google/protobuf/struct.ts +++ b/integration/value/google/protobuf/struct.ts @@ -179,7 +179,7 @@ export const Struct = { const struct = createBaseStruct(); if (object !== undefined) { Object.keys(object).forEach((key) => { - struct.fields[key] = Value.wrap(object[key]); + struct.fields[key] = object[key]; }); } return struct; @@ -189,7 +189,7 @@ export const Struct = { const object: { [key: string]: any } = {}; if (message.fields) { Object.keys(message.fields).forEach((key) => { - object[key] = Value.unwrap(message.fields[key]); + object[key] = message.fields[key]; }); } return object; @@ -371,9 +371,9 @@ export const Value = { } else if (typeof value === "string") { result.stringValue = value; } else if (Array.isArray(value)) { - result.listValue = ListValue.wrap(value); + result.listValue = value; } else if (typeof value === "object") { - result.structValue = Struct.wrap(value); + result.structValue = value; } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } @@ -388,9 +388,9 @@ export const Value = { } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { return message.boolValue; } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { - return Struct.unwrap(message.structValue as any); + return message.structValue as any; } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return ListValue.unwrap(message.listValue); + return message.listValue; } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { return null; } @@ -453,12 +453,12 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []).map(Value.wrap) }; + return { values: (array ?? []) }; }, unwrap(message: ListValue): Array { if (message?.hasOwnProperty("values") && Array.isArray(message.values)) { - return message.values.map(Value.unwrap); + return message.values; } else { return message as any; } diff --git a/src/generate-struct-wrappers.ts b/src/generate-struct-wrappers.ts new file mode 100644 index 000000000..cf989737f --- /dev/null +++ b/src/generate-struct-wrappers.ts @@ -0,0 +1,295 @@ +import { Context } from "./context"; +import { code, Code } from "ts-poet"; +import { isAnyValueTypeName, isFieldMaskTypeName, isListValueTypeName, isStructTypeName } from "./types"; +import { Options } from "./options"; + +export type StructFieldNames = { + nullValue: string; + numberValue: string; + stringValue: string; + boolValue: string; + structValue: string; + listValue: string; +}; + +/** Whether we need to generate `.wrap` and `.unwrap` methods for the given type. */ +export function isWrapperType(fullProtoTypeName: string): boolean { + return ( + isStructTypeName(fullProtoTypeName) || + isAnyValueTypeName(fullProtoTypeName) || + isListValueTypeName(fullProtoTypeName) || + isFieldMaskTypeName(fullProtoTypeName) + ); +} + +/** + * Converts ts-proto's idiomatic Struct/Value/ListValue representation to the proto messages. + * + * We do this deeply b/c NestJS does not invoke wrappers recursively. + */ +export function generateWrapDeep(ctx: Context, fullProtoTypeName: string, fieldNames: StructFieldNames): Code[] { + const chunks: Code[] = []; + if (isStructTypeName(fullProtoTypeName)) { + let setStatement = "struct.fields[key] = Value.wrap(object[key]);"; + if (ctx.options.useMapType) { + setStatement = "struct.fields.set(key, Value.wrap(object[key]));"; + } + chunks.push(code`wrap(object: {[key: string]: any} | undefined): Struct { + const struct = createBaseStruct(); + if (object !== undefined) { + Object.keys(object).forEach(key => { + ${setStatement} + }); + } + return struct; + }`); + } + + if (isAnyValueTypeName(fullProtoTypeName)) { + // Turn ts-proto representation --> proto representation + chunks.push(code`wrap(value: any): Value { + const result = {} as any; + if (value === null) { + result.${fieldNames.nullValue} = NullValue.NULL_VALUE; + } else if (typeof value === 'boolean') { + result.${fieldNames.boolValue} = value; + } else if (typeof value === 'number') { + result.${fieldNames.numberValue} = value; + } else if (typeof value === 'string') { + result.${fieldNames.stringValue} = value; + } else if (Array.isArray(value)) { + result.${fieldNames.listValue} = ListValue.wrap(value); + } else if (typeof value === 'object') { + result.${fieldNames.structValue} = Struct.wrap(value); + } else if (typeof value !== 'undefined') { + throw new Error('Unsupported any value type: ' + typeof value); + } + return result; + }`); + } + + if (isListValueTypeName(fullProtoTypeName)) { + const maybeReadyOnly = ctx.options.useReadonlyTypes ? "Readonly" : ""; + chunks.push(code`wrap(array: ${maybeReadyOnly}Array | undefined): ListValue { + return { values: (array ?? []).map(Value.wrap) }; + }`); + } + + if (isFieldMaskTypeName(fullProtoTypeName)) { + chunks.push(code`wrap(paths: ${maybeReadonly(ctx.options)} string[]): FieldMask { + const result = createBaseFieldMask()${maybeAsAny(ctx.options)}; + result.paths = paths; + return result; + }`); + } + + return chunks; +} + +/** + * Converts proto's Struct/Value?listValue messages to ts-proto's idiomatic representation. + * + * We do this deeply b/c NestJS does not invoke wrappers recursively. + */ +export function generateUnwrapDeep(ctx: Context, fullProtoTypeName: string, fieldNames: StructFieldNames): Code[] { + const chunks: Code[] = []; + if (isStructTypeName(fullProtoTypeName)) { + if (ctx.options.useMapType) { + chunks.push(code`unwrap(message: Struct): {[key: string]: any} { + const object: { [key: string]: any } = {}; + [...message.fields.keys()].forEach((key) => { + object[key] = Value.unwrap(message.fields.get(key)); + }); + return object; + }`); + } else { + chunks.push(code`unwrap(message: Struct): {[key: string]: any} { + const object: { [key: string]: any } = {}; + if (message.fields) { + Object.keys(message.fields).forEach(key => { + object[key] = Value.unwrap(message.fields[key]); + }); + } + return object; + }`); + } + } + + if (isAnyValueTypeName(fullProtoTypeName)) { + // Put proto encoding into idiomatic ts-proto + chunks.push(code`unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty('${fieldNames.stringValue}') && message.${fieldNames.stringValue} !== undefined) { + return message.${fieldNames.stringValue}; + } else if (message?.hasOwnProperty('${fieldNames.numberValue}') && message?.${fieldNames.numberValue} !== undefined) { + return message.${fieldNames.numberValue}; + } else if (message?.hasOwnProperty('${fieldNames.boolValue}') && message?.${fieldNames.boolValue} !== undefined) { + return message.${fieldNames.boolValue}; + } else if (message?.hasOwnProperty('${fieldNames.structValue}') && message?.${fieldNames.structValue} !== undefined) { + return Struct.unwrap(message.${fieldNames.structValue} as any); + } else if (message?.hasOwnProperty('${fieldNames.listValue}') && message?.${fieldNames.listValue} !== undefined) { + return ListValue.unwrap(message.${fieldNames.listValue}); + } else if (message?.hasOwnProperty('${fieldNames.nullValue}') && message?.${fieldNames.nullValue} !== undefined) { + return null; + } + return undefined; + }`); + } + + if (isListValueTypeName(fullProtoTypeName)) { + chunks.push(code`unwrap(message: ${ctx.options.useReadonlyTypes ? "any" : "ListValue"}): Array { + if (message?.hasOwnProperty('values') && Array.isArray(message.values)) { + return message.values.map(Value.unwrap); + } else { + return message as any; + } + }`); + } + + if (isFieldMaskTypeName(fullProtoTypeName)) { + chunks.push(code`unwrap(message: ${ctx.options.useReadonlyTypes ? "any" : "FieldMask"}): string[] { + return message.paths; + }`); + } + + return chunks; +} + +/** + * Converts ts-proto's idiomatic Struct/Value/ListValue representation to the proto messages. + * + * We do this shallow's b/c ts-proto's encode methods handle the recursion. + */ +export function generateWrapShallow(ctx: Context, fullProtoTypeName: string, fieldNames: StructFieldNames): Code[] { + const chunks: Code[] = []; + if (isStructTypeName(fullProtoTypeName)) { + let setStatement = "struct.fields[key] = object[key];"; + if (ctx.options.useMapType) { + setStatement = "struct.fields.set(key, object[key]);"; + } + chunks.push(code`wrap(object: {[key: string]: any} | undefined): Struct { + const struct = createBaseStruct(); + if (object !== undefined) { + Object.keys(object).forEach(key => { + ${setStatement} + }); + } + return struct; + }`); + } + + if (isAnyValueTypeName(fullProtoTypeName)) { + // Turn ts-proto representation --> proto representation + chunks.push(code`wrap(value: any): Value { + const result = {} as any; + if (value === null) { + result.${fieldNames.nullValue} = NullValue.NULL_VALUE; + } else if (typeof value === 'boolean') { + result.${fieldNames.boolValue} = value; + } else if (typeof value === 'number') { + result.${fieldNames.numberValue} = value; + } else if (typeof value === 'string') { + result.${fieldNames.stringValue} = value; + } else if (Array.isArray(value)) { + result.${fieldNames.listValue} = value; + } else if (typeof value === 'object') { + result.${fieldNames.structValue} = value; + } else if (typeof value !== 'undefined') { + throw new Error('Unsupported any value type: ' + typeof value); + } + return result; + }`); + } + + if (isListValueTypeName(fullProtoTypeName)) { + const maybeReadyOnly = ctx.options.useReadonlyTypes ? "Readonly" : ""; + chunks.push(code`wrap(array: ${maybeReadyOnly}Array | undefined): ListValue { + return { values: (array ?? []) }; + }`); + } + + if (isFieldMaskTypeName(fullProtoTypeName)) { + chunks.push(code`wrap(paths: ${maybeReadonly(ctx.options)} string[]): FieldMask { + const result = createBaseFieldMask()${maybeAsAny(ctx.options)}; + result.paths = paths; + return result; + }`); + } + + return chunks; +} + +/** + * Converts proto's Struct/Value?listValue messages to ts-proto's idiomatic representation. + * + * We do this shallowly b/c ts-proto's decode methods handle recursion. + */ +export function generateUnwrapShallow(ctx: Context, fullProtoTypeName: string, fieldNames: StructFieldNames): Code[] { + const chunks: Code[] = []; + if (isStructTypeName(fullProtoTypeName)) { + if (ctx.options.useMapType) { + chunks.push(code`unwrap(message: Struct): {[key: string]: any} { + const object: { [key: string]: any } = {}; + [...message.fields.keys()].forEach((key) => { + object[key] = message.fields.get(key); + }); + return object; + }`); + } else { + chunks.push(code`unwrap(message: Struct): {[key: string]: any} { + const object: { [key: string]: any } = {}; + if (message.fields) { + Object.keys(message.fields).forEach(key => { + object[key] = message.fields[key]; + }); + } + return object; + }`); + } + } + + if (isAnyValueTypeName(fullProtoTypeName)) { + // Put proto encoding into idiomatic ts-proto + chunks.push(code`unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty('${fieldNames.stringValue}') && message.${fieldNames.stringValue} !== undefined) { + return message.${fieldNames.stringValue}; + } else if (message?.hasOwnProperty('${fieldNames.numberValue}') && message?.${fieldNames.numberValue} !== undefined) { + return message.${fieldNames.numberValue}; + } else if (message?.hasOwnProperty('${fieldNames.boolValue}') && message?.${fieldNames.boolValue} !== undefined) { + return message.${fieldNames.boolValue}; + } else if (message?.hasOwnProperty('${fieldNames.structValue}') && message?.${fieldNames.structValue} !== undefined) { + return message.${fieldNames.structValue} as any; + } else if (message?.hasOwnProperty('${fieldNames.listValue}') && message?.${fieldNames.listValue} !== undefined) { + return message.${fieldNames.listValue}; + } else if (message?.hasOwnProperty('${fieldNames.nullValue}') && message?.${fieldNames.nullValue} !== undefined) { + return null; + } + return undefined; + }`); + } + + if (isListValueTypeName(fullProtoTypeName)) { + chunks.push(code`unwrap(message: ${ctx.options.useReadonlyTypes ? "any" : "ListValue"}): Array { + if (message?.hasOwnProperty('values') && Array.isArray(message.values)) { + return message.values; + } else { + return message as any; + } + }`); + } + + if (isFieldMaskTypeName(fullProtoTypeName)) { + chunks.push(code`unwrap(message: ${ctx.options.useReadonlyTypes ? "any" : "FieldMask"}): string[] { + return message.paths; + }`); + } + + return chunks; +} + +function maybeReadonly(options: Options): string { + return options.useReadonlyTypes ? "readonly " : ""; +} + +function maybeAsAny(options: Options): string { + return options.useReadonlyTypes ? " as any" : ""; +} diff --git a/src/main.ts b/src/main.ts index 5e17907b5..2bcabc23b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -78,6 +78,15 @@ import { ConditionalOutput } from "ts-poet/build/ConditionalOutput"; import { generateGrpcJsService } from "./generate-grpc-js"; import { generateGenericServiceDefinition } from "./generate-generic-service-definition"; import { generateNiceGrpcService } from "./generate-nice-grpc"; +import { + generateUnwrap, + generateUnwrapDeep, + generateUnwrapShallow, + generateWrap, + generateWrapDeep, + generateWrapShallow, + isWrapperType, +} from "./generate-struct-wrappers"; export function generateFile(ctx: Context, fileDesc: FileDescriptorProto): [string, Code] { const { options, utils } = ctx; @@ -203,8 +212,13 @@ export function generateFile(ctx: Context, fileDesc: FileDescriptorProto): [stri structValue: maybeSnakeToCamel("struct_value", ctx.options), listValue: maybeSnakeToCamel("list_value", ctx.options), }; - staticMembers.push(...generateWrap(ctx, fullTypeName, structFieldNames)); - staticMembers.push(...generateUnwrap(ctx, fullTypeName, structFieldNames)); + if (options.nestJs) { + staticMembers.push(...generateWrapDeep(ctx, fullTypeName, structFieldNames)); + staticMembers.push(...generateUnwrapDeep(ctx, fullTypeName, structFieldNames)); + } else { + staticMembers.push(...generateWrapShallow(ctx, fullTypeName, structFieldNames)); + staticMembers.push(...generateUnwrapShallow(ctx, fullTypeName, structFieldNames)); + } if (staticMembers.length > 0) { chunks.push(code` @@ -1783,147 +1797,6 @@ function generateFromPartial(ctx: Context, fullName: string, messageDesc: Descri return joinCode(chunks, { on: "\n" }); } -type StructFieldNames = { - nullValue: string; - numberValue: string; - stringValue: string; - boolValue: string; - structValue: string; - listValue: string; -}; - -/** Whether we need to generate `.wrap` and `.unwrap` methods for the given type. */ -function isWrapperType(fullProtoTypeName: string): boolean { - return ( - isStructTypeName(fullProtoTypeName) || - isAnyValueTypeName(fullProtoTypeName) || - isListValueTypeName(fullProtoTypeName) || - isFieldMaskTypeName(fullProtoTypeName) - ); -} - -function generateWrap(ctx: Context, fullProtoTypeName: string, fieldNames: StructFieldNames): Code[] { - const chunks: Code[] = []; - if (isStructTypeName(fullProtoTypeName)) { - let setStatement = "struct.fields[key] = Value.wrap(object[key]);"; - if (ctx.options.useMapType) { - setStatement = "struct.fields.set(key, Value.wrap(object[key]));"; - } - chunks.push(code`wrap(object: {[key: string]: any} | undefined): Struct { - const struct = createBaseStruct(); - if (object !== undefined) { - Object.keys(object).forEach(key => { - ${setStatement} - }); - } - return struct; - }`); - } - - if (isAnyValueTypeName(fullProtoTypeName)) { - // Turn ts-proto representation --> proto representation - chunks.push(code`wrap(value: any): Value { - const result = {} as any; - if (value === null) { - result.${fieldNames.nullValue} = NullValue.NULL_VALUE; - } else if (typeof value === 'boolean') { - result.${fieldNames.boolValue} = value; - } else if (typeof value === 'number') { - result.${fieldNames.numberValue} = value; - } else if (typeof value === 'string') { - result.${fieldNames.stringValue} = value; - } else if (Array.isArray(value)) { - result.${fieldNames.listValue} = ListValue.wrap(value); - } else if (typeof value === 'object') { - result.${fieldNames.structValue} = Struct.wrap(value); - } else if (typeof value !== 'undefined') { - throw new Error('Unsupported any value type: ' + typeof value); - } - return result; - }`); - } - - if (isListValueTypeName(fullProtoTypeName)) { - const maybeReadyOnly = ctx.options.useReadonlyTypes ? "Readonly" : ""; - chunks.push(code`wrap(array: ${maybeReadyOnly}Array | undefined): ListValue { - return { values: (array ?? []).map(Value.wrap) }; - }`); - } - - if (isFieldMaskTypeName(fullProtoTypeName)) { - chunks.push(code`wrap(paths: ${maybeReadonly(ctx.options)} string[]): FieldMask { - const result = createBaseFieldMask()${maybeAsAny(ctx.options)}; - result.paths = paths; - return result; - }`); - } - - return chunks; -} - -function generateUnwrap(ctx: Context, fullProtoTypeName: string, fieldNames: StructFieldNames): Code[] { - const chunks: Code[] = []; - if (isStructTypeName(fullProtoTypeName)) { - if (ctx.options.useMapType) { - chunks.push(code`unwrap(message: Struct): {[key: string]: any} { - const object: { [key: string]: any } = {}; - [...message.fields.keys()].forEach((key) => { - object[key] = Value.unwrap(message.fields.get(key)); - }); - return object; - }`); - } else { - chunks.push(code`unwrap(message: Struct): {[key: string]: any} { - const object: { [key: string]: any } = {}; - if (message.fields) { - Object.keys(message.fields).forEach(key => { - object[key] = Value.unwrap(message.fields[key]); - }); - } - return object; - }`); - } - } - - if (isAnyValueTypeName(fullProtoTypeName)) { - // Put proto encoding into idiomatic ts-proto - chunks.push(code`unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty('${fieldNames.stringValue}') && message.${fieldNames.stringValue} !== undefined) { - return message.${fieldNames.stringValue}; - } else if (message?.hasOwnProperty('${fieldNames.numberValue}') && message?.${fieldNames.numberValue} !== undefined) { - return message.${fieldNames.numberValue}; - } else if (message?.hasOwnProperty('${fieldNames.boolValue}') && message?.${fieldNames.boolValue} !== undefined) { - return message.${fieldNames.boolValue}; - } else if (message?.hasOwnProperty('${fieldNames.structValue}') && message?.${fieldNames.structValue} !== undefined) { - return Struct.unwrap(message.${fieldNames.structValue} as any); - } else if (message?.hasOwnProperty('${fieldNames.listValue}') && message?.${fieldNames.listValue} !== undefined) { - return ListValue.unwrap(message.${fieldNames.listValue}); - } else if (message?.hasOwnProperty('${fieldNames.nullValue}') && message?.${fieldNames.nullValue} !== undefined) { - return null; - } - return undefined; - }`); - } - - if (isListValueTypeName(fullProtoTypeName)) { - chunks.push(code`unwrap(message: ${ctx.options.useReadonlyTypes ? "any" : "ListValue"}): Array { - if (message?.hasOwnProperty('values') && Array.isArray(message.values)) { - return message.values.map(Value.unwrap); - } else { - return message as any; - } - }`); - } - - if (isFieldMaskTypeName(fullProtoTypeName)) { - chunks.push(code`unwrap(message: ${ctx.options.useReadonlyTypes ? "any" : "FieldMask"}): string[] { - return message.paths; - }`); - } - - return chunks; -} - export const contextTypeVar = "Context extends DataLoaders"; function maybeCastToNumber( From ffb21dc32f1916269cdf707710e35c687c182e47 Mon Sep 17 00:00:00 2001 From: Stephen Haberman Date: Mon, 30 Jan 2023 19:49:26 -0600 Subject: [PATCH 9/9] Fix oneofs. --- integration/grpc-js/google/protobuf/struct.ts | 18 +-- .../nestjs-simple/google/protobuf/struct.ts | 4 +- .../nice-grpc/google/protobuf/struct.ts | 18 +-- .../google/protobuf/struct.ts | 45 ++++--- .../oneof-unions/google/protobuf/struct.ts | 45 ++++--- .../simple-snake/google/protobuf/struct.ts | 18 +-- .../google/protobuf/struct.ts | 18 +-- integration/struct/google/protobuf/struct.ts | 18 +-- .../type-registry/google/protobuf/struct.ts | 18 +-- .../use-map-type/google/protobuf/struct.ts | 18 +-- .../google/protobuf/struct.ts | 18 +-- .../google/protobuf/struct.ts | 45 ++++--- integration/value/google/protobuf/struct.ts | 18 +-- src/generate-struct-wrappers.ts | 126 ++++++++++++------ 14 files changed, 251 insertions(+), 176 deletions(-) diff --git a/integration/grpc-js/google/protobuf/struct.ts b/integration/grpc-js/google/protobuf/struct.ts index 40dad0b5e..cc3f1bebd 100644 --- a/integration/grpc-js/google/protobuf/struct.ts +++ b/integration/grpc-js/google/protobuf/struct.ts @@ -361,7 +361,7 @@ export const Value = { }, wrap(value: any): Value { - const result = {} as any; + const result = createBaseValue(); if (value === null) { result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -381,17 +381,17 @@ export const Value = { }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { + if (message.stringValue !== undefined) { return message.stringValue; - } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { + } else if (message?.numberValue !== undefined) { return message.numberValue; - } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { + } else if (message?.boolValue !== undefined) { return message.boolValue; - } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + } else if (message?.structValue !== undefined) { return message.structValue as any; - } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { + } else if (message?.listValue !== undefined) { return message.listValue; - } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { + } else if (message?.nullValue !== undefined) { return null; } return undefined; @@ -453,7 +453,9 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []) }; + const result = createBaseListValue(); + result.values = array ?? []; + return result; }, unwrap(message: ListValue): Array { diff --git a/integration/nestjs-simple/google/protobuf/struct.ts b/integration/nestjs-simple/google/protobuf/struct.ts index 44aaaf4dc..d9ae0e11d 100644 --- a/integration/nestjs-simple/google/protobuf/struct.ts +++ b/integration/nestjs-simple/google/protobuf/struct.ts @@ -155,7 +155,9 @@ function createBaseListValue(): ListValue { export const ListValue = { wrap(array: Array | undefined): ListValue { - return { values: (array ?? []).map(Value.wrap) }; + const result = createBaseListValue(); + result.values = (array ?? []).map(Value.wrap); + return result; }, unwrap(message: ListValue): Array { diff --git a/integration/nice-grpc/google/protobuf/struct.ts b/integration/nice-grpc/google/protobuf/struct.ts index 23cf0d31d..8a5a6a439 100644 --- a/integration/nice-grpc/google/protobuf/struct.ts +++ b/integration/nice-grpc/google/protobuf/struct.ts @@ -361,7 +361,7 @@ export const Value = { }, wrap(value: any): Value { - const result = {} as any; + const result = createBaseValue(); if (value === null) { result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -381,17 +381,17 @@ export const Value = { }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { + if (message.stringValue !== undefined) { return message.stringValue; - } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { + } else if (message?.numberValue !== undefined) { return message.numberValue; - } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { + } else if (message?.boolValue !== undefined) { return message.boolValue; - } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + } else if (message?.structValue !== undefined) { return message.structValue as any; - } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { + } else if (message?.listValue !== undefined) { return message.listValue; - } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { + } else if (message?.nullValue !== undefined) { return null; } return undefined; @@ -453,7 +453,9 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []) }; + const result = createBaseListValue(); + result.values = array ?? []; + return result; }, unwrap(message: ListValue): Array { diff --git a/integration/oneof-unions-snake/google/protobuf/struct.ts b/integration/oneof-unions-snake/google/protobuf/struct.ts index bedc7ef90..1cf3d7cc5 100644 --- a/integration/oneof-unions-snake/google/protobuf/struct.ts +++ b/integration/oneof-unions-snake/google/protobuf/struct.ts @@ -379,40 +379,41 @@ export const Value = { }, wrap(value: any): Value { - const result = {} as any; + const result = createBaseValue(); if (value === null) { - result.null_value = NullValue.NULL_VALUE; + result.kind = { $case: "null_value", null_value: NullValue.NULL_VALUE }; } else if (typeof value === "boolean") { - result.bool_value = value; + result.kind = { $case: "bool_value", bool_value: value }; } else if (typeof value === "number") { - result.number_value = value; + result.kind = { $case: "number_value", number_value: value }; } else if (typeof value === "string") { - result.string_value = value; + result.kind = { $case: "string_value", string_value: value }; } else if (Array.isArray(value)) { - result.list_value = value; + result.kind = { $case: "list_value", list_value: value }; } else if (typeof value === "object") { - result.struct_value = value; + result.kind = { $case: "struct_value", struct_value: value }; } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } return result; }, - unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("string_value") && message.string_value !== undefined) { - return message.string_value; - } else if (message?.hasOwnProperty("number_value") && message?.number_value !== undefined) { - return message.number_value; - } else if (message?.hasOwnProperty("bool_value") && message?.bool_value !== undefined) { - return message.bool_value; - } else if (message?.hasOwnProperty("struct_value") && message?.struct_value !== undefined) { - return message.struct_value as any; - } else if (message?.hasOwnProperty("list_value") && message?.list_value !== undefined) { - return message.list_value; - } else if (message?.hasOwnProperty("null_value") && message?.null_value !== undefined) { + unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { + if (message.kind?.$case === "null_value") { return null; + } else if (message.kind?.$case === "number_value") { + return message.kind?.number_value; + } else if (message.kind?.$case === "string_value") { + return message.kind?.string_value; + } else if (message.kind?.$case === "bool_value") { + return message.kind?.bool_value; + } else if (message.kind?.$case === "struct_value") { + return message.kind?.struct_value; + } else if (message.kind?.$case === "list_value") { + return message.kind?.list_value; + } else { + return undefined; } - return undefined; }, }; @@ -471,7 +472,9 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []) }; + const result = createBaseListValue(); + result.values = array ?? []; + return result; }, unwrap(message: ListValue): Array { diff --git a/integration/oneof-unions/google/protobuf/struct.ts b/integration/oneof-unions/google/protobuf/struct.ts index 014c90c41..c135f74d2 100644 --- a/integration/oneof-unions/google/protobuf/struct.ts +++ b/integration/oneof-unions/google/protobuf/struct.ts @@ -370,40 +370,41 @@ export const Value = { }, wrap(value: any): Value { - const result = {} as any; + const result = createBaseValue(); if (value === null) { - result.nullValue = NullValue.NULL_VALUE; + result.kind = { $case: "nullValue", nullValue: NullValue.NULL_VALUE }; } else if (typeof value === "boolean") { - result.boolValue = value; + result.kind = { $case: "boolValue", boolValue: value }; } else if (typeof value === "number") { - result.numberValue = value; + result.kind = { $case: "numberValue", numberValue: value }; } else if (typeof value === "string") { - result.stringValue = value; + result.kind = { $case: "stringValue", stringValue: value }; } else if (Array.isArray(value)) { - result.listValue = value; + result.kind = { $case: "listValue", listValue: value }; } else if (typeof value === "object") { - result.structValue = value; + result.kind = { $case: "structValue", structValue: value }; } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } return result; }, - unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { - return message.stringValue; - } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { - return message.numberValue; - } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { - return message.boolValue; - } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { - return message.structValue as any; - } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return message.listValue; - } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { + unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { + if (message.kind?.$case === "nullValue") { return null; + } else if (message.kind?.$case === "numberValue") { + return message.kind?.numberValue; + } else if (message.kind?.$case === "stringValue") { + return message.kind?.stringValue; + } else if (message.kind?.$case === "boolValue") { + return message.kind?.boolValue; + } else if (message.kind?.$case === "structValue") { + return message.kind?.structValue; + } else if (message.kind?.$case === "listValue") { + return message.kind?.listValue; + } else { + return undefined; } - return undefined; }, }; @@ -462,7 +463,9 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []) }; + const result = createBaseListValue(); + result.values = array ?? []; + return result; }, unwrap(message: ListValue): Array { diff --git a/integration/simple-snake/google/protobuf/struct.ts b/integration/simple-snake/google/protobuf/struct.ts index 8d360819f..4dbdbd8a4 100644 --- a/integration/simple-snake/google/protobuf/struct.ts +++ b/integration/simple-snake/google/protobuf/struct.ts @@ -361,7 +361,7 @@ export const Value = { }, wrap(value: any): Value { - const result = {} as any; + const result = createBaseValue(); if (value === null) { result.null_value = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -381,17 +381,17 @@ export const Value = { }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("string_value") && message.string_value !== undefined) { + if (message.string_value !== undefined) { return message.string_value; - } else if (message?.hasOwnProperty("number_value") && message?.number_value !== undefined) { + } else if (message?.number_value !== undefined) { return message.number_value; - } else if (message?.hasOwnProperty("bool_value") && message?.bool_value !== undefined) { + } else if (message?.bool_value !== undefined) { return message.bool_value; - } else if (message?.hasOwnProperty("struct_value") && message?.struct_value !== undefined) { + } else if (message?.struct_value !== undefined) { return message.struct_value as any; - } else if (message?.hasOwnProperty("list_value") && message?.list_value !== undefined) { + } else if (message?.list_value !== undefined) { return message.list_value; - } else if (message?.hasOwnProperty("null_value") && message?.null_value !== undefined) { + } else if (message?.null_value !== undefined) { return null; } return undefined; @@ -453,7 +453,9 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []) }; + const result = createBaseListValue(); + result.values = array ?? []; + return result; }, unwrap(message: ListValue): Array { diff --git a/integration/simple-string-enums/google/protobuf/struct.ts b/integration/simple-string-enums/google/protobuf/struct.ts index 55f74d501..09cb4ca9b 100644 --- a/integration/simple-string-enums/google/protobuf/struct.ts +++ b/integration/simple-string-enums/google/protobuf/struct.ts @@ -371,7 +371,7 @@ export const Value = { }, wrap(value: any): Value { - const result = {} as any; + const result = createBaseValue(); if (value === null) { result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -391,17 +391,17 @@ export const Value = { }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { + if (message.stringValue !== undefined) { return message.stringValue; - } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { + } else if (message?.numberValue !== undefined) { return message.numberValue; - } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { + } else if (message?.boolValue !== undefined) { return message.boolValue; - } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + } else if (message?.structValue !== undefined) { return message.structValue as any; - } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { + } else if (message?.listValue !== undefined) { return message.listValue; - } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { + } else if (message?.nullValue !== undefined) { return null; } return undefined; @@ -463,7 +463,9 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []) }; + const result = createBaseListValue(); + result.values = array ?? []; + return result; }, unwrap(message: ListValue): Array { diff --git a/integration/struct/google/protobuf/struct.ts b/integration/struct/google/protobuf/struct.ts index 40dad0b5e..cc3f1bebd 100644 --- a/integration/struct/google/protobuf/struct.ts +++ b/integration/struct/google/protobuf/struct.ts @@ -361,7 +361,7 @@ export const Value = { }, wrap(value: any): Value { - const result = {} as any; + const result = createBaseValue(); if (value === null) { result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -381,17 +381,17 @@ export const Value = { }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { + if (message.stringValue !== undefined) { return message.stringValue; - } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { + } else if (message?.numberValue !== undefined) { return message.numberValue; - } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { + } else if (message?.boolValue !== undefined) { return message.boolValue; - } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + } else if (message?.structValue !== undefined) { return message.structValue as any; - } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { + } else if (message?.listValue !== undefined) { return message.listValue; - } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { + } else if (message?.nullValue !== undefined) { return null; } return undefined; @@ -453,7 +453,9 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []) }; + const result = createBaseListValue(); + result.values = array ?? []; + return result; }, unwrap(message: ListValue): Array { diff --git a/integration/type-registry/google/protobuf/struct.ts b/integration/type-registry/google/protobuf/struct.ts index 9fbad3cf0..4eb87ba66 100644 --- a/integration/type-registry/google/protobuf/struct.ts +++ b/integration/type-registry/google/protobuf/struct.ts @@ -386,7 +386,7 @@ export const Value = { }, wrap(value: any): Value { - const result = {} as any; + const result = createBaseValue(); if (value === null) { result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -406,17 +406,17 @@ export const Value = { }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { + if (message.stringValue !== undefined) { return message.stringValue; - } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { + } else if (message?.numberValue !== undefined) { return message.numberValue; - } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { + } else if (message?.boolValue !== undefined) { return message.boolValue; - } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + } else if (message?.structValue !== undefined) { return message.structValue as any; - } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { + } else if (message?.listValue !== undefined) { return message.listValue; - } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { + } else if (message?.nullValue !== undefined) { return null; } return undefined; @@ -482,7 +482,9 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []) }; + const result = createBaseListValue(); + result.values = array ?? []; + return result; }, unwrap(message: ListValue): Array { diff --git a/integration/use-map-type/google/protobuf/struct.ts b/integration/use-map-type/google/protobuf/struct.ts index 855f4e6a1..ffcb6b973 100644 --- a/integration/use-map-type/google/protobuf/struct.ts +++ b/integration/use-map-type/google/protobuf/struct.ts @@ -359,7 +359,7 @@ export const Value = { }, wrap(value: any): Value { - const result = {} as any; + const result = createBaseValue(); if (value === null) { result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -379,17 +379,17 @@ export const Value = { }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { + if (message.stringValue !== undefined) { return message.stringValue; - } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { + } else if (message?.numberValue !== undefined) { return message.numberValue; - } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { + } else if (message?.boolValue !== undefined) { return message.boolValue; - } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + } else if (message?.structValue !== undefined) { return message.structValue as any; - } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { + } else if (message?.listValue !== undefined) { return message.listValue; - } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { + } else if (message?.nullValue !== undefined) { return null; } return undefined; @@ -451,7 +451,9 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []) }; + const result = createBaseListValue(); + result.values = array ?? []; + return result; }, unwrap(message: ListValue): Array { diff --git a/integration/use-numeric-enum-json/google/protobuf/struct.ts b/integration/use-numeric-enum-json/google/protobuf/struct.ts index 06599f4b2..78ae9698f 100644 --- a/integration/use-numeric-enum-json/google/protobuf/struct.ts +++ b/integration/use-numeric-enum-json/google/protobuf/struct.ts @@ -361,7 +361,7 @@ export const Value = { }, wrap(value: any): Value { - const result = {} as any; + const result = createBaseValue(); if (value === null) { result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -381,17 +381,17 @@ export const Value = { }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { + if (message.stringValue !== undefined) { return message.stringValue; - } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { + } else if (message?.numberValue !== undefined) { return message.numberValue; - } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { + } else if (message?.boolValue !== undefined) { return message.boolValue; - } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + } else if (message?.structValue !== undefined) { return message.structValue as any; - } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { + } else if (message?.listValue !== undefined) { return message.listValue; - } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { + } else if (message?.nullValue !== undefined) { return null; } return undefined; @@ -453,7 +453,9 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []) }; + const result = createBaseListValue(); + result.values = array ?? []; + return result; }, unwrap(message: ListValue): Array { diff --git a/integration/use-readonly-types/google/protobuf/struct.ts b/integration/use-readonly-types/google/protobuf/struct.ts index 409e38cbc..42c77fe9f 100644 --- a/integration/use-readonly-types/google/protobuf/struct.ts +++ b/integration/use-readonly-types/google/protobuf/struct.ts @@ -370,40 +370,41 @@ export const Value = { }, wrap(value: any): Value { - const result = {} as any; + const result = createBaseValue() as any; if (value === null) { - result.nullValue = NullValue.NULL_VALUE; + result.kind = { $case: "nullValue", nullValue: NullValue.NULL_VALUE }; } else if (typeof value === "boolean") { - result.boolValue = value; + result.kind = { $case: "boolValue", boolValue: value }; } else if (typeof value === "number") { - result.numberValue = value; + result.kind = { $case: "numberValue", numberValue: value }; } else if (typeof value === "string") { - result.stringValue = value; + result.kind = { $case: "stringValue", stringValue: value }; } else if (Array.isArray(value)) { - result.listValue = value; + result.kind = { $case: "listValue", listValue: value }; } else if (typeof value === "object") { - result.structValue = value; + result.kind = { $case: "structValue", structValue: value }; } else if (typeof value !== "undefined") { throw new Error("Unsupported any value type: " + typeof value); } return result; }, - unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { - return message.stringValue; - } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { - return message.numberValue; - } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { - return message.boolValue; - } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { - return message.structValue as any; - } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { - return message.listValue; - } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { + unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { + if (message.kind?.$case === "nullValue") { return null; + } else if (message.kind?.$case === "numberValue") { + return message.kind?.numberValue; + } else if (message.kind?.$case === "stringValue") { + return message.kind?.stringValue; + } else if (message.kind?.$case === "boolValue") { + return message.kind?.boolValue; + } else if (message.kind?.$case === "structValue") { + return message.kind?.structValue; + } else if (message.kind?.$case === "listValue") { + return message.kind?.listValue; + } else { + return undefined; } - return undefined; }, }; @@ -462,7 +463,9 @@ export const ListValue = { }, wrap(array: ReadonlyArray | undefined): ListValue { - return { values: (array ?? []) }; + const result = createBaseListValue() as any; + result.values = array ?? []; + return result; }, unwrap(message: any): Array { diff --git a/integration/value/google/protobuf/struct.ts b/integration/value/google/protobuf/struct.ts index 40dad0b5e..cc3f1bebd 100644 --- a/integration/value/google/protobuf/struct.ts +++ b/integration/value/google/protobuf/struct.ts @@ -361,7 +361,7 @@ export const Value = { }, wrap(value: any): Value { - const result = {} as any; + const result = createBaseValue(); if (value === null) { result.nullValue = NullValue.NULL_VALUE; } else if (typeof value === "boolean") { @@ -381,17 +381,17 @@ export const Value = { }, unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { + if (message.stringValue !== undefined) { return message.stringValue; - } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { + } else if (message?.numberValue !== undefined) { return message.numberValue; - } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { + } else if (message?.boolValue !== undefined) { return message.boolValue; - } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + } else if (message?.structValue !== undefined) { return message.structValue as any; - } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { + } else if (message?.listValue !== undefined) { return message.listValue; - } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { + } else if (message?.nullValue !== undefined) { return null; } return undefined; @@ -453,7 +453,9 @@ export const ListValue = { }, wrap(array: Array | undefined): ListValue { - return { values: (array ?? []) }; + const result = createBaseListValue(); + result.values = array ?? []; + return result; }, unwrap(message: ListValue): Array { diff --git a/src/generate-struct-wrappers.ts b/src/generate-struct-wrappers.ts index cf989737f..1a6dbbb6e 100644 --- a/src/generate-struct-wrappers.ts +++ b/src/generate-struct-wrappers.ts @@ -1,7 +1,7 @@ import { Context } from "./context"; import { code, Code } from "ts-poet"; import { isAnyValueTypeName, isFieldMaskTypeName, isListValueTypeName, isStructTypeName } from "./types"; -import { Options } from "./options"; +import { OneofOption, Options } from "./options"; export type StructFieldNames = { nullValue: string; @@ -71,7 +71,9 @@ export function generateWrapDeep(ctx: Context, fullProtoTypeName: string, fieldN if (isListValueTypeName(fullProtoTypeName)) { const maybeReadyOnly = ctx.options.useReadonlyTypes ? "Readonly" : ""; chunks.push(code`wrap(array: ${maybeReadyOnly}Array | undefined): ListValue { - return { values: (array ?? []).map(Value.wrap) }; + const result = createBaseListValue()${maybeAsAny(ctx.options)}; + result.values = (array ?? []).map(Value.wrap); + return result; }`); } @@ -116,7 +118,9 @@ export function generateUnwrapDeep(ctx: Context, fullProtoTypeName: string, fiel } if (isAnyValueTypeName(fullProtoTypeName)) { - // Put proto encoding into idiomatic ts-proto + // We check hasOwnProperty because the incoming `message` has been serde-ing + // by the NestJS/protobufjs runtime, and so has a base class with default values + // that throw off the simpler checks we do in generateUnwrapShallow chunks.push(code`unwrap(message: any): string | number | boolean | Object | null | Array | undefined { if (message?.hasOwnProperty('${fieldNames.stringValue}') && message.${fieldNames.stringValue} !== undefined) { return message.${fieldNames.stringValue}; @@ -178,32 +182,55 @@ export function generateWrapShallow(ctx: Context, fullProtoTypeName: string, fie } if (isAnyValueTypeName(fullProtoTypeName)) { - // Turn ts-proto representation --> proto representation - chunks.push(code`wrap(value: any): Value { - const result = {} as any; - if (value === null) { - result.${fieldNames.nullValue} = NullValue.NULL_VALUE; - } else if (typeof value === 'boolean') { - result.${fieldNames.boolValue} = value; - } else if (typeof value === 'number') { - result.${fieldNames.numberValue} = value; - } else if (typeof value === 'string') { - result.${fieldNames.stringValue} = value; - } else if (Array.isArray(value)) { - result.${fieldNames.listValue} = value; - } else if (typeof value === 'object') { - result.${fieldNames.structValue} = value; - } else if (typeof value !== 'undefined') { - throw new Error('Unsupported any value type: ' + typeof value); - } - return result; + if (ctx.options.oneof === OneofOption.UNIONS) { + chunks.push(code`wrap(value: any): Value { + const result = createBaseValue()${maybeAsAny(ctx.options)}; + if (value === null) { + result.kind = {$case: '${fieldNames.nullValue}', ${fieldNames.nullValue}: NullValue.NULL_VALUE}; + } else if (typeof value === 'boolean') { + result.kind = {$case: '${fieldNames.boolValue}', ${fieldNames.boolValue}: value}; + } else if (typeof value === 'number') { + result.kind = {$case: '${fieldNames.numberValue}', ${fieldNames.numberValue}: value}; + } else if (typeof value === 'string') { + result.kind = {$case: '${fieldNames.stringValue}', ${fieldNames.stringValue}: value}; + } else if (Array.isArray(value)) { + result.kind = {$case: '${fieldNames.listValue}', ${fieldNames.listValue}: value}; + } else if (typeof value === 'object') { + result.kind = {$case: '${fieldNames.structValue}', ${fieldNames.structValue}: value}; + } else if (typeof value !== 'undefined') { + throw new Error('Unsupported any value type: ' + typeof value); + } + return result; }`); + } else { + chunks.push(code`wrap(value: any): Value { + const result = createBaseValue()${maybeAsAny(ctx.options)}; + if (value === null) { + result.${fieldNames.nullValue} = NullValue.NULL_VALUE; + } else if (typeof value === 'boolean') { + result.${fieldNames.boolValue} = value; + } else if (typeof value === 'number') { + result.${fieldNames.numberValue} = value; + } else if (typeof value === 'string') { + result.${fieldNames.stringValue} = value; + } else if (Array.isArray(value)) { + result.${fieldNames.listValue} = value; + } else if (typeof value === 'object') { + result.${fieldNames.structValue} = value; + } else if (typeof value !== 'undefined') { + throw new Error('Unsupported any value type: ' + typeof value); + } + return result; + }`); + } } if (isListValueTypeName(fullProtoTypeName)) { const maybeReadyOnly = ctx.options.useReadonlyTypes ? "Readonly" : ""; chunks.push(code`wrap(array: ${maybeReadyOnly}Array | undefined): ListValue { - return { values: (array ?? []) }; + const result = createBaseListValue()${maybeAsAny(ctx.options)}; + result.values = array ?? []; + return result; }`); } @@ -248,23 +275,42 @@ export function generateUnwrapShallow(ctx: Context, fullProtoTypeName: string, f } if (isAnyValueTypeName(fullProtoTypeName)) { - // Put proto encoding into idiomatic ts-proto - chunks.push(code`unwrap(message: any): string | number | boolean | Object | null | Array | undefined { - if (message?.hasOwnProperty('${fieldNames.stringValue}') && message.${fieldNames.stringValue} !== undefined) { - return message.${fieldNames.stringValue}; - } else if (message?.hasOwnProperty('${fieldNames.numberValue}') && message?.${fieldNames.numberValue} !== undefined) { - return message.${fieldNames.numberValue}; - } else if (message?.hasOwnProperty('${fieldNames.boolValue}') && message?.${fieldNames.boolValue} !== undefined) { - return message.${fieldNames.boolValue}; - } else if (message?.hasOwnProperty('${fieldNames.structValue}') && message?.${fieldNames.structValue} !== undefined) { - return message.${fieldNames.structValue} as any; - } else if (message?.hasOwnProperty('${fieldNames.listValue}') && message?.${fieldNames.listValue} !== undefined) { - return message.${fieldNames.listValue}; - } else if (message?.hasOwnProperty('${fieldNames.nullValue}') && message?.${fieldNames.nullValue} !== undefined) { - return null; - } - return undefined; - }`); + if (ctx.options.oneof === OneofOption.UNIONS) { + chunks.push(code`unwrap(message: Value): string | number | boolean | Object | null | Array | undefined { + if (message.kind?.$case === '${fieldNames.nullValue}') { + return null; + } else if (message.kind?.$case === '${fieldNames.numberValue}') { + return message.kind?.${fieldNames.numberValue}; + } else if (message.kind?.$case === '${fieldNames.stringValue}') { + return message.kind?.${fieldNames.stringValue}; + } else if (message.kind?.$case === '${fieldNames.boolValue}') { + return message.kind?.${fieldNames.boolValue}; + } else if (message.kind?.$case === '${fieldNames.structValue}') { + return message.kind?.${fieldNames.structValue}; + } else if (message.kind?.$case === '${fieldNames.listValue}') { + return message.kind?.${fieldNames.listValue}; + } else { + return undefined; + } + }`); + } else { + chunks.push(code`unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message.${fieldNames.stringValue} !== undefined) { + return message.${fieldNames.stringValue}; + } else if (message?.${fieldNames.numberValue} !== undefined) { + return message.${fieldNames.numberValue}; + } else if (message?.${fieldNames.boolValue} !== undefined) { + return message.${fieldNames.boolValue}; + } else if (message?.${fieldNames.structValue} !== undefined) { + return message.${fieldNames.structValue} as any; + } else if (message?.${fieldNames.listValue} !== undefined) { + return message.${fieldNames.listValue}; + } else if (message?.${fieldNames.nullValue} !== undefined) { + return null; + } + return undefined; + }`); + } } if (isListValueTypeName(fullProtoTypeName)) {