Skip to content

Commit 105e042

Browse files
committed
Match class by name
1 parent 898fbe0 commit 105e042

File tree

5 files changed

+62
-10
lines changed

5 files changed

+62
-10
lines changed

yarn-project/foundation/src/json-rpc/class_converter.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ export type ClassEncoding = 'string' | 'object';
103103
*/
104104
export class ClassConverter {
105105
private toClass = new Map<string, [IOClass, ClassEncoding]>();
106-
private toName = new Map<IOClass, [string, ClassEncoding]>();
107106

108107
/**
109108
* Create a class converter from a table of classes.
@@ -140,7 +139,6 @@ export class ClassConverter {
140139
(class_ as StringIOClass)['fromString'] || (class_ as ObjIOClass)['fromJSON'],
141140
`Class ${type} must define a fromString() OR fromJSON() static method.`,
142141
);
143-
this.toName.set(class_, [type, encoding]);
144142
this.toClass.set(type, [class_, encoding]);
145143
}
146144

@@ -153,12 +151,13 @@ export class ClassConverter {
153151
return this.toClass.has(type);
154152
}
155153
/**
156-
* Is this class object registered?
154+
* Is this class object registered under its constructor name?
157155
* @param obj - The class object.
158156
* @returns If it is a registered class.
159157
*/
160158
isRegisteredClass(obj: any) {
161-
return this.toName.has(obj);
159+
const name = obj.prototype.constructor.name;
160+
return this.isRegisteredClassName(name);
162161
}
163162
/**
164163
* Convert a JSON-like object to a class object.
@@ -182,10 +181,11 @@ export class ClassConverter {
182181
* @returns The class object.
183182
*/
184183
toJsonObj(classObj: any): JsonEncodedClass | StringEncodedClass {
185-
const result = this.toName.get(classObj.constructor);
184+
const type = classObj.constructor.name;
185+
const result = this.toClass.get(type);
186186
assert(result, `Could not find class in lookup.`);
187-
const [type, encoding] = result;
187+
const [_class, encoding] = result;
188188
const data = encoding === 'string' ? classObj.toString() : classObj.toJSON();
189-
return { type: type!, data };
189+
return { type, data };
190190
}
191191
}

yarn-project/foundation/src/json-rpc/convert.test.ts

+22
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { Buffer } from 'buffer';
22

33
import { ClassConverter } from './class_converter.js';
44
import { convertBigintsInObj, convertFromJsonObj, convertToJsonObj } from './convert.js';
5+
import { ToStringClass as ToStringClassA } from './fixtures/class_a.js';
6+
import { ToStringClass as ToStringClassB } from './fixtures/class_b.js';
57
import { TestNote } from './fixtures/test_state.js';
68

79
const TEST_BASE64 = 'YmFzZTY0IGRlY29kZXI=';
@@ -24,3 +26,23 @@ test('does not convert a string', () => {
2426
expect(convertBigintsInObj('hello')).toEqual('hello');
2527
expect(convertBigintsInObj({ msg: 'hello' })).toEqual({ msg: 'hello' });
2628
});
29+
30+
test('converts a registered class', () => {
31+
const cc = new ClassConverter({ ToStringClass: ToStringClassA });
32+
const obj = { content: new ToStringClassA('a', 'b') };
33+
const serialised = convertToJsonObj(cc, obj);
34+
const deserialised = convertFromJsonObj(cc, serialised) as { content: ToStringClassA };
35+
expect(deserialised.content).toBeInstanceOf(ToStringClassA);
36+
expect(deserialised.content.x).toEqual('a');
37+
expect(deserialised.content.y).toEqual('b');
38+
});
39+
40+
test('converts a class by name', () => {
41+
const cc = new ClassConverter({ ToStringClass: ToStringClassA });
42+
const obj = { content: new ToStringClassB('a', 'b') };
43+
const serialised = convertToJsonObj(cc, obj);
44+
const deserialised = convertFromJsonObj(cc, serialised) as { content: ToStringClassA };
45+
expect(deserialised.content).toBeInstanceOf(ToStringClassA);
46+
expect(deserialised.content.x).toEqual('a');
47+
expect(deserialised.content.y).toEqual('b');
48+
});

yarn-project/foundation/src/json-rpc/convert.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ export function convertFromJsonObj(cc: ClassConverter, obj: any): any {
7676
return newObj;
7777
}
7878
// Throw if this is a non-primitive class that was not registered
79-
if (typeof obj === 'object' && obj.constructor !== Object) {
80-
throw new Error(`Object ${obj.constructor.name} not registered for deserialisation`);
79+
if (typeof obj === 'object' && Object.getPrototypeOf(obj) === Object.getPrototypeOf({})) {
80+
throw new Error(`Class ${obj.constructor.name} not registered for deserialisation`);
8181
}
8282
// Leave alone, assume JSON primitive
8383
return obj;
@@ -122,7 +122,7 @@ export function convertToJsonObj(cc: ClassConverter, obj: any): any {
122122
return newObj;
123123
}
124124
// Throw if this is a non-primitive class that was not registered
125-
if (typeof obj === 'object' && obj.constructor !== Object) {
125+
if (typeof obj === 'object' && Object.getPrototypeOf(obj) === Object.getPrototypeOf({})) {
126126
throw new Error(`Object ${obj.constructor.name} not registered for serialisation`);
127127
}
128128
// Leave alone, assume JSON primitive
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* Test class for testing string converter.
3+
*/
4+
export class ToStringClass {
5+
constructor(/** A value */ public readonly x: string, /** Another value */ public readonly y: string) {}
6+
7+
toString(): string {
8+
return [this.x, this.y].join('-');
9+
}
10+
11+
static fromString(value: string) {
12+
const [x, y] = value.split('-');
13+
return new ToStringClass(x, y);
14+
}
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* Test class for testing string converter.
3+
*/
4+
export class ToStringClass {
5+
constructor(/** A value */ public readonly x: string, /** Another value */ public readonly y: string) {}
6+
7+
toString(): string {
8+
return [this.x, this.y].join('-');
9+
}
10+
11+
static fromString(value: string) {
12+
const [x, y] = value.split('-');
13+
return new ToStringClass(x, y);
14+
}
15+
}

0 commit comments

Comments
 (0)