Skip to content

Commit

Permalink
chore: resolve all data asynchronously
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisvxd committed Nov 3, 2023
1 parent 8592840 commit 8c9bb9a
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 156 deletions.
106 changes: 56 additions & 50 deletions packages/core/lib/__tests__/use-resolved-data.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { act, cleanup, renderHook, waitFor } from "@testing-library/react";
import { Config, Data } from "../../types/Config";
import { useResolvedData } from "../use-resolved-data";
import { SetDataAction } from "../../reducer";
import { cache } from "../resolve-all-props";
import { cache } from "../resolve-component-data";

const item1 = { type: "MyComponent", props: { id: "MyComponent-1" } };
const item2 = { type: "MyComponent", props: { id: "MyComponent-2" } };
Expand Down Expand Up @@ -55,27 +55,55 @@ describe("use-resolved-data", () => {
});

it("should call the `setData` action with resolved data", async () => {
let dispatchedEvent: SetDataAction = {} as any;
let dispatchedEvents: SetDataAction[] = [];
let currentData = data;

const renderedHook = renderHook(() => {
return useResolvedData(currentData, config, (args) => {
const action = args as SetDataAction;
const newData = action.data as any;

dispatchedEvents.push(action);

currentData = { ...currentData, ...newData(currentData) };
});
});

const renderedHook = renderHook(() =>
useResolvedData(data, config, (args) => {
dispatchedEvent = args as any;
})
);
const { resolveData } = renderedHook.result.current;
await act(async () => {
resolveData();
// resolveData gets called on render
renderedHook.rerender();
});

expect(dispatchedEvent?.type).toBe("setData");
expect(dispatchedEvents.length).toBe(4); // calls dispatcher for each resolver

if (typeof dispatchedEvent?.data === "function") {
expect(dispatchedEvent?.data(data)).toMatchInlineSnapshot(`
{
"content": [
const fn = dispatchedEvents[dispatchedEvents.length - 1].data as any;
expect(currentData).toMatchInlineSnapshot(`
{
"content": [
{
"props": {
"id": "MyComponent-1",
"prop": "Hello, world",
},
"readOnly": {
"prop": true,
},
"type": "MyComponent",
},
],
"root": {
"props": {
"title": "Resolved title",
},
"readOnly": {
"title": true,
},
},
"zones": {
"MyComponent-1:zone": [
{
"props": {
"id": "MyComponent-1",
"id": "MyComponent-2",
"prop": "Hello, world",
},
"readOnly": {
Expand All @@ -84,43 +112,21 @@ describe("use-resolved-data", () => {
"type": "MyComponent",
},
],
"root": {
"props": {
"title": "Resolved title",
},
"readOnly": {
"title": true,
},
},
"zones": {
"MyComponent-1:zone": [
{
"props": {
"id": "MyComponent-2",
"prop": "Hello, world",
},
"readOnly": {
"prop": true,
},
"type": "MyComponent",
"MyComponent-2:zone": [
{
"props": {
"id": "MyComponent-3",
"prop": "Hello, world",
},
],
"MyComponent-2:zone": [
{
"props": {
"id": "MyComponent-3",
"prop": "Hello, world",
},
"readOnly": {
"prop": true,
},
"type": "MyComponent",
"readOnly": {
"prop": true,
},
],
},
}
`);
}
"type": "MyComponent",
},
],
},
}
`);
});

it("should NOT call the `setData` action with resolved data, when the data is unchanged", async () => {
Expand Down
6 changes: 3 additions & 3 deletions packages/core/lib/resolve-all-data.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Config, Data, MappedItem } from "../types/Config";
import { resolveAllProps } from "./resolve-all-props";
import { resolveAllComponentData } from "./resolve-component-data";
import { resolveRootData } from "./resolve-root-data";

export const resolveAllData = async (
Expand All @@ -17,7 +17,7 @@ export const resolveAllData = async (

for (let i = 0; i < zoneKeys.length; i++) {
const zoneKey = zoneKeys[i];
resolvedZones[zoneKey] = await resolveAllProps(
resolvedZones[zoneKey] = await resolveAllComponentData(
zones[zoneKey],
config,
onResolveStart,
Expand All @@ -28,7 +28,7 @@ export const resolveAllData = async (
return {
...data,
root: dynamicRoot,
content: await resolveAllProps(
content: await resolveAllComponentData(
data.content,
config,
onResolveStart,
Expand Down
73 changes: 0 additions & 73 deletions packages/core/lib/resolve-all-props.ts

This file was deleted.

86 changes: 86 additions & 0 deletions packages/core/lib/resolve-component-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { ComponentData, Config, MappedItem } from "../types/Config";

export const cache = { lastChange: {} };

export const resolveAllComponentData = async (
content: MappedItem[],
config: Config,
onResolveStart?: (item: MappedItem) => void,
onResolveEnd?: (item: MappedItem) => void
) => {
return await Promise.all(
content.map(async (item) => {
return await resolveComponentData(
item,
config,
onResolveStart,
onResolveEnd
);
})
);
};

export const resolveComponentData = async (
item: ComponentData,
config: Config,
onResolveStart?: (item: MappedItem) => void,
onResolveEnd?: (item: MappedItem) => void
) => {
const configForItem = config.components[item.type];
if (configForItem.resolveData) {
let changed = Object.keys(item.props).reduce(
(acc, item) => ({ ...acc, [item]: true }),
{}
);

if (cache.lastChange[item.props.id]) {
const { item: oldItem, resolved } = cache.lastChange[item.props.id];

if (oldItem === item) {
return resolved;
}

Object.keys(item.props).forEach((propName) => {
if (oldItem.props[propName] === item.props[propName]) {
changed[propName] = false;
}
});
}

if (onResolveStart) {
onResolveStart(item);
}

const { props: resolvedProps, readOnly = {} } =
await configForItem.resolveData(item, { changed });

const { readOnly: existingReadOnly = {} } = item || {};

const newReadOnly = { ...existingReadOnly, ...readOnly };

const resolvedItem = {
...item,
props: {
...item.props,
...resolvedProps,
},
};

if (Object.keys(newReadOnly).length) {
resolvedItem.readOnly = newReadOnly;
}

cache.lastChange[item.props.id] = {
item,
resolved: resolvedItem,
};

if (onResolveEnd) {
onResolveEnd(resolvedItem);
}

return resolvedItem;
}

return item;
};
Loading

0 comments on commit 8c9bb9a

Please sign in to comment.