Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@semantic-ui/utils

Package Overview
Dependencies
Maintainers
1
Versions
48
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@semantic-ui/utils - npm Package Compare versions

Comparing version 0.0.3 to 0.0.5

10

package.json
{
"name": "@semantic-ui/utils",
"version": "0.0.3",
"version": "0.0.5",
"type": "module",

@@ -9,10 +9,2 @@ "main": "src/utils.js",

"license": "ISC",
"scripts": {
"publish": "wireit"
},
"wireit": {
"publish": {
"command": "npm publish"
}
},
"devDependencies": {

@@ -19,0 +11,0 @@ "vitest": "^1.5.2"

4

README.md

@@ -28,2 +28,3 @@ # @semantic-ui/utils

- `some/any(arr, truthFunc)` - Returns true if any/some values match truthFunc
- `sum(values)` - sums an array of numbers

@@ -44,2 +45,3 @@

- `reverseKeys(obj)` - Reverses a lookup object's keys and values.
- `arrayFromObject(obj) - Returns an array with key value pairs from an object

@@ -59,2 +61,3 @@ ### Types

- `isNode(x)` - Checks if the value is a DOM node.
- `isEmpty(x)` Checks if the value is empty like {}

@@ -77,2 +80,3 @@ ### Date

- `escapeRegExp(string)` - Escapes special characters in a string for use in a regular expression.
- `escapeHTML(string)` - Escapes string for html '&<>"' only

@@ -79,0 +83,0 @@ ### Looping

@@ -119,2 +119,19 @@ /*

};
export const isEmpty = (x) => {
// we want nullish here
if (x == null) {
return true;
}
if (isArray(x) || isString(x)) {
return x.length === 0;
}
for (let key in x) {
if (x[key]) {
return false;
}
}
return true;
};
/*-------------------

@@ -359,2 +376,6 @@ Date

export const sum = (values) => {
return values.reduce((acc, num) => acc + num, 0);
};
export const where = (array, properties) => {

@@ -380,2 +401,36 @@ return array.filter((obj) =>

export const sortBy = function (arr, key, comparator) {
const compare = (a, b) => {
const valA = get(a, key);
const valB = get(b, key);
if (valA === undefined && valB === undefined) return 0;
if (valA === undefined) return 1; // Place undefined values at the end
if (valB === undefined) return -1; // Place undefined values at the end
if (comparator) {
return comparator(valA, valB, a, b);
}
if (valA < valB) return -1;
if (valA > valB) return 1;
return 0;
};
return arr.slice().sort(compare);
};
export const groupBy = function(array, property) {
return array.reduce((result, obj) => {
const key = get(obj, property);
if (key !== undefined) {
if (!result[key]) {
result[key] = [];
}
result[key].push(obj);
}
return result;
}, {});
}
/*-------------------

@@ -435,3 +490,3 @@ Objects

export const pick = function (obj, ...keys) {
export const pick = (obj, ...keys) => {
let copy = {};

@@ -446,30 +501,84 @@ each(keys, function (key) {

export const arrayFromObject = (obj) => {
if(isArray(obj)) {
return obj;
}
let arr = [];
each(obj, (value, key) => {
arr.push({
value,
key,
});
});
return arr;
};
/*
Access a nested object field from a string, like 'a.b.c'
*/
export const get = function (obj, path = '') {
if (typeof path !== 'string') {
return undefined;
}
// map 'foo.1.baz' -> foo[1].baz'
const transformArrayRegExp = /\[(\w+)\]/g;
function extractArrayLikeAccess(part) {
const key = part.substring(0, part.indexOf('['));
const index = parseInt(part.substring(part.indexOf('[') + 1, part.indexOf(']')), 10);
return { key, index };
}
export const get = function (obj, string = '') {
if (typeof string !== 'string') {
function getCombinedKey(path) {
const dotIndex = path.indexOf('.');
if (dotIndex !== -1) {
const nextDotIndex = path.indexOf('.', dotIndex + 1);
if (nextDotIndex !== -1) {
return path.slice(0, nextDotIndex);
}
}
return path;
}
if (obj === null || !isObject(obj)) {
return undefined;
}
// Transform array notation to dot notation
const stringParts = string.replace(transformArrayRegExp, '.$1').split('.');
const parts = path.split('.');
let currentObject = obj;
for (let index = 0; index < stringParts.length; index++) {
const part = stringParts[index];
if (part === '') continue; // Skip empty parts that result from leading dots or consecutive dots.
// Check if the part exists in the current object
if (currentObject !== null && typeof currentObject === 'object' && part in currentObject) {
currentObject = currentObject[part];
} else {
// If the path breaks, return undefined
for (let i = 0; i < parts.length; i++) {
if (currentObject === null || !isObject(currentObject)) {
return undefined;
}
let part = parts[i];
if (part.includes('[')) {
const { key, index } = extractArrayLikeAccess(part);
if (key in currentObject && isArray(currentObject[key]) && index < currentObject[key].length) {
currentObject = currentObject[key][index];
} else {
return undefined;
}
} else {
if (part in currentObject) {
currentObject = currentObject[part];
} else {
const remainingPath = parts.slice(i).join('.');
if (remainingPath in currentObject) {
currentObject = currentObject[remainingPath];
break;
} else {
const combinedKey = getCombinedKey(`${part}.${parts[i + 1]}`);
if (combinedKey in currentObject) {
currentObject = currentObject[combinedKey];
i++;
} else {
return undefined;
}
}
}
}
}
return currentObject;

@@ -675,6 +784,22 @@ };

*/
export const escapeRegExp = function (string) {
export const escapeRegExp = (string) => {
return string.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
};
export const escapeHTML = (string) => {
const htmlEscapes = {
'&': '&amp',
'<': '&lt',
'>': '&gt',
'"': '&quot',
"\'": '&#39'
};
const htmlRegExp = /[&<>"']/g;
const hasHTML = RegExp(htmlRegExp.source);
return (string && hasHTML.test(string))
? string.replace(htmlRegExp, (chr) => htmlEscapes[chr])
: string
;
};
/*-------------------

@@ -685,4 +810,5 @@ Identity

export const tokenize = (str = '') => {
return (str).replace(/\s+/g, '-')
return (str || '').replace(/\s+/g, '-')
.replace(/[^\w-]+/g, '')
.replace(/_/g, '-')
.toLowerCase()

@@ -689,0 +815,0 @@ ;

@@ -1,5 +0,15 @@

import { describe, expect, it, vi } from 'vitest';
import { clone } from '@semantic-ui/utils';
import { describe, expect, beforeEach, afterEach, afterAll, beforeAll, it, vi } from 'vitest';
import { clone, copyText, getText, isDOM, fatal } from '@semantic-ui/utils';
beforeAll(() => {
vi.spyOn(console, 'error').mockImplementation((...args) => {
throw new Error(`Unhandled Console Error: ${args.join(' ')}`);
});
});
afterAll(() => {
console.error.mockRestore();
});
describe('clone', () => {

@@ -13,2 +23,98 @@

});
});
describe('copyText', () => {
it('should call navigator.clipboard.writeText with the provided text', () => {
const writeTextMock = vi.fn();
global.navigator = {
clipboard: {
writeText: writeTextMock,
},
};
const text = 'Test text';
copyText(text);
expect(writeTextMock).toHaveBeenCalledWith(text);
});
});
describe('getText', () => {
it('should fetch the text content from the provided source', async () => {
const mockResponse = 'Test text';
global.fetch = vi.fn().mockResolvedValue({
text: () => Promise.resolve(mockResponse),
});
const src = 'https://example.com/test.txt';
const result = await getText(src);
expect(fetch).toHaveBeenCalledWith(src);
expect(result).toBe(mockResponse);
});
});
describe('isDOM', () => {
it('should return true for Element instances', () => {
const element = document.createElement('div');
expect(isDOM(element)).toBe(true);
});
it('should return true for Document instances', () => {
expect(isDOM(document)).toBe(true);
});
it('should return true for window', () => {
expect(isDOM(window)).toBe(true);
});
it('should return true for DocumentFragment instances', () => {
const fragment = document.createDocumentFragment();
expect(isDOM(fragment)).toBe(true);
});
});
/* Need to fix this
describe('fatal', () => {
let originalOnError;
beforeEach(() => {
originalOnError = global.onError;
global.onError = vi.fn();
});
afterEach(() => {
global.onError = originalOnError;
});
it('should throw an error with the provided message', async () => {
await expect(new Promise((resolve, reject) => {
try {
fatal('Test error', { onError: reject });
} catch (error) {
reject(error);
}
})).rejects.toThrow('Test error');
});
it('should attach provided metadata to the error', async () => {
const metadata = { code: 'ERR_TEST' };
await expect(new Promise((resolve, reject) => {
try {
fatal('Test error', { metadata, onError: reject });
} catch (error) {
reject(error);
}
})).rejects.toHaveProperty('code', 'ERR_TEST');
});
it('should modify the error stack based on removeStackLines option', async () => {
await expect(new Promise((resolve, reject) => {
try {
fatal('Test error', { removeStackLines: 2, onError: reject });
} catch (error) {
reject(error);
}
})).rejects.toSatisfy((error) => {
return error.stack.split('\n').length < new Error().stack.split('\n').length;
});
});
});
*/
import { describe, expect, it, vi } from 'vitest';
import { each, clone, unique, filterEmpty, last, firstMatch, findIndex, remove, inArray, range, keys, values, mapObject, extend, pick, get, hasProperty, reverseKeys, isObject, isPlainObject, isString, isNumber, isArray, isBinary, isFunction, isPromise, isArguments, formatDate, noop, wrapFunction, kebabToCamel, camelToKebab, capitalizeWords, toTitleCase, escapeRegExp, prettifyID, hashCode, generateID, isEqual, fatal } from '@semantic-ui/utils';
import { tokenize,
asyncEach,
asyncMap,
camelToKebab,
capitalizeWords,
clone,
each,
escapeHTML,
escapeRegExp,
extend,
filterEmpty,
findIndex,
firstMatch,
formatDate,
generateID,
get,
groupBy,
hashCode,
hasProperty,
inArray,
isArguments,
isArray,
isBinary,
isEqual,
isFunction,
isNumber,
isObject,
isPlainObject,
isPromise,
isString,
kebabToCamel,
keys,
last,
mapObject,
noop,
pick,
prettifyID,
range,
remove,
reverseKeys,
sortBy,
toTitleCase,
tokenize,
unique,
values,
where,
wrapFunction
} from '@semantic-ui/utils';

@@ -57,2 +104,17 @@ describe('Array Utilities', () => {

describe('where', () => {
it('should filter an array of objects based on properties', () => {
const array = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' },
{ id: 3, name: 'John' },
];
const result = where(array, { name: 'John' });
expect(result).toEqual([
{ id: 1, name: 'John' },
{ id: 3, name: 'John' },
]);
});
});
});

@@ -119,3 +181,115 @@

});
describe('groupBy', () => {
it('should group objects by a simple property', () => {
const array = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 30 },
{ name: 'Charlie', age: 25 },
];
const expected = {
'25': [
{ name: 'Alice', age: 25 },
{ name: 'Charlie', age: 25 },
],
'30': [
{ name: 'Bob', age: 30 },
],
};
expect(groupBy(array, 'age')).toEqual(expected);
});
it('should group objects by a nested property', () => {
const array = [
{ name: 'Alice', details: { city: 'New York' } },
{ name: 'Bob', details: { city: 'London' } },
{ name: 'Charlie', details: { city: 'New York' } },
];
const expected = {
'New York': [
{ name: 'Alice', details: { city: 'New York' } },
{ name: 'Charlie', details: { city: 'New York' } },
],
'London': [
{ name: 'Bob', details: { city: 'London' } },
],
};
expect(groupBy(array, 'details.city')).toEqual(expected);
});
it('should handle an empty array', () => {
const array = [];
const expected = {};
expect(groupBy(array, 'age')).toEqual(expected);
});
it('should handle objects with missing property', () => {
const array = [
{ name: 'Alice', age: 25 },
{ name: 'Bob' },
{ name: 'Charlie', age: 30 },
];
const expected = {
'25': [
{ name: 'Alice', age: 25 },
],
'30': [
{ name: 'Charlie', age: 30 },
],
};
expect(groupBy(array, 'age')).toEqual(expected);
});
it('should handle a property that does not exist on any objects', () => {
const array = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 30 },
{ name: 'Charlie', age: 25 },
];
const expected = {};
expect(groupBy(array, 'city')).toEqual(expected);
});
});
describe('sortBy', () => {
it('should sort by a simple key', () => {
const input = [{a: 2}, {a: 3}, {a: 1}];
const expected = [{a: 1}, {a: 2}, {a: 3}];
expect(sortBy(input, 'a')).toEqual(expected);
});
it('should sort by a nested key', () => {
const input = [{a: {b: 2}}, {a: {b: 3}}, {a: {b: 1}}];
const expected = [{a: {b: 1}}, {a: {b: 2}}, {a: {b: 3}}];
expect(sortBy(input, 'a.b')).toEqual(expected);
});
it('should handle custom comparator', () => {
const input = [{a: 1}, {a: 2}, {a: 3}];
const expected = [{a: 3}, {a: 2}, {a: 1}];
const reverseComparator = (a, b) => b - a;
expect(sortBy(input, 'a', reverseComparator)).toEqual(expected);
});
it('should handle sorting with additional object context in comparator', () => {
const input = [{a: 1, b: 2}, {a: 1, b: 1}];
const expected = [{a: 1, b: 1}, {a: 1, b: 2}];
const comparator = (valA, valB, objA, objB) => objA.b - objB.b;
expect(sortBy(input, 'a', comparator)).toEqual(expected);
});
it('should return a new array and not mutate the original', () => {
const input = [{a: 1}, {a: 2}];
const result = sortBy(input, 'a');
expect(result).not.toBe(input);
expect(result).toEqual([{a: 1}, {a: 2}]);
});
it('should sort objects with undefined values last', () => {
const input = [{a: 1}, {a: undefined}, {a: 2}];
const expected = [{a: 1}, {a: 2}, {a: undefined}];
expect(sortBy(input, 'a')).toEqual(expected);
});
});
});

@@ -134,57 +308,110 @@

it('keys should return the keys of an object', () => {
expect(keys({ a: 1, b: 2 })).toEqual(['a', 'b']);
expect(keys([1, 2, 3])).toEqual(['0', '1', '2']);
describe('keys', () => {
it('keys should return the keys of an object', () => {
expect(keys({ a: 1, b: 2 })).toEqual(['a', 'b']);
expect(keys([1, 2, 3])).toEqual(['0', '1', '2']);
});
});
it('values should return the values of an object', () => {
expect(values({ a: 1, b: 2 })).toEqual([1, 2]);
expect(values([1, 2, 3])).toEqual([1, 2, 3]);
describe('values', () => {
it('values should return the values of an object', () => {
expect(values({ a: 1, b: 2 })).toEqual([1, 2]);
expect(values([1, 2, 3])).toEqual([1, 2, 3]);
});
});
it('mapObject should create an object with the same keys and mapped values', () => {
const result = mapObject({ a: 1, b: 2 }, (val) => val * 2);
expect(result).toEqual({ a: 2, b: 4 });
describe('mapObject', () => {
it('mapObject should create an object with the same keys and mapped values', () => {
const result = mapObject({ a: 1, b: 2 }, (val) => val * 2);
expect(result).toEqual({ a: 2, b: 4 });
});
});
it('extend should merge properties from source into target, including getters and setters', () => {
const target = { a: 1 };
const source = {
get b() { return 2; },
set b(val) { this.c = val; }
};
extend(target, source);
expect(target.b).toBe(2);
target.b = 3;
expect(target.c).toBe(3);
describe('extend', () => {
it('extend should merge properties from source into target, including getters and setters', () => {
const target = { a: 1 };
const source = {
get b() { return 2; },
set b(val) { this.c = val; }
};
extend(target, source);
expect(target.b).toBe(2);
target.b = 3;
expect(target.c).toBe(3);
});
});
it('pick should create an object composed of the picked properties', () => {
const obj = { a: 1, b: 2, c: 3 };
expect(pick(obj, 'a', 'c')).toEqual({ a: 1, c: 3 });
describe('pick', () => {
it('pick should create an object composed of the picked properties', () => {
const obj = { a: 1, b: 2, c: 3 };
expect(pick(obj, 'a', 'c')).toEqual({ a: 1, c: 3 });
});
});
it('get should access a nested object field from a string', () => {
const obj = { a: { b: { c: 1 } } };
expect(get(obj, 'a.b.c')).toBe(1);
expect(get(obj, 'a.b.c.d')).toBeUndefined();
});
describe('get', () => {
it('hasProperty should return true if the object has the specified property', () => {
const obj = { a: 1, b: undefined };
expect(hasProperty(obj, 'a')).toBe(true);
expect(hasProperty(obj, 'b')).toBe(true);
expect(hasProperty(obj, 'c')).toBe(false);
it('get should support array like "arr.1.value" notation in lookup', () => {
const obj = { arr: [{ value: 1 }, { value: 2 }] };
expect(get(obj, 'arr.1.value')).toBe(2);
});
it('get should access a nested object field from a string', () => {
const obj = { a: { b: { c: 1 } } };
expect(get(obj, 'a.b.c')).toBe(1);
expect(get(obj, 'a.b.c.d')).toBeUndefined();
});
it('get should support files with "." in the key', () => {
const obj = { 'a.b': 1 };
expect(get(obj, 'a.b')).toBe(1);
});
it('get should support deeply nested files with "." in the key', () => {
const obj = { a: { 'b.c': 1 } };
expect(get(obj, 'a.b.c')).toBe(1);
});
it('get should return undefined when accessing a non-existent nested key', () => {
const obj = { a: { b: { c: 1 } } };
expect(get(obj, 'a.b.d')).toBeUndefined();
});
it('get should support accessing nested keys with dots and array indexes', () => {
const obj = { 'a.b': [{ 'c.d': 1 }, { 'c.d': 2 }] };
expect(get(obj, 'a.b.1.c.d')).toBe(2);
});
it('get should return undefined when accessing an out-of-bounds array index', () => {
const obj = { arr: [1, 2, 3] };
expect(get(obj, 'arr.3')).toBeUndefined();
});
it('get should return undefined when accessing a non-existent array index', () => {
const obj = { a: { b: [1, 2, 3] } };
expect(get(obj, 'a.c.1')).toBeUndefined();
});
});
it('reverseKeys should reverse a lookup object\'s keys and values', () => {
const obj = { a: 1, b: [1, 2], c: 2 };
const reversed = reverseKeys(obj);
expect(reversed).toEqual({ '1': ['a', 'b'], '2': ['b', 'c'] });
describe('hasProperty', () => {
it('hasProperty should return true if the object has the specified property', () => {
const obj = { a: 1, b: undefined };
expect(hasProperty(obj, 'a')).toBe(true);
expect(hasProperty(obj, 'b')).toBe(true);
expect(hasProperty(obj, 'c')).toBe(false);
});
});
it('reverseKeys should reverse array values', () => {
const obj = { a: [1, 2], b: [2, 3], c: 1 };
const reversed = reverseKeys(obj);
expect(reversed).toEqual({ '1': ['a', 'c'], '2': ['a', 'b'], '3': 'b' });
describe('reverseKeys', () => {
it('reverseKeys should reverse a lookup object\'s keys and values', () => {
const obj = { a: 1, b: [1, 2], c: 2 };
const reversed = reverseKeys(obj);
expect(reversed).toEqual({ '1': ['a', 'b'], '2': ['b', 'c'] });
});
it('reverseKeys should reverse array values', () => {
const obj = { a: [1, 2], b: [2, 3], c: 1 };
const reversed = reverseKeys(obj);
expect(reversed).toEqual({ '1': ['a', 'c'], '2': ['a', 'b'], '3': 'b' });
});
});

@@ -380,2 +607,10 @@

describe('tokenize', () => {
it('should convert a string to a token', () => {
expect(tokenize('Hello World')).toBe('hello-world');
expect(tokenize('A simple-test_string')).toBe('a-simple-test-string');
});
});
describe('prettifyID', () => {

@@ -522,16 +757,97 @@ it('should return "0" for input 0', () => {

describe('regular expression utilities', () => {
it('should escape characters that have special meaning in regex', () => {
const specialChars = '. * + ? ^ $ { } ( ) | [ ] \\';
const escaped = escapeRegExp(specialChars);
expect(() => new RegExp(escaped)).not.toThrow();
describe('escapeRegExp', () => {
it('should escape characters that have special meaning in regex', () => {
const specialChars = '. * + ? ^ $ { } ( ) | [ ] \\';
const escaped = escapeRegExp(specialChars);
expect(() => new RegExp(escaped)).not.toThrow();
});
});
describe('escapeHTML', () => {
it('should escape only HTML tag characters', () => {
const input = '<div>Hello "World"</div>';
const expected = '&ltdiv&gtHello &quotWorld&quot&lt/div&gt';
expect(escapeHTML(input)).toBe(expected);
});
it('should not modify a string without special characters', () => {
const input = 'Hello World';
expect(escapeHTML(input)).toBe(input);
});
});
});
describe('each iterator utility', () => {
describe('iterators', () => {
describe('Array iteration', () => {
it('should iterate over all elements', () => {
describe('each', () => {
describe('Array iteration', () => {
it('should iterate over all elements', () => {
const array = [1, 2, 3];
const spy = vi.fn();
each(array, spy);
expect(spy).toHaveBeenCalledTimes(3);
expect(spy).toHaveBeenNthCalledWith(1, 1, 0, array);
expect(spy).toHaveBeenNthCalledWith(2, 2, 1, array);
expect(spy).toHaveBeenNthCalledWith(3, 3, 2, array);
});
it('should break early if the callback returns false', () => {
const array = [1, 2, 3];
const spy = vi.fn().mockReturnValueOnce(true).mockReturnValueOnce(false);
each(array, spy);
expect(spy).toHaveBeenCalledTimes(2);
});
});
describe('Object iteration', () => {
it('should iterate over all properties', () => {
const obj = { a: 1, b: 2, c: 3 };
const spy = vi.fn();
each(obj, spy);
expect(spy).toHaveBeenCalledTimes(3);
expect(spy).toHaveBeenCalledWith(1, 'a', obj);
expect(spy).toHaveBeenCalledWith(2, 'b', obj);
expect(spy).toHaveBeenCalledWith(3, 'c', obj);
});
it('should break early if the callback returns false', () => {
const obj = { a: 1, b: 2, c: 3 };
const spy = vi.fn().mockReturnValueOnce(true).mockReturnValueOnce(false);
each(obj, spy);
expect(spy).toHaveBeenCalledTimes(2);
});
it('should not iterate over non-enumerable properties', () => {
const obj = { a: 1, b: 2 };
Object.defineProperty(obj, 'c', {
value: 3,
enumerable: false,
});
const spy = vi.fn();
each(obj, spy);
expect(spy).toHaveBeenCalledTimes(2); // should not include non-enumerable 'c'
expect(spy).toHaveBeenCalledWith(1, 'a', obj);
expect(spy).toHaveBeenCalledWith(2, 'b', obj);
expect(spy).not.toHaveBeenCalledWith(3, 'c', obj); // ensure 'c' is not iterated
});
});
it('should handle null/undefined gracefully', () => {
const spy = vi.fn();
each(null, spy);
each(undefined, spy);
expect(spy).not.toHaveBeenCalled();
});
});
describe('asyncEach', () => {
it('should iterate over an array asynchronously', async () => {
const array = [1, 2, 3];
const spy = vi.fn();
each(array, spy);
await asyncEach(array, spy);
expect(spy).toHaveBeenCalledTimes(3);

@@ -543,51 +859,31 @@ expect(spy).toHaveBeenNthCalledWith(1, 1, 0, array);

it('should break early if the callback returns false', () => {
const array = [1, 2, 3];
const spy = vi.fn().mockReturnValueOnce(true).mockReturnValueOnce(false);
each(array, spy);
expect(spy).toHaveBeenCalledTimes(2);
it('should handle null/undefined gracefully', async () => {
const spy = vi.fn();
await asyncEach(null, spy);
await asyncEach(undefined, spy);
expect(spy).not.toHaveBeenCalled();
});
});
describe('Object iteration', () => {
it('should iterate over all properties', () => {
const obj = { a: 1, b: 2, c: 3 };
const spy = vi.fn();
each(obj, spy);
expect(spy).toHaveBeenCalledTimes(3);
expect(spy).toHaveBeenCalledWith(1, 'a', obj);
expect(spy).toHaveBeenCalledWith(2, 'b', obj);
expect(spy).toHaveBeenCalledWith(3, 'c', obj);
describe('asyncMap', () => {
it('should map an array asynchronously', async () => {
const array = [1, 2, 3];
const result = await asyncMap(array, async (value) => value * 2);
expect(result).toEqual([2, 4, 6]);
});
it('should break early if the callback returns false', () => {
it('should map an object asynchronously', async () => {
const obj = { a: 1, b: 2, c: 3 };
const spy = vi.fn().mockReturnValueOnce(true).mockReturnValueOnce(false);
each(obj, spy);
expect(spy).toHaveBeenCalledTimes(2);
const result = await asyncMap(obj, async (value) => value * 2);
expect(result).toEqual({ a: 2, b: 4, c: 6 });
});
it('should not iterate over non-enumerable properties', () => {
const obj = { a: 1, b: 2 };
Object.defineProperty(obj, 'c', {
value: 3,
enumerable: false,
});
const spy = vi.fn();
each(obj, spy);
expect(spy).toHaveBeenCalledTimes(2); // should not include non-enumerable 'c'
expect(spy).toHaveBeenCalledWith(1, 'a', obj);
expect(spy).toHaveBeenCalledWith(2, 'b', obj);
expect(spy).not.toHaveBeenCalledWith(3, 'c', obj); // ensure 'c' is not iterated
it('should handle null/undefined gracefully', async () => {
const result1 = await asyncMap(null, async (value) => value);
expect(result1).toBeNull();
const result2 = await asyncMap(undefined, async (value) => value);
expect(result2).toBeUndefined();
});
});
it('should handle null/undefined gracefully', () => {
const spy = vi.fn();
each(null, spy);
each(undefined, spy);
expect(spy).not.toHaveBeenCalled();
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc