From 3daa47dc83e22da1f54b7ae80d0224cfadc38a3b Mon Sep 17 00:00:00 2001 From: robonen Date: Thu, 31 Oct 2024 00:48:01 +0700 Subject: [PATCH 1/4] feat(packages/stdlib): add omit object tool --- .../stdlib/src/objects/omit/index.test.ts | 50 +++++++++++++++++++ packages/stdlib/src/objects/omit/index.ts | 38 ++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 packages/stdlib/src/objects/omit/index.test.ts create mode 100644 packages/stdlib/src/objects/omit/index.ts diff --git a/packages/stdlib/src/objects/omit/index.test.ts b/packages/stdlib/src/objects/omit/index.test.ts new file mode 100644 index 0000000..c086a89 --- /dev/null +++ b/packages/stdlib/src/objects/omit/index.test.ts @@ -0,0 +1,50 @@ +import { describe, it, expect } from 'vitest'; +import { omit } from '.'; + +describe('omit', () => { + it('omit a single key from the object', () => { + const result = omit({ a: 1, b: 2, c: 3 }, 'a'); + + expect(result).toEqual({ b: 2, c: 3 }); + }); + + it('omit multiple keys from the object', () => { + const result = omit({ a: 1, b: 2, c: 3 }, ['a', 'b']); + + expect(result).toEqual({ c: 3 }); + }); + + it('return the same object if no keys are omitted', () => { + const result = omit({ a: 1, b: 2, c: 3 }, []); + + expect(result).toEqual({ a: 1, b: 2, c: 3 }); + }); + + it('not modify the original object', () => { + const obj = { a: 1, b: 2, c: 3 }; + const result = omit(obj, 'a'); + + expect(obj).toEqual({ a: 1, b: 2, c: 3 }); + expect(result).toEqual({ b: 2, c: 3 }); + }); + + it('handle an empty object', () => { + const result = omit({}, 'a' as any); + + expect(result).toEqual({}); + }); + + it('handle non-existent keys gracefully', () => { + const result = omit({ a: 1, b: 2, c: 3 } as Record, 'd'); + + expect(result).toEqual({ a: 1, b: 2, c: 3 }); + }); + + it('handle null gracefully', () => { + const emptyTarget = omit(null as any, 'a'); + const emptyKeys = omit({ a: 1 }, null as any); + + expect(emptyTarget).toEqual({}); + expect(emptyKeys).toEqual({ a: 1 }); + }); +}); \ No newline at end of file diff --git a/packages/stdlib/src/objects/omit/index.ts b/packages/stdlib/src/objects/omit/index.ts new file mode 100644 index 0000000..840147c --- /dev/null +++ b/packages/stdlib/src/objects/omit/index.ts @@ -0,0 +1,38 @@ +import { isArray, type Arrayable } from '../../types'; + +/** + * @name omit + * @category Objects + * @description Returns a new object with the specified keys omitted + * + * @param {object} target - The object to omit keys from + * @param {Arrayable} keys - The keys to omit + * @returns {Omit} The new object with the specified keys omitted + * + * @example + * omit({ a: 1, b: 2, c: 3 }, 'a') // => { b: 2, c: 3 } + * + * @example + * omit({ a: 1, b: 2, c: 3 }, ['a', 'b']) // => { c: 3 } + * + * @since 0.0.3 + */ +export function omit( + target: Target, + keys: Arrayable +): Omit { + const result = { ...target }; + + if (!target || !keys) + return result; + + if (isArray(keys)) { + for (const key of keys) { + delete result[key]; + } + } else { + delete result[keys]; + } + + return result; +} From 23541a54766767b5cdde00e2183e0f5e9cf83dc4 Mon Sep 17 00:00:00 2001 From: robonen Date: Thu, 31 Oct 2024 00:48:24 +0700 Subject: [PATCH 2/4] feat(packages/stdlib): add pick object tool --- .../stdlib/src/objects/pick/index.test.ts | 36 ++++++++++++++++++ packages/stdlib/src/objects/pick/index.ts | 38 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 packages/stdlib/src/objects/pick/index.test.ts create mode 100644 packages/stdlib/src/objects/pick/index.ts diff --git a/packages/stdlib/src/objects/pick/index.test.ts b/packages/stdlib/src/objects/pick/index.test.ts new file mode 100644 index 0000000..48c088f --- /dev/null +++ b/packages/stdlib/src/objects/pick/index.test.ts @@ -0,0 +1,36 @@ +import { describe, it, expect } from 'vitest'; +import { pick } from '.'; + +describe('pick', () => { + it('pick a single key', () => { + const result = pick({ a: 1, b: 2, c: 3 }, 'a'); + + expect(result).toEqual({ a: 1 }); + }); + + it('pick multiple keys', () => { + const result = pick({ a: 1, b: 2, c: 3 }, ['a', 'b']); + + expect(result).toEqual({ a: 1, b: 2 }); + }); + + it('return an empty object when no keys are provided', () => { + const result = pick({ a: 1, b: 2 }, []); + + expect(result).toEqual({}); + }); + + it('handle non-existent keys by setting them to undefined', () => { + const result = pick({ a: 1, b: 2 }, ['a', 'c'] as any); + + expect(result).toEqual({ a: 1, c: undefined }); + }); + + it('return an empty object if target is null or undefined', () => { + const emptyTarget = pick(null as any, 'a'); + const emptyKeys = pick({ a: 1 }, null as any); + + expect(emptyTarget).toEqual({}); + expect(emptyKeys).toEqual({}); + }); +}); \ No newline at end of file diff --git a/packages/stdlib/src/objects/pick/index.ts b/packages/stdlib/src/objects/pick/index.ts new file mode 100644 index 0000000..9a0b167 --- /dev/null +++ b/packages/stdlib/src/objects/pick/index.ts @@ -0,0 +1,38 @@ +import { isArray, type Arrayable } from '../../types'; + +/** + * @name pick + * @category Objects + * @description Returns a partial copy of an object containing only the keys specified + * + * @param {object} target - The object to pick keys from + * @param {Arrayable} keys - The keys to pick + * @returns {Pick} The new object with the specified keys picked + * + * @example + * pick({ a: 1, b: 2, c: 3 }, 'a') // => { a: 1 } + * + * @example + * pick({ a: 1, b: 2, c: 3 }, ['a', 'b']) // => { a: 1, b: 2 } + * + * @since 0.0.3 + */ +export function pick( + target: Target, + keys: Arrayable +): Pick { + const result = {} as Pick; + + if (!target || !keys) + return result; + + if (isArray(keys)) { + for (const key of keys) { + result[key] = target[key]; + } + } else { + result[keys] = target[keys]; + } + + return result; +} \ No newline at end of file From 6408c1b3286e99432aed318dfb22f829f9726f0d Mon Sep 17 00:00:00 2001 From: robonen Date: Thu, 31 Oct 2024 00:48:55 +0700 Subject: [PATCH 3/4] feat(packages/stdlib): add object tools exports --- packages/stdlib/src/index.ts | 1 + packages/stdlib/src/objects/index.ts | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 packages/stdlib/src/objects/index.ts diff --git a/packages/stdlib/src/index.ts b/packages/stdlib/src/index.ts index 084c951..9e936f1 100644 --- a/packages/stdlib/src/index.ts +++ b/packages/stdlib/src/index.ts @@ -2,6 +2,7 @@ export * from './arrays'; export * from './async'; export * from './bits'; export * from './math'; +export * from './objects'; export * from './patterns'; export * from './structs'; export * from './text'; diff --git a/packages/stdlib/src/objects/index.ts b/packages/stdlib/src/objects/index.ts new file mode 100644 index 0000000..76705c5 --- /dev/null +++ b/packages/stdlib/src/objects/index.ts @@ -0,0 +1,2 @@ +export * from './omit'; +export * from './pick'; From dd0f481e19487dc0c2d4956e5185beac20752d56 Mon Sep 17 00:00:00 2001 From: robonen Date: Thu, 31 Oct 2024 00:50:08 +0700 Subject: [PATCH 4/4] chore(packages/stdlib): fix code style, stack pop and peek jsdoc --- packages/stdlib/src/arrays/cluster/index.test.ts | 6 ++++++ packages/stdlib/src/arrays/sum/index.test.ts | 7 +++++++ packages/stdlib/src/arrays/unique/index.test.ts | 6 ++++++ packages/stdlib/src/structs/stack/index.ts | 4 ++-- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/stdlib/src/arrays/cluster/index.test.ts b/packages/stdlib/src/arrays/cluster/index.test.ts index 1956c75..c0a8648 100644 --- a/packages/stdlib/src/arrays/cluster/index.test.ts +++ b/packages/stdlib/src/arrays/cluster/index.test.ts @@ -4,31 +4,37 @@ import { cluster } from '.'; describe('cluster', () => { it('cluster an array into subarrays of a specific size', () => { const result = cluster([1, 2, 3, 4, 5, 6, 7, 8], 3); + expect(result).toEqual([[1, 2, 3], [4, 5, 6], [7, 8]]); }); it('handle arrays that are not perfectly divisible by the size', () => { const result = cluster([1, 2, 3, 4, 5], 2); + expect(result).toEqual([[1, 2], [3, 4], [5]]); }); it('return an array with each element in its own subarray if size is 1', () => { const result = cluster([1, 2, 3, 4], 1); + expect(result).toEqual([[1], [2], [3], [4]]); }); it('return an array with a single subarray if size is greater than the array length', () => { const result = cluster([1, 2, 3], 5); + expect(result).toEqual([[1, 2, 3]]); }); it('return an empty array if size is less than or equal to 0', () => { const result = cluster([1, 2, 3, 4], -1); + expect(result).toEqual([]); }); it('return an empty array if the input array is empty', () => { const result = cluster([], 3); + expect(result).toEqual([]); }); }); \ No newline at end of file diff --git a/packages/stdlib/src/arrays/sum/index.test.ts b/packages/stdlib/src/arrays/sum/index.test.ts index a007487..6785353 100644 --- a/packages/stdlib/src/arrays/sum/index.test.ts +++ b/packages/stdlib/src/arrays/sum/index.test.ts @@ -4,36 +4,43 @@ import { sum } from '.'; describe('sum', () => { it('return the sum of all elements in a number array', () => { const result = sum([1, 2, 3, 4, 5]); + expect(result).toBe(15); }); it('return 0 for an empty array', () => { const result = sum([]); + expect(result).toBe(0); }); it('return the sum of all elements using a getValue function', () => { const result = sum([{ value: 1 }, { value: 2 }, { value: 3 }], (item) => item.value); + expect(result).toBe(6); }); it('handle arrays with negative numbers', () => { const result = sum([-1, -2, -3, -4, -5]); + expect(result).toBe(-15); }); it('handle arrays with mixed positive and negative numbers', () => { const result = sum([1, -2, 3, -4, 5]); + expect(result).toBe(3); }); it('handle arrays with floating point numbers', () => { const result = sum([1.5, 2.5, 3.5]); + expect(result).toBe(7.5); }); it('handle arrays with a getValue function returning floating point numbers', () => { const result = sum([{ value: 1.5 }, { value: 2.5 }, { value: 3.5 }], (item) => item.value); + expect(result).toBe(7.5); }); }); \ No newline at end of file diff --git a/packages/stdlib/src/arrays/unique/index.test.ts b/packages/stdlib/src/arrays/unique/index.test.ts index 4efcf04..bb4e30a 100644 --- a/packages/stdlib/src/arrays/unique/index.test.ts +++ b/packages/stdlib/src/arrays/unique/index.test.ts @@ -4,6 +4,7 @@ import { unique } from '.'; describe('unique', () => { it('return an array with unique numbers', () => { const result = unique([1, 2, 3, 3, 4, 5, 5, 6]); + expect(result).toEqual([1, 2, 3, 4, 5, 6]); }); @@ -12,16 +13,19 @@ describe('unique', () => { [{ id: 1 }, { id: 2 }, { id: 1 }], (item) => item.id, ); + expect(result).toEqual([{ id: 1 }, { id: 2 }]); }); it('return the same array if all elements are unique', () => { const result = unique([1, 2, 3, 4, 5]); + expect(result).toEqual([1, 2, 3, 4, 5]); }); it('handle arrays with different types of values', () => { const result = unique([1, '1', 2, '2', 2, 3, '3']); + expect(result).toEqual([1, '1', 2, '2', 3, '3']); }); @@ -29,11 +33,13 @@ describe('unique', () => { const sym1 = Symbol('a'); const sym2 = Symbol('b'); const result = unique([sym1, sym2, sym1]); + expect(result).toEqual([sym1, sym2]); }); it('return an empty array when given an empty array', () => { const result = unique([]); + expect(result).toEqual([]); }); }); \ No newline at end of file diff --git a/packages/stdlib/src/structs/stack/index.ts b/packages/stdlib/src/structs/stack/index.ts index 6a6d1af..20c30f5 100644 --- a/packages/stdlib/src/structs/stack/index.ts +++ b/packages/stdlib/src/structs/stack/index.ts @@ -84,7 +84,7 @@ export class Stack implements Iterable, AsyncIterable { /** * Pops an element from the stack - * @returns {T} The element popped from the stack + * @returns {T | undefined} The element popped from the stack */ public pop() { return this.stack.pop(); @@ -92,7 +92,7 @@ export class Stack implements Iterable, AsyncIterable { /** * Peeks at the top element of the stack - * @returns {T} The top element of the stack + * @returns {T | undefined} The top element of the stack */ public peek() { if (this.isEmpty)