diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 748ba93d..1b17cdad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,10 +1,10 @@ -name: CI +name: full-ci # Define the events that trigger the workflow on: pull_request_target: branches: - - main # Trigger on pull request to the main branch + - ci-testing # Trigger on pull request to the main branch workflow_dispatch: # Allow manual triggering of the workflow inputs: node_version: diff --git a/.gitignore b/.gitignore index 37e17bf4..5ee25e57 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,4 @@ build/ .vscode/ # Local Testing -.local-testing/ \ No newline at end of file +local-testing/* \ No newline at end of file diff --git a/functionsUnittests/objectFunctions/omitBy.test.ts b/functionsUnittests/objectFunctions/omitBy.test.ts new file mode 100644 index 00000000..0a1c55cc --- /dev/null +++ b/functionsUnittests/objectFunctions/omitBy.test.ts @@ -0,0 +1,85 @@ +import { omitBy } from '../../objectFunctions/omitBy'; + +describe('omitBy', () => { + // Test case 1: Omit properties based on value + it('Test case 1: should omit properties based on value', () => { + const obj = { a: 1, b: 2, c: 3 }; + const result = omitBy(obj, value => value > 1); + const expected = { a: 1 }; + expect(result).toEqual(expected); + }); + + // Test case 2: Omit properties based on key + it('Test case 2: should omit properties based on key', () => { + const obj = { a: 1, b: 2, c: 3 }; + const result = omitBy(obj, (value, key) => key === 'b'); + const expected = { a: 1, c: 3 }; + expect(result).toEqual(expected); + }); + + // Test case 3: Omit properties with different data types + it('Test case 3: should omit properties with different data types', () => { + const obj = { a: 1, b: 'string', c: true, d: null }; + const result = omitBy(obj, value => typeof value === 'string'); + const expected = { a: 1, c: true, d: null }; + expect(result).toEqual(expected); + }); + + // Test case 4: Omit no properties if predicate always returns false + it('Test case 4: should omit no properties if predicate always returns false', () => { + const obj = { a: 1, b: 2, c: 3 }; + const result = omitBy(obj, () => false); + const expected = { a: 1, b: 2, c: 3 }; + expect(result).toEqual(expected); + }); + + // Test case 5: Omit all properties if predicate always returns true + it('Test case 5: should omit all properties if predicate always returns true', () => { + const obj = { a: 1, b: 2, c: 3 }; + const result = omitBy(obj, () => true); + const expected = {}; + expect(result).toEqual(expected); + }); + + // Test case 6: Omit properties from an object with nested objects + it('Test case 6: should omit properties from an object with nested objects', () => { + const obj = { a: 1, b: { c: 2, d: 3 }, e: 4 }; + const result = omitBy(obj, value => typeof value === 'object'); + const expected = { a: 1, e: 4 }; + expect(result).toEqual(expected); + }); + + // Test case 7: Omit properties from an object with Date objects + it('Test case 7: should omit properties from an object with Date objects', () => { + const date = new Date(); + const obj = { a: 1, b: date, c: 3 }; + const result = omitBy(obj, value => value instanceof Date); + const expected = { a: 1, c: 3 }; + expect(result).toEqual(expected); + }); + + // Test case 8: Handle non-object input (number) + it('Test case 8: should throw a TypeError if input is a number', () => { + expect(() => omitBy(42 as any, value => value)).toThrow(TypeError); + }); + + // Test case 9: Handle non-object input (string) + it('Test case 9: should throw a TypeError if input is a string', () => { + expect(() => omitBy('string' as any, value => value)).toThrow(TypeError); + }); + + // Test case 10: Handle non-object input (boolean) + it('Test case 10: should throw a TypeError if input is a boolean', () => { + expect(() => omitBy(true as any, value => value)).toThrow(TypeError); + }); + + // Test case 11: Handle null input + it('Test case 11: should throw a TypeError if input is null', () => { + expect(() => omitBy(null as any, value => value)).toThrow(TypeError); + }); + + // Test case 12: Handle undefined input + it('Test case 12: should throw a TypeError if input is undefined', () => { + expect(() => omitBy(undefined as any, value => value)).toThrow(TypeError); + }); +}); \ No newline at end of file diff --git a/objectFunctions/future.ts b/objectFunctions/future.ts new file mode 100644 index 00000000..a5cb4471 --- /dev/null +++ b/objectFunctions/future.ts @@ -0,0 +1,109 @@ +// pickBy.ts +export function pickBy>( + obj: T, + predicate: (value: any, key: string) => boolean + ): Partial { + return Object.fromEntries( + Object.entries(obj).filter(([key, value]) => predicate(value, key)) + ); + } + + // groupBy.ts + export function groupBy( + array: T[], + key: keyof T + ): Record { + return array.reduce((acc, item) => { + const group = item[key] as unknown as string; + if (!acc[group]) acc[group] = []; + acc[group].push(item); + return acc; + }, {} as Record); + } + + // compactObject.ts + export function compactObject>(obj: T): Partial { + return Object.fromEntries( + Object.entries(obj).filter(([_, value]) => value != null) + ); + } + + // safeGet.ts + export function safeGet( + obj: T, + path: string, + defaultValue: any = undefined + ): any { + return path + .split('.') + .reduce((acc, key) => (acc && key in acc ? acc[key] : defaultValue), obj); + } + + // safeSet.ts + export function safeSet>( + obj: T, + path: string, + value: any + ): void { + const keys = path.split('.'); + let current: any = obj; + while (keys.length > 1) { + const key = keys.shift()!; + if (!(key in current)) current[key] = {}; + current = current[key]; + } + current[keys[0]] = value; + } + + // keyBy.ts + export function keyBy>( + array: T[], + key: keyof T + ): Record { + return Object.fromEntries(array.map(item => [item[key], item])); + } + + // entriesToObject.ts + export function entriesToObject(entries: [string, any][]): T { + return Object.fromEntries(entries) as T; + } + + // objectToEntries.ts + export function objectToEntries>(obj: T): [string, any][] { + return Object.entries(obj); + } + + // isDeepSubset.ts + export function isDeepSubset>(subset: T, obj: T): boolean { + return Object.keys(subset).every(key => + typeof subset[key] === 'object' && subset[key] !== null + ? isDeepSubset(subset[key], obj[key]) + : subset[key] === obj[key] + ); + } + + // objectSize.ts + export function objectSize(obj: Record): number { + return Object.keys(obj).length; + } + + // sortObjectKeys.ts + export function sortObjectKeys>(obj: T): T { + return Object.fromEntries(Object.entries(obj).sort(([a], [b]) => a.localeCompare(b))) as T; + } + + // differenceBy.ts + export function differenceBy>( + obj1: T, + obj2: T, + comparator: (a: any, b: any) => boolean + ): Partial { + return Object.fromEntries( + Object.entries(obj1).filter(([key, value]) => !comparator(value, obj2[key])) + ); + } + + // uniqueValues.ts + export function uniqueValues>(obj: T): any[] { + return [...new Set(Object.values(obj))]; + } \ No newline at end of file diff --git a/objectFunctions/omitBy.ts b/objectFunctions/omitBy.ts new file mode 100644 index 00000000..f0fa21bb --- /dev/null +++ b/objectFunctions/omitBy.ts @@ -0,0 +1,24 @@ +/** + * Creates an object composed of the properties of the input object that do not match the predicate. + * + * @param {Record} obj - The source object. + * @param {(value: any, key: string) => boolean} predicate - The function invoked per property. + * @returns {Partial>} - The new object. + */ +export function omitBy>( + obj: T, + predicate: (value: any, key: string) => boolean +): Partial { + if (typeof obj !== 'object' || obj === null) { + throw new TypeError('Input must be a non-null object'); + } + + return Object.fromEntries( + Object.entries(obj).filter(([key, value]) => !predicate(value, key)) + ) as Partial; +} + +// Example usage: +// const obj = { a: 1, b: 2, c: 3 }; +// const result = omitBy(obj, value => value === 2); +// console.log(result); // { a: 1, c: 3 } \ No newline at end of file