From ed77433772ed58ef6e4bd68129b1b53da09e1bd7 Mon Sep 17 00:00:00 2001 From: Kim Lan Phan Hoang Date: Mon, 22 Jan 2024 10:00:15 +0100 Subject: [PATCH] feat: add sortChildrenWith (#378) * feat: add sortChildrenWith * refactor: fix node 20 --- .github/workflows/test.yml | 2 + src/utils/item.test.ts | 62 +++++++++++++++++++++++++++ src/utils/item.ts | 34 +++++++++++++-- tsconfig.json | 1 + yarn.lock | 86 +++++++++++++++++++------------------- 5 files changed, 139 insertions(+), 46 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4cd73cec..c906e58b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,6 +12,8 @@ jobs: - name: set up node uses: actions/setup-node@v4 + with: + node-version: 20 - name: Yarn Install and Cache uses: graasp/graasp-deploy/.github/actions/yarn-install-and-cache@v1 diff --git a/src/utils/item.test.ts b/src/utils/item.test.ts index dc6eb39e..7da2110f 100644 --- a/src/utils/item.test.ts +++ b/src/utils/item.test.ts @@ -1,6 +1,7 @@ import { v4 } from 'uuid'; import { describe, expect, it } from 'vitest'; +import { DiscriminatedItem } from '..'; import { buildPathFromIds, getChildFromPath, @@ -9,6 +10,7 @@ import { isChildOf, isDescendantOf, isRootItem, + sortChildrenWith, } from './item'; describe('Item Utils', () => { @@ -120,4 +122,64 @@ describe('Item Utils', () => { expect(isRootItem(item)).toBeTruthy(); }); }); + + describe('sortChildrenWith', () => { + it('correctly sort children', () => { + const children = [ + { id: v4() }, + { id: v4() }, + { id: v4() }, + { id: v4() }, + ] as DiscriminatedItem[]; + const order = [ + children[1].id, + children[3].id, + children[2].id, + children[0].id, + ]; + expect(sortChildrenWith(children, order)).toEqual([ + children[1], + children[3], + children[2], + children[0], + ]); + }); + it('correctly sort despite containing falsy ids', () => { + const children = [ + { id: v4() }, + { id: v4() }, + { id: v4() }, + { id: v4() }, + ] as DiscriminatedItem[]; + const order = [ + children[1].id, + v4(), + children[3].id, + children[2].id, + children[0].id, + v4(), + ]; + expect(sortChildrenWith(children, order)).toEqual([ + children[1], + children[3], + children[2], + children[0], + ]); + }); + it('sort by created at children outside of the ordered array', () => { + const children = [ + { id: v4(), createdAt: '2024-01-07T19:24:29.058Z' }, + { id: v4(), createdAt: '2024-01-07T18:24:29.058Z' }, + { id: v4(), createdAt: '2024-03-07T19:24:29.058Z' }, + { id: v4(), createdAt: '2024-04-07T19:24:29.058Z' }, + ] as DiscriminatedItem[]; + const order = [children[3].id, children[2].id]; + expect(sortChildrenWith(children, order)).toEqual([ + children[3], + children[2], + children[1], + children[0], + ]); + }); + }); }); diff --git a/src/utils/item.ts b/src/utils/item.ts index 53aa78a9..b19add50 100644 --- a/src/utils/item.ts +++ b/src/utils/item.ts @@ -1,4 +1,4 @@ -import { Item } from '@/index'; +import { DiscriminatedItem } from '@/index'; /** * @param ids consecutive item ids @@ -53,9 +53,37 @@ export const isChildOf = (path: string, parentPath: string) => { export const isDescendantOf = (path: string, parentPath: string) => path.startsWith(parentPath); -// TODO /** * @param {Item} item * @returns whether the item is a root */ -export const isRootItem = ({ path }: Pick) => !path.includes('.'); +export const isRootItem = ({ path }: Pick) => + !path.includes('.'); + +/** + * Sort children given order array + * @param {Item[]} children children to be sorted + * @param {string[]} idsOrder non-exhaustive ids in order + * @returns array of ordered children + */ +export const sortChildrenWith = ( + children: DiscriminatedItem[], + idsOrder: string[], +) => { + const compareFn = (stElem: DiscriminatedItem, ndElem: DiscriminatedItem) => { + if (idsOrder.indexOf(stElem.id) >= 0 && idsOrder.indexOf(ndElem.id) >= 0) { + return idsOrder.indexOf(stElem.id) - idsOrder.indexOf(ndElem.id); + } + if (idsOrder.indexOf(stElem.id) >= 0) { + return -1; + } + + if (idsOrder.indexOf(ndElem.id) >= 0) { + return 1; + } + + return stElem.createdAt < ndElem.createdAt ? -1 : 1; + }; + + return children.toSorted(compareFn); +}; diff --git a/tsconfig.json b/tsconfig.json index 7e1bb5c7..dc082e5a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,7 @@ "module": "node16", "outDir": "dist", "esModuleInterop": true, + "lib": ["esnext"], "skipLibCheck": true, "declaration": true, "declarationDir": "dist", diff --git a/yarn.lock b/yarn.lock index 004762fa..a4d66c9f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -703,13 +703,13 @@ __metadata: husky: "npm:8.0.3" js-cookie: "npm:3.0.5" jsdom: "npm:23.2.0" - prettier: "npm:3.1.1" + prettier: "npm:3.2.2" ts-node: "npm:10.9.2" tsc-alias: "npm:1.8.8" typescript: "npm:5.3.3" uuid: "npm:9.0.1" validator: "npm:13.11.0" - vitest: "npm:1.1.3" + vitest: "npm:1.2.0" languageName: unknown linkType: soft @@ -1251,57 +1251,57 @@ __metadata: languageName: node linkType: hard -"@vitest/expect@npm:1.1.3": - version: 1.1.3 - resolution: "@vitest/expect@npm:1.1.3" +"@vitest/expect@npm:1.2.0": + version: 1.2.0 + resolution: "@vitest/expect@npm:1.2.0" dependencies: - "@vitest/spy": "npm:1.1.3" - "@vitest/utils": "npm:1.1.3" + "@vitest/spy": "npm:1.2.0" + "@vitest/utils": "npm:1.2.0" chai: "npm:^4.3.10" - checksum: fe5c9eade516a754efc26d4b6378a250f0c3b668fa15b3e6b6042190b64a65c4459b7fd67bfca72fb1fbf215feb838b68da4ab224a2a10137d8828ca6af70516 + checksum: 332ba4bc34e803d09ed98dc8d02ce88f426eb6823e461d2f6aadb3cfd1acda8173cfa9a7e90a437bd889fd931b5e6282bbde4e1a2376d1e7f6d4d756d61ca3a3 languageName: node linkType: hard -"@vitest/runner@npm:1.1.3": - version: 1.1.3 - resolution: "@vitest/runner@npm:1.1.3" +"@vitest/runner@npm:1.2.0": + version: 1.2.0 + resolution: "@vitest/runner@npm:1.2.0" dependencies: - "@vitest/utils": "npm:1.1.3" + "@vitest/utils": "npm:1.2.0" p-limit: "npm:^5.0.0" pathe: "npm:^1.1.1" - checksum: 544455f7d7d3e04e8b6df18dfc8dec0ca5a90dd6c39ce72685de4383d4b2f77e907e6cf225df12af5127293344256056021d3d39b8c8960e943a518c30196801 + checksum: c75cb47942a410deb56df6188df362e968eb280df077da983c029f46c44fdbe7b6a06432ce6cff732f6f18d423dcc7ac858c5077fab82fe9893cf54375a434e4 languageName: node linkType: hard -"@vitest/snapshot@npm:1.1.3": - version: 1.1.3 - resolution: "@vitest/snapshot@npm:1.1.3" +"@vitest/snapshot@npm:1.2.0": + version: 1.2.0 + resolution: "@vitest/snapshot@npm:1.2.0" dependencies: magic-string: "npm:^0.30.5" pathe: "npm:^1.1.1" pretty-format: "npm:^29.7.0" - checksum: bf841693c0210a12b96060e5bc5d3eeda36d6d96f3446c789ccaf22c68d13c41d868d0e76dddcd298cd7c08564f0bed75ad26fb2e94e4909d83f60b5ec9c8904 + checksum: 03e9f83b39b96d4ca1470a32305a3c21fe92f1680d879c62a6feeb873f74b71e0e108d036204b19affe1f9525f841900bcec57abea6407a12bb654c13c3abfbd languageName: node linkType: hard -"@vitest/spy@npm:1.1.3": - version: 1.1.3 - resolution: "@vitest/spy@npm:1.1.3" +"@vitest/spy@npm:1.2.0": + version: 1.2.0 + resolution: "@vitest/spy@npm:1.2.0" dependencies: tinyspy: "npm:^2.2.0" - checksum: d1692582afb7b665ec283723b15bbb7da95896cbfd7befaad9fdac6b64a8250fd918781263d43e8e10ee4874cdd18646224f6d993749c3751296dced8095a9ed + checksum: 7f1bf7ed9146da07a9353a88f98241fcb3d2e424794d80fb1a2c528e2be01d7e4fa1743123150a3d3f2633a126de70fa00e7ff5aa75133bc8e71f294ae75e081 languageName: node linkType: hard -"@vitest/utils@npm:1.1.3": - version: 1.1.3 - resolution: "@vitest/utils@npm:1.1.3" +"@vitest/utils@npm:1.2.0": + version: 1.2.0 + resolution: "@vitest/utils@npm:1.2.0" dependencies: diff-sequences: "npm:^29.6.3" estree-walker: "npm:^3.0.3" loupe: "npm:^2.3.7" pretty-format: "npm:^29.7.0" - checksum: 86f48a7722927741449f40f33584dd9857629782f6661654225b5dd3c039d61cc60806c5dfe419bd793f2a231ba91fe708cbdec5d99b62a1f6f819b6f2121fc3 + checksum: f796583ca18c0dc024c53992b93fe8b17f8879087bd305f7cfda29d9987bde67b9df76b6ac67bd675fc0365a2534aed923fd7afe4103381ab835817b7b92a4b6 languageName: node linkType: hard @@ -3993,12 +3993,12 @@ __metadata: languageName: node linkType: hard -"prettier@npm:3.1.1": - version: 3.1.1 - resolution: "prettier@npm:3.1.1" +"prettier@npm:3.2.2": + version: 3.2.2 + resolution: "prettier@npm:3.2.2" bin: prettier: bin/prettier.cjs - checksum: facc944ba20e194ff4db765e830ffbcb642803381f0d2033ed397e79904fa4ccc877dc25ad68f42d36985c01d051c990ca1b905fb83d2d7d65fe69e4386fa1a3 + checksum: e84d0d2a4ce2b88ee1636904effbdf68b59da63d9f887128f2ed5382206454185432e7c0a9578bc4308bc25d099cfef47fd0b9c211066777854e23e65e34044d languageName: node linkType: hard @@ -4951,9 +4951,9 @@ __metadata: languageName: node linkType: hard -"vite-node@npm:1.1.3": - version: 1.1.3 - resolution: "vite-node@npm:1.1.3" +"vite-node@npm:1.2.0": + version: 1.2.0 + resolution: "vite-node@npm:1.2.0" dependencies: cac: "npm:^6.7.14" debug: "npm:^4.3.4" @@ -4962,7 +4962,7 @@ __metadata: vite: "npm:^5.0.0" bin: vite-node: vite-node.mjs - checksum: 011346c156c4df7cb49fc1de357ff7dc6316011faeb00855aca7ecab24ed19aac4c03c0bc921923d13c37870f2954c3fcbf975c5eeee3a03d675831a60556dfb + checksum: fa93de2808705be2d4d029c3ddd9651787d45a20b9ccb6492b762a682898ac788b5e90f57de86dbf20a070b6a2b137fa7d00de071367a36735af53f8ea9dc046 languageName: node linkType: hard @@ -5006,15 +5006,15 @@ __metadata: languageName: node linkType: hard -"vitest@npm:1.1.3": - version: 1.1.3 - resolution: "vitest@npm:1.1.3" +"vitest@npm:1.2.0": + version: 1.2.0 + resolution: "vitest@npm:1.2.0" dependencies: - "@vitest/expect": "npm:1.1.3" - "@vitest/runner": "npm:1.1.3" - "@vitest/snapshot": "npm:1.1.3" - "@vitest/spy": "npm:1.1.3" - "@vitest/utils": "npm:1.1.3" + "@vitest/expect": "npm:1.2.0" + "@vitest/runner": "npm:1.2.0" + "@vitest/snapshot": "npm:1.2.0" + "@vitest/spy": "npm:1.2.0" + "@vitest/utils": "npm:1.2.0" acorn-walk: "npm:^8.3.1" cac: "npm:^6.7.14" chai: "npm:^4.3.10" @@ -5029,7 +5029,7 @@ __metadata: tinybench: "npm:^2.5.1" tinypool: "npm:^0.8.1" vite: "npm:^5.0.0" - vite-node: "npm:1.1.3" + vite-node: "npm:1.2.0" why-is-node-running: "npm:^2.2.2" peerDependencies: "@edge-runtime/vm": "*" @@ -5053,7 +5053,7 @@ __metadata: optional: true bin: vitest: vitest.mjs - checksum: 5dc6010b14ab069f6483e343724bd4b6ff72c0ea1cca52b2f5d2ea2b0b7acc9584887b2d428af309c855b731d081dc32ec370032d2d40a20492ced5695950acb + checksum: 0aa1c65bfc14225bcd6aa2623e325f6d9da6dc8e39687e7ceffce870ed6204e7e72578db3835664d97da5ed647de838b1b04b3bb4a50eb2636e9c54b5f80c8a3 languageName: node linkType: hard