Skip to content

Commit

Permalink
fix: default key edge case
Browse files Browse the repository at this point in the history
  • Loading branch information
infodusha committed Aug 30, 2024
1 parent cb75600 commit b54304b
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 6 deletions.
13 changes: 12 additions & 1 deletion __tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Universe } from "./test-data/generated/universe_pb";
import { Spices } from "./test-data/generated/spices_pb";
import { Newspaper } from "./test-data/generated/newspaper_pb";
import { File } from "./test-data/generated/file_pb";
import { Edge } from "./test-data/generated/edge_pb";

describe('fromProtobufObject', () => {
it('Should work with easy structure', () => {
Expand Down Expand Up @@ -270,4 +271,14 @@ describe('Binary data', () => {
const file = fromProtobufObject(File, obj);
expect(file.toObject()).toEqual(obj);
});
})
});

describe("Edge cases", () => {
it("Should work with default property", () => {
const obj = {
pb_default: true,
} satisfies Edge.AsObject;
const file = fromProtobufObject(Edge, obj);
expect(file.toObject()).toEqual(obj);
});
});
5 changes: 5 additions & 0 deletions __tests__/test-data/edge.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
syntax = "proto3";

message Edge {
bool default = 1;
}
1 change: 1 addition & 0 deletions __tests__/test-data/generate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ gen ./universe.proto
gen ./spices.proto
gen ./newspaper.proto
gen ./file.proto
gen ./edge.proto
15 changes: 10 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const enum PREFIX {
export function fromProtobufObject<T extends Message>(MessageType: MessageConstructor<T>, data: AsObject<T>): T {
const instance = new MessageType();
validateMissingProps(instance, data);
for (const [prop, value] of Object.entries(filterExtraProps(instance, data))) {
for (const [key, value] of Object.entries(filterExtraProps(instance, data))) {
const prop = getActualKey(key);
if (Array.isArray(value) && isProtobufMap(instance, prop)) {
const mapMethod = getMethod(prop, PREFIX.GET);
const map = callMethod(instance, mapMethod) as ProtobufMap<unknown, unknown>;
Expand Down Expand Up @@ -66,8 +67,12 @@ function callMethod<T extends object, R>(obj: T, key: string, value?: unknown):
return (obj[key as keyof T] as (value: unknown) => R)(value);
}

function getActualKey(key: string): string {
return key === 'pb_default' ? 'default' : key;
}

function getProp(key: string, prefix: PREFIX): string {
const prop = key.slice(prefix.length);
const prop = getActualKey(key).slice(prefix.length);
return prop.slice(0, 1).toLowerCase() + prop.slice(1);
}

Expand Down Expand Up @@ -99,17 +104,17 @@ function isOptional<T extends Message>(instance: T, prop: string): boolean {

function validateMissingProps<T extends Message>(instance: T, data: AsObject<T>): void {
const instanceProps = getInstanceProps(instance);
const dataProps = Object.keys(data);
const dataKeys = Object.keys(data).map(getActualKey);
for (const prop of instanceProps) {
if (!dataProps.includes(prop) && !isOptional(instance, prop)) {
if (!dataKeys.includes(prop) && !isOptional(instance, prop)) {
throw new Error(`Missing property '${prop}'`);
}
}
}

function filterExtraProps<T extends Message>(instance: T, data: AsObject<T>): AsObject<T> {
const instanceProps = getInstanceProps(instance);
return Object.fromEntries(Object.entries(data).filter(([key, value]) => instanceProps.includes(key) && value !== undefined)) as AsObject<T>;
return Object.fromEntries(Object.entries(data).filter(([key, value]) => instanceProps.includes(getActualKey(key)) && value !== undefined)) as AsObject<T>;
}

function isObject(value: unknown, prop: string): boolean {
Expand Down

0 comments on commit b54304b

Please sign in to comment.