Skip to content

Commit 594b137

Browse files
authoredAug 15, 2023
fix: enum default value when remove-enum-prefix and string-enum both on (#902)
1 parent 2639818 commit 594b137

7 files changed

+255
-5
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
removeEnumPrefix=true,stringEnums=true,unrecognizedEnum=false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { EnumFields, Foo, Bar } from "./remove-enum-prefix-string-enums";
2+
3+
describe("nestjs-metadata-test", () => {
4+
it("compiles", () => {
5+
const msg: EnumFields = {
6+
foo: Foo.BAR,
7+
bar: Bar.BAZ,
8+
};
9+
const out = EnumFields.toJSON(msg);
10+
expect(out).not.toBeUndefined();
11+
});
12+
});
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
syntax = "proto3";
2+
3+
enum Foo {
4+
FOO_UNSPECIFIED = 0;
5+
FOO_BAR = 1;
6+
FOO_BAZ = 2;
7+
}
8+
9+
enum Bar {
10+
BAR_UNSPECIFIED = 0;
11+
BAZ = 1;
12+
QUX = 2;
13+
}
14+
15+
message EnumFields {
16+
Foo foo = 1;
17+
Bar bar = 2;
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
/* eslint-disable */
2+
import * as _m0 from "protobufjs/minimal";
3+
4+
export const protobufPackage = "";
5+
6+
export enum Foo {
7+
UNSPECIFIED = "FOO_UNSPECIFIED",
8+
BAR = "FOO_BAR",
9+
BAZ = "FOO_BAZ",
10+
}
11+
12+
export function fooFromJSON(object: any): Foo {
13+
switch (object) {
14+
case 0:
15+
case "FOO_UNSPECIFIED":
16+
return Foo.UNSPECIFIED;
17+
case 1:
18+
case "FOO_BAR":
19+
return Foo.BAR;
20+
case 2:
21+
case "FOO_BAZ":
22+
return Foo.BAZ;
23+
default:
24+
throw new tsProtoGlobalThis.Error("Unrecognized enum value " + object + " for enum Foo");
25+
}
26+
}
27+
28+
export function fooToJSON(object: Foo): string {
29+
switch (object) {
30+
case Foo.UNSPECIFIED:
31+
return "FOO_UNSPECIFIED";
32+
case Foo.BAR:
33+
return "FOO_BAR";
34+
case Foo.BAZ:
35+
return "FOO_BAZ";
36+
default:
37+
throw new tsProtoGlobalThis.Error("Unrecognized enum value " + object + " for enum Foo");
38+
}
39+
}
40+
41+
export function fooToNumber(object: Foo): number {
42+
switch (object) {
43+
case Foo.UNSPECIFIED:
44+
return 0;
45+
case Foo.BAR:
46+
return 1;
47+
case Foo.BAZ:
48+
return 2;
49+
default:
50+
throw new tsProtoGlobalThis.Error("Unrecognized enum value " + object + " for enum Foo");
51+
}
52+
}
53+
54+
export enum Bar {
55+
UNSPECIFIED = "BAR_UNSPECIFIED",
56+
BAZ = "BAZ",
57+
QUX = "QUX",
58+
}
59+
60+
export function barFromJSON(object: any): Bar {
61+
switch (object) {
62+
case 0:
63+
case "BAR_UNSPECIFIED":
64+
return Bar.UNSPECIFIED;
65+
case 1:
66+
case "BAZ":
67+
return Bar.BAZ;
68+
case 2:
69+
case "QUX":
70+
return Bar.QUX;
71+
default:
72+
throw new tsProtoGlobalThis.Error("Unrecognized enum value " + object + " for enum Bar");
73+
}
74+
}
75+
76+
export function barToJSON(object: Bar): string {
77+
switch (object) {
78+
case Bar.UNSPECIFIED:
79+
return "BAR_UNSPECIFIED";
80+
case Bar.BAZ:
81+
return "BAZ";
82+
case Bar.QUX:
83+
return "QUX";
84+
default:
85+
throw new tsProtoGlobalThis.Error("Unrecognized enum value " + object + " for enum Bar");
86+
}
87+
}
88+
89+
export function barToNumber(object: Bar): number {
90+
switch (object) {
91+
case Bar.UNSPECIFIED:
92+
return 0;
93+
case Bar.BAZ:
94+
return 1;
95+
case Bar.QUX:
96+
return 2;
97+
default:
98+
throw new tsProtoGlobalThis.Error("Unrecognized enum value " + object + " for enum Bar");
99+
}
100+
}
101+
102+
export interface EnumFields {
103+
foo: Foo;
104+
bar: Bar;
105+
}
106+
107+
function createBaseEnumFields(): EnumFields {
108+
return { foo: Foo.UNSPECIFIED, bar: Bar.UNSPECIFIED };
109+
}
110+
111+
export const EnumFields = {
112+
encode(message: EnumFields, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
113+
if (message.foo !== Foo.UNSPECIFIED) {
114+
writer.uint32(8).int32(fooToNumber(message.foo));
115+
}
116+
if (message.bar !== Bar.UNSPECIFIED) {
117+
writer.uint32(16).int32(barToNumber(message.bar));
118+
}
119+
return writer;
120+
},
121+
122+
decode(input: _m0.Reader | Uint8Array, length?: number): EnumFields {
123+
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
124+
let end = length === undefined ? reader.len : reader.pos + length;
125+
const message = createBaseEnumFields();
126+
while (reader.pos < end) {
127+
const tag = reader.uint32();
128+
switch (tag >>> 3) {
129+
case 1:
130+
if (tag !== 8) {
131+
break;
132+
}
133+
134+
message.foo = fooFromJSON(reader.int32());
135+
continue;
136+
case 2:
137+
if (tag !== 16) {
138+
break;
139+
}
140+
141+
message.bar = barFromJSON(reader.int32());
142+
continue;
143+
}
144+
if ((tag & 7) === 4 || tag === 0) {
145+
break;
146+
}
147+
reader.skipType(tag & 7);
148+
}
149+
return message;
150+
},
151+
152+
fromJSON(object: any): EnumFields {
153+
return {
154+
foo: isSet(object.foo) ? fooFromJSON(object.foo) : Foo.UNSPECIFIED,
155+
bar: isSet(object.bar) ? barFromJSON(object.bar) : Bar.UNSPECIFIED,
156+
};
157+
},
158+
159+
toJSON(message: EnumFields): unknown {
160+
const obj: any = {};
161+
if (message.foo !== Foo.UNSPECIFIED) {
162+
obj.foo = fooToJSON(message.foo);
163+
}
164+
if (message.bar !== Bar.UNSPECIFIED) {
165+
obj.bar = barToJSON(message.bar);
166+
}
167+
return obj;
168+
},
169+
170+
create<I extends Exact<DeepPartial<EnumFields>, I>>(base?: I): EnumFields {
171+
return EnumFields.fromPartial(base ?? ({} as any));
172+
},
173+
fromPartial<I extends Exact<DeepPartial<EnumFields>, I>>(object: I): EnumFields {
174+
const message = createBaseEnumFields();
175+
message.foo = object.foo ?? Foo.UNSPECIFIED;
176+
message.bar = object.bar ?? Bar.UNSPECIFIED;
177+
return message;
178+
},
179+
};
180+
181+
declare const self: any | undefined;
182+
declare const window: any | undefined;
183+
declare const global: any | undefined;
184+
const tsProtoGlobalThis: any = (() => {
185+
if (typeof globalThis !== "undefined") {
186+
return globalThis;
187+
}
188+
if (typeof self !== "undefined") {
189+
return self;
190+
}
191+
if (typeof window !== "undefined") {
192+
return window;
193+
}
194+
if (typeof global !== "undefined") {
195+
return global;
196+
}
197+
throw "Unable to locate global object";
198+
})();
199+
200+
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
201+
202+
export type DeepPartial<T> = T extends Builtin ? T
203+
: T extends Array<infer U> ? Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
204+
: T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
205+
: Partial<T>;
206+
207+
type KeysOfUnion<T> = T extends T ? keyof T : never;
208+
export type Exact<P, I extends P> = P extends Builtin ? P
209+
: P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };
210+
211+
function isSet(value: any): boolean {
212+
return value !== null && value !== undefined;
213+
}

‎src/enums.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ export function generateEnumToNumber(ctx: Context, fullName: string, enumDesc: E
192192
return joinCode(chunks, { on: "\n" });
193193
}
194194

195-
function getMemberName(ctx: Context, fullName: string, valueDesc: EnumValueDescriptorProto): string {
195+
export function getMemberName(ctx: Context, fullName: string, valueDesc: EnumValueDescriptorProto): string {
196196
if (ctx.options.removeEnumPrefix) {
197197
return valueDesc.name.replace(`${camelToSnake(fullName)}_`, "");
198198
}

‎src/types.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { fail, FormattedMethodDescriptor, impProto, maybePrefixPackage } from ".
1717
import SourceInfo from "./sourceInfo";
1818
import { uncapitalize } from "./case";
1919
import { Context } from "./context";
20+
import { getMemberName as getEnumMemberName } from "./enums";
2021

2122
/** Based on https://github.com/dcodeIO/protobuf.js/blob/master/src/types.js#L37. */
2223
export function basicWireType(type: FieldDescriptorProto_Type): number {
@@ -192,11 +193,13 @@ export function defaultValue(ctx: Context, field: FieldDescriptorProto): any {
192193
// to probe and see if zero is an allowed value. If it's not, pick the first one.
193194
// This is probably not great, but it's only used in fromJSON and fromPartial,
194195
// and I believe the semantics of those in the proto2 world are generally undefined.
195-
const enumProto = typeMap.get(field.typeName)![2] as EnumDescriptorProto;
196+
const typeInfo = typeMap.get(field.typeName)!;
197+
const enumProto = typeInfo[2] as EnumDescriptorProto;
198+
const enumFullName = typeInfo[1];
196199
const zerothValue = enumProto.value.find((v) => v.number === 0) || enumProto.value[0];
197200
if (options.stringEnums) {
198201
const enumType = messageToTypeName(ctx, field.typeName);
199-
return code`${enumType}.${zerothValue.name}`;
202+
return code`${enumType}.${getEnumMemberName(ctx, enumFullName, zerothValue)}`;
200203
} else {
201204
return zerothValue.number;
202205
}
@@ -264,11 +267,14 @@ export function notDefaultCheck(
264267
// to probe and see if zero is an allowed value. If it's not, pick the first one.
265268
// This is probably not great, but it's only used in fromJSON and fromPartial,
266269
// and I believe the semantics of those in the proto2 world are generally undefined.
267-
const enumProto = typeMap.get(field.typeName)![2] as EnumDescriptorProto;
270+
const typeInfo = typeMap.get(field.typeName)!;
271+
const enumProto = typeInfo[2] as EnumDescriptorProto;
272+
const enumFullName = typeInfo[1];
268273
const zerothValue = enumProto.value.find((v) => v.number === 0) || enumProto.value[0];
269274
if (options.stringEnums) {
270275
const enumType = messageToTypeName(ctx, field.typeName);
271-
return code`${maybeNotUndefinedAnd} ${place} !== ${enumType}.${zerothValue.name}`;
276+
const enumValue = getEnumMemberName(ctx, enumFullName, zerothValue);
277+
return code`${maybeNotUndefinedAnd} ${place} !== ${enumType}.${enumValue}`;
272278
} else {
273279
return code`${maybeNotUndefinedAnd} ${place} !== ${zerothValue.number}`;
274280
}

0 commit comments

Comments
 (0)
Please sign in to comment.