From 9ae356b003f28e994e1bbdcb56cd9796425bb863 Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Sat, 25 May 2024 16:11:02 +0300 Subject: [PATCH 1/2] refactor: move Map.groupBy into shims Here moved our utility polyfill for Map.groupBy into shims module we are using for all stuff we will replace with native methods. Used it in marketplace to group by category. --- .../panels/marketplace/overview.tsx | 30 ++++--------------- .../app/builder/shared/expression-editor.tsx | 4 +-- apps/builder/app/shared/array-utils.test.ts | 10 ------- apps/builder/app/shared/array-utils.ts | 18 ----------- apps/builder/app/shared/nano-states/props.ts | 8 ++--- apps/builder/app/shared/shim.test.ts | 11 ++++++- apps/builder/app/shared/shim.ts | 17 +++++++++++ 7 files changed, 39 insertions(+), 59 deletions(-) diff --git a/apps/builder/app/builder/features/sidebar-left/panels/marketplace/overview.tsx b/apps/builder/app/builder/features/sidebar-left/panels/marketplace/overview.tsx index d8263bffb69b..0661bd386bd2 100644 --- a/apps/builder/app/builder/features/sidebar-left/panels/marketplace/overview.tsx +++ b/apps/builder/app/builder/features/sidebar-left/panels/marketplace/overview.tsx @@ -12,33 +12,12 @@ import { Tooltip, } from "@webstudio-is/design-system"; import { EllipsesIcon } from "@webstudio-is/icons"; -import type { MarketplaceOverviewItem } from "~/shared/marketplace/types"; import type { Project } from "@webstudio-is/project"; import { usePress } from "@react-aria/interactions"; import { marketplaceCategories } from "@webstudio-is/project-build"; +import { mapGroupBy } from "~/shared/shim"; +import type { MarketplaceOverviewItem } from "~/shared/marketplace/types"; import { Card } from "./card"; -import {} from "@webstudio-is/feature-flags"; - -const getItemsByCategory = (items: Array = []) => { - const itemsByCategory = new Map< - MarketplaceOverviewItem["category"], - Array - >(); - - for (const item of items) { - if (marketplaceCategories.has(item.category) === false) { - throw new Error(`Unknown category: ${item.category}`); - } - let categoryItems = itemsByCategory.get(item.category); - if (categoryItems === undefined) { - categoryItems = []; - itemsByCategory.set(item.category, categoryItems); - } - categoryItems.push(item); - } - - return itemsByCategory; -}; const GalleryOverviewItem = ({ item, @@ -92,7 +71,10 @@ export const Overview = ({ openAbout?: Project["id"]; onOpenAbout: (projectId?: string) => void; }) => { - const itemsByCategory = useMemo(() => getItemsByCategory(items), [items]); + const itemsByCategory = useMemo( + () => mapGroupBy(items ?? [], (item) => item.category), + [items] + ); const [selectedCategory, setSelectedCategory] = useState("sectionTemplates"); diff --git a/apps/builder/app/builder/shared/expression-editor.tsx b/apps/builder/app/builder/shared/expression-editor.tsx index 01268348936a..690930038571 100644 --- a/apps/builder/app/builder/shared/expression-editor.tsx +++ b/apps/builder/app/builder/shared/expression-editor.tsx @@ -31,12 +31,12 @@ import { decodeDataSourceVariable, transpileExpression, } from "@webstudio-is/sdk"; +import { mapGroupBy } from "~/shared/shim"; import { CodeEditorBase, EditorContent, EditorDialog, } from "./code-editor-base"; -import { groupBy } from "~/shared/array-utils"; export const formatValue = (value: unknown) => { if (Array.isArray(value)) { @@ -423,7 +423,7 @@ export const ExpressionEditor = ({ autoFocus={autoFocus} value={value} onChange={(value) => { - const aliasesByName = groupBy( + const aliasesByName = mapGroupBy( Array.from(aliases), ([_id, name]) => name ); diff --git a/apps/builder/app/shared/array-utils.test.ts b/apps/builder/app/shared/array-utils.test.ts index 90fc11cb3f5c..b8442a88b4e1 100644 --- a/apps/builder/app/shared/array-utils.test.ts +++ b/apps/builder/app/shared/array-utils.test.ts @@ -2,7 +2,6 @@ import { expect, test } from "@jest/globals"; import { getMapValuesBy, getMapValuesByKeysSet, - groupBy, removeByMutable, } from "./array-utils"; @@ -63,12 +62,3 @@ test("getMapValuesBy", () => { getMapValuesBy(map, (value) => value.includes("3") || value.includes("5")) ).toEqual(["value3", "value5"]); }); - -test("groupBy", () => { - expect(groupBy([1, 2, 3, 4, 5], (item) => item % 2)).toEqual( - new Map([ - [0, [2, 4]], - [1, [1, 3, 5]], - ]) - ); -}); diff --git a/apps/builder/app/shared/array-utils.ts b/apps/builder/app/shared/array-utils.ts index 982e0493eb07..e1a34f32b745 100644 --- a/apps/builder/app/shared/array-utils.ts +++ b/apps/builder/app/shared/array-utils.ts @@ -38,21 +38,3 @@ export const getMapValuesBy = ( } return values; }; - -// @todo replace with builtin Map.groupBy when support -export const groupBy = ( - array: Item[] | IterableIterator, - getKey: (item: Item) => Key -) => { - const groups = new Map(); - for (const item of array) { - const key = getKey(item); - let group = groups.get(key); - if (group === undefined) { - group = []; - groups.set(key, group); - } - group.push(item); - } - return groups; -}; diff --git a/apps/builder/app/shared/nano-states/props.ts b/apps/builder/app/shared/nano-states/props.ts index c80910bd2a2b..12ec92321114 100644 --- a/apps/builder/app/shared/nano-states/props.ts +++ b/apps/builder/app/shared/nano-states/props.ts @@ -19,10 +19,10 @@ import { textContentAttribute, } from "@webstudio-is/react-sdk"; import { isFeatureEnabled } from "@webstudio-is/feature-flags"; +import { mapGroupBy } from "~/shared/shim"; import { $instances } from "./instances"; import { $dataSources, $props, $assets, $resources } from "./nano-states"; import { $selectedPage, $pages } from "./pages"; -import { groupBy } from "../array-utils"; import type { InstanceSelector } from "../tree-utils"; import { $params } from "~/canvas/stores"; import { restResourcesLoader } from "../router-utils"; @@ -247,7 +247,7 @@ export const $propValuesByInstanceSelector = computed( }); } // collect props and group by instances - const propsByInstanceId = groupBy(propsList, (prop) => prop.instanceId); + const propsByInstanceId = mapGroupBy(propsList, (prop) => prop.instanceId); // traverse instances tree and compute props within each instance const propValuesByInstanceSelector = new Map< @@ -356,12 +356,12 @@ export const $variableValuesByInstanceSelector = computed( resourceValues, defaultSystem ) => { - const propsByInstanceId = groupBy( + const propsByInstanceId = mapGroupBy( props.values(), (prop) => prop.instanceId ); - const variablesByInstanceId = groupBy( + const variablesByInstanceId = mapGroupBy( dataSources.values(), (dataSource) => dataSource.scopeInstanceId ); diff --git a/apps/builder/app/shared/shim.test.ts b/apps/builder/app/shared/shim.test.ts index 0bb05f60e70d..99c94d6785d3 100644 --- a/apps/builder/app/shared/shim.test.ts +++ b/apps/builder/app/shared/shim.test.ts @@ -1,5 +1,5 @@ import { expect, test } from "@jest/globals"; -import { setDifference } from "./shim"; +import { mapGroupBy, setDifference } from "./shim"; test("set difference", () => { // this set is bigger than other @@ -11,3 +11,12 @@ test("set difference", () => { new Set([1]) ); }); + +test("groupBy", () => { + expect(mapGroupBy([1, 2, 3, 4, 5], (item) => item % 2)).toEqual( + new Map([ + [0, [2, 4]], + [1, [1, 3, 5]], + ]) + ); +}); diff --git a/apps/builder/app/shared/shim.ts b/apps/builder/app/shared/shim.ts index c63318414699..ec2165e151e0 100644 --- a/apps/builder/app/shared/shim.ts +++ b/apps/builder/app/shared/shim.ts @@ -15,3 +15,20 @@ export const setDifference = (current: Set, other: Set) => { } return result; }; + +export const mapGroupBy = ( + array: Item[] | IterableIterator, + getKey: (item: Item) => Key +) => { + const groups = new Map(); + for (const item of array) { + const key = getKey(item); + let group = groups.get(key); + if (group === undefined) { + group = []; + groups.set(key, group); + } + group.push(item); + } + return groups; +}; From 8dd79328014faeefd0090d29550a37ddf463182d Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Sat, 25 May 2024 16:15:13 +0300 Subject: [PATCH 2/2] Tweak test names --- apps/builder/app/shared/shim.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/builder/app/shared/shim.test.ts b/apps/builder/app/shared/shim.test.ts index 99c94d6785d3..793b15d87885 100644 --- a/apps/builder/app/shared/shim.test.ts +++ b/apps/builder/app/shared/shim.test.ts @@ -1,7 +1,7 @@ import { expect, test } from "@jest/globals"; import { mapGroupBy, setDifference } from "./shim"; -test("set difference", () => { +test("Set.prototype.difference", () => { // this set is bigger than other expect(setDifference(new Set([1, 2, 3, 4]), new Set([3, 4, 5]))).toEqual( new Set([1, 2]) @@ -12,7 +12,7 @@ test("set difference", () => { ); }); -test("groupBy", () => { +test("Map.groupBy", () => { expect(mapGroupBy([1, 2, 3, 4, 5], (item) => item % 2)).toEqual( new Map([ [0, [2, 4]],