From 3765ad93fc5f62dc955eff15cd7d4bcc4b1fd252 Mon Sep 17 00:00:00 2001 From: Evyatar Date: Fri, 1 Dec 2023 01:41:50 +0200 Subject: [PATCH] patch(vestjs-runtime): Support inflation of serialized values --- .../vestjs-runtime/src/Isolate/IsolateKeys.ts | 2 +- .../src/exports/IsolateSerializer.ts | 35 ++++++++--- .../__tests__/IsolateSerializer.test.ts | 63 +++++++++++++++++++ 3 files changed, 92 insertions(+), 8 deletions(-) diff --git a/packages/vestjs-runtime/src/Isolate/IsolateKeys.ts b/packages/vestjs-runtime/src/Isolate/IsolateKeys.ts index 3d01a70c7..287bc5afc 100644 --- a/packages/vestjs-runtime/src/Isolate/IsolateKeys.ts +++ b/packages/vestjs-runtime/src/Isolate/IsolateKeys.ts @@ -1,4 +1,4 @@ -import { assign } from 'vest-utils'; +import { assign } from 'lodash'; export enum IsolateKeys { Type = '$type', diff --git a/packages/vestjs-runtime/src/exports/IsolateSerializer.ts b/packages/vestjs-runtime/src/exports/IsolateSerializer.ts index 611ab7676..785fa18ed 100644 --- a/packages/vestjs-runtime/src/exports/IsolateSerializer.ts +++ b/packages/vestjs-runtime/src/exports/IsolateSerializer.ts @@ -2,6 +2,7 @@ import { ErrorStrings } from 'ErrorStrings'; import { Maybe, Nullable, + assign, hasOwnProperty, invariant, isEmpty, @@ -18,12 +19,11 @@ import { KeyToMinified, MinifiedKeys, MinifiedToKey, - invertKeyMap, } from 'IsolateKeys'; import { IsolateMutator } from 'IsolateMutator'; export class IsolateSerializer { - // eslint-disable-next-line max-statements, complexity + // eslint-disable-next-line max-statements, complexity, max-lines-per-function static deserialize( node: Record | TIsolate | string, miniMaps: Maybe @@ -35,7 +35,7 @@ export class IsolateSerializer { // to avoid circular references during serialization. // we need to rebuild the tree and add back the parent property to the children // and the keys property to the parents. - const inverseMinimap = invertKeyMap(miniMaps?.keys?.data); + const inverseMinimap = deeplyInvertKeyMap(miniMaps); // Validate the root object const root = isStringValue(node) @@ -65,12 +65,20 @@ export class IsolateSerializer { const keyToUse = MinifiedToKey[key]; // If the key is data, then we may need to transform the keys + // eslint-disable-next-line max-depth if (keyToUse === IsolateKeys.Data) { // Transform the keys - current[keyToUse] = transformKeys(value, inverseMinimap); + current[keyToUse] = transformKeys( + value, + inverseMinimap?.keys?.data + ); } else { // Otherwise, just set the key - current[keyToUse] = value; + current[keyToUse] = transformValueByKey( + keyToUse, + value, + inverseMinimap + ); } // Remove the old key @@ -163,7 +171,7 @@ function transformIsolate( } const keyToUse = minifyKey(key); - next[keyToUse] = minifyValueByKey(key, value, miniMaps); + next[keyToUse] = transformValueByKey(key, value, miniMaps); } return next; @@ -177,7 +185,7 @@ function minifyKey(key: string): string { return KeyToMinified[key as keyof typeof KeyToMinified] ?? key; } -function minifyValueByKey( +function transformValueByKey( key: string, value: any, miniMaps: Maybe @@ -223,3 +231,16 @@ type MiniMaps = Partial<{ [IsolateKeys.Type]: MiniMap; }>; }>; + +export function deeplyInvertKeyMap(miniMaps: Maybe = {}): MiniMaps { + return Object.entries(miniMaps).reduce((acc, [key, value]) => { + if (typeof value === 'object') { + return assign(acc, { + [key]: deeplyInvertKeyMap(value as MiniMaps), + }); + } + return assign(acc, { + [value]: key, + }); + }, {} as MiniMaps); +} diff --git a/packages/vestjs-runtime/src/exports/__tests__/IsolateSerializer.test.ts b/packages/vestjs-runtime/src/exports/__tests__/IsolateSerializer.test.ts index 5c81fe60c..e9893af3f 100644 --- a/packages/vestjs-runtime/src/exports/__tests__/IsolateSerializer.test.ts +++ b/packages/vestjs-runtime/src/exports/__tests__/IsolateSerializer.test.ts @@ -112,6 +112,69 @@ describe('IsolateSerializer', () => { `"{"C":[{"D":{"some_data":true},"$":"UC1","S":"d"},{"$":"UC2","S":"f"},{"$":"UC3"}],"D":{"some_data":true},"$":"UR","S":"p"}"` ); }); + + it('Should correctly expand values', () => { + const { root } = createRoot(); + + root.status = 'pending'; + // @ts-ignore + root.children[0].status = 'done'; + // @ts-ignore + root.children[1].status = 'failed'; + + const minimap = { + values: { + status: { + pending: 'p', + done: 'd', + failed: 'f', + }, + $type: { + URoot: 'UR', + UChild_1: 'UC1', + UChild_2: 'UC2', + UChild_3: 'UC3', + }, + }, + }; + + const serialized = IsolateSerializer.serialize(root, minimap); + const inflated = IsolateSerializer.deserialize(serialized, minimap); + + expect(inflated.status).toBe('pending'); + // @ts-ignore + expect(inflated.children[0].status).toBe('done'); + // @ts-ignore + expect(inflated.children[1].status).toBe('failed'); + expect(inflated).toMatchInlineSnapshot(` + { + "$type": "URoot", + "children": [ + { + "$type": "UChild_1", + "data": { + "some_data": true, + }, + "parent": [Circular], + "status": "done", + }, + { + "$type": "UChild_2", + "parent": [Circular], + "status": "failed", + }, + { + "$type": "UChild_3", + "parent": [Circular], + }, + ], + "data": { + "some_data": true, + }, + "status": "pending", + } + `); + }); }); it('Should inflate with correct keys', () => {