New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

object-array-utils

Package Overview
Dependencies
Maintainers
1
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

object-array-utils - npm Package Compare versions

Comparing version
4.0.0
to
5.0.0
+51
-50
dist/index.d.ts

@@ -1,55 +0,56 @@

export declare type ObjectLiteral<T = unknown> = Record<string, T>;
export declare type ObjectInstance<T = unknown> = {
constructor: Function;
[key: string]: unknown;
};
export declare type Primitive = string | number | bigint | boolean | symbol | null | undefined;
declare function isNullOrUndefined(v: unknown): boolean;
declare function isObject(o: unknown): o is ObjectInstance | ObjectLiteral;
declare function isObjectLiteral(o: unknown): o is ObjectLiteral;
declare function isEmptyObjectLiteral(o: unknown): o is {};
declare function isObjectInstance(o: unknown): o is ObjectInstance;
declare function isArray(a: unknown): a is unknown[];
export type PlainObject<T = unknown> = Record<string, T>;
export type Primitive = string | number | bigint | boolean | symbol | null | undefined;
declare function isPrimitive(v: unknown): v is Primitive;
declare function isNullOrUndefined(v: unknown): v is null | undefined;
declare function isPrimitiveWrapper(o: unknown): o is Number | String | Boolean;
type Unboxed<T> = T extends Number ? number : T extends String ? string : T extends Boolean ? boolean : T;
declare function unboxPrimitiveWrapper<T>(v: T): Unboxed<T>;
declare function isEmptyArray(a: unknown): a is [];
declare function isArrayOfObjects(a: unknown): a is (ObjectInstance | ObjectLiteral)[];
declare function isArrayOfObjectLiterals(a: unknown): a is ObjectLiteral[];
declare function isArrayOfPrimitives(a: unknown): a is Primitive[];
declare function isArrayOfType<T extends string | number | boolean>(a: unknown, type: T extends string ? 'string' : T extends number ? 'number' : 'boolean'): a is Array<T>;
declare function isArrayWhereEvery<T>(a: unknown, fun: (value: unknown) => boolean): a is Array<T>;
declare function isObjectLiteralWhereEvery<T>(o: unknown, fun: (value: unknown) => boolean): o is ObjectLiteral<T>;
declare function areValuesEqual(a: unknown, b: unknown): boolean;
declare function isPlainObject(o: unknown): o is PlainObject;
declare function isEmptyPlainObject(o: unknown): o is {};
declare function isArrayWhereEvery<T>(a: unknown, predicate: (v: unknown) => v is T): a is T[];
declare function isPlainObjectWhereEvery<T>(o: unknown, predicate: (v: unknown) => v is T): o is PlainObject<T>;
export declare enum ComparisonResult {
Equal = "EQUAL",
NotEqual = "NOT_EQUAL",
DefaultComparison = "DEFAULT_COMPARISON"
UseDefault = "USE_DEFAULT"
}
declare type AreEqualOptions = {
compare: (a: any, b: any) => ComparisonResult;
export type ComparePlainObjects = {
(a: PlainObject, b: PlainObject): ComparisonResult;
};
declare function areObjectsEqual(a: ObjectLiteral | ObjectInstance, b: ObjectLiteral | ObjectInstance, options?: AreEqualOptions): boolean;
declare function areArraysEqual(a: unknown[], b: unknown[], options?: AreEqualOptions): boolean;
declare function hasProperty(o: ObjectInstance | ObjectLiteral, prop: string): boolean;
declare function hasProperties(o: ObjectInstance | ObjectLiteral, props: string[]): boolean;
declare function filterProperties<T = unknown>(o: object, arg: string[] | ((key: string, val: T) => boolean)): {};
declare function rejectProperties<T = unknown>(o: object, arg: string[] | ((key: string, val: T) => boolean)): {
[k: string]: any;
export type AreNonPlainObjectsEqual = {
(a: object, b: object): boolean;
};
declare function takeProperties<T = unknown>(o: object, arg: string[] | ((key: string, val: T) => boolean)): {
filtered: {};
rejected: {};
undefined: {};
type EqualOptions = {
comparePlainObjects?: ComparePlainObjects;
areNonPlainObjectsEqual: AreNonPlainObjectsEqual;
unboxPrimitives: boolean;
unorderedArrays: true;
};
declare function areDataEqual(x: unknown, y: unknown, opts: EqualOptions): boolean;
declare function arePlainObjectsEqual(a: PlainObject, b: PlainObject, options: EqualOptions): boolean;
declare function areArraysEqual(a: readonly unknown[], b: readonly unknown[], options: EqualOptions): boolean;
declare function hasProperty(o: object, prop: string): boolean;
declare function hasProperties(o: object, props: string[]): boolean;
type KeyPredicate<T> = (key: string, val: T) => boolean;
export declare function copyOwnStrings<T, K extends string = string>(src: Record<K, T>, filter: (key: K, value: T) => boolean): Record<K, T>;
declare function pickProperties<T = unknown>(obj: object, arg: string[] | KeyPredicate<T>): Record<string, unknown>;
declare function omitProperties<T = unknown>(obj: object, arg: string[] | KeyPredicate<T>): Record<string, unknown>;
declare function partitionProperties<T = unknown>(obj: object, arg: string[] | KeyPredicate<T>): {
picked: Record<string, unknown>;
omitted: Record<string, unknown>;
missingKeys: string[];
};
declare function removeArrayElements<T = unknown>(array: T[], listOfValues: T[]): T[];
declare function removeArrayElement<T = unknown>(array: T[], valueOrFun: T | ((value: T) => boolean)): T[];
declare function removeArrayElement<T = unknown>(array: T[], valueOrPredicate: T | ((value: T) => boolean)): T[];
declare function removeArrayElementByIndex<T = unknown>(array: T[], index: number): T[];
declare function differenceArraysOfPrimitives<T extends Primitive>(a1: T[], a2: T[]): T[];
declare function isObjectSubset(superObject: ObjectInstance | ObjectLiteral, subObject: ObjectInstance | ObjectLiteral): boolean;
declare function isArraySubset(superArray: unknown[], subArray: unknown[]): boolean;
declare function isPrimitive(value: unknown): boolean;
declare function cloneShape<T = unknown>(value: T): T;
declare function deepFreeze(o: unknown[] | ObjectInstance | ObjectLiteral): Readonly<ObjectInstance<unknown> | ObjectLiteral<unknown> | unknown[]>;
declare function sortProperties(o: ObjectLiteral): {
[k: string]: unknown;
};
declare type RangeOptionsWithCount = {
declare function differencePrimitives<T extends Primitive>(a1: readonly T[], a2: readonly T[]): T[];
export declare function isDataSubset(sup: unknown, sub: unknown, opts: EqualOptions): boolean;
declare function isPlainObjectSubset(sup: PlainObject, sub: PlainObject, opt: EqualOptions): boolean;
declare function isArraySubset(supArr: readonly unknown[], subArr: readonly unknown[], opt: EqualOptions): boolean;
declare function deepClonePlain<T = unknown>(value: T): T;
type ObjectOrArray = unknown[] | Record<string | number | symbol, unknown>;
declare function deepFreezePlain<T extends ObjectOrArray>(root: T): Readonly<T>;
declare function toSortedObject(o: PlainObject): PlainObject<unknown>;
type RangeOptionsWithCount = {
start?: number;

@@ -60,3 +61,3 @@ count: number;

};
declare type RangeOptionsWithEndInclusive = {
type RangeOptionsWithEndInclusive = {
start?: number;

@@ -67,3 +68,3 @@ count?: never;

};
declare type RangeOptionsWithEndExclusive = {
type RangeOptionsWithEndExclusive = {
start?: number;

@@ -74,6 +75,6 @@ count?: never;

};
declare type RangeOptions = RangeOptionsWithCount | RangeOptionsWithEndInclusive | RangeOptionsWithEndExclusive;
type RangeOptions = RangeOptionsWithCount | RangeOptionsWithEndInclusive | RangeOptionsWithEndExclusive;
declare function range(options: RangeOptions): number[];
declare function duplicate<T = unknown>(value: T, count: number, transformFun?: (v: T, _i: number) => T): T[];
declare function unique<T>(a: T[], fun?: (val: T) => unknown): T[];
export { areArraysEqual, areObjectsEqual, areValuesEqual, cloneShape, deepFreeze, differenceArraysOfPrimitives, duplicate, filterProperties, hasProperty, hasProperties, isArray, isArrayOfObjects, isArrayOfObjectLiterals, isArrayOfPrimitives, isArrayOfType, isArraySubset, isArrayWhereEvery, isEmptyArray, isEmptyObjectLiteral, isNullOrUndefined, isObject, isObjectInstance, isObjectLiteral, isObjectLiteralWhereEvery, isObjectSubset, isPrimitive, range, rejectProperties, removeArrayElement, removeArrayElementByIndex, removeArrayElements, sortProperties, takeProperties, unique };
declare function repeat<T = unknown>(value: T, count: number, transformFun?: (v: T, _i: number) => T): T[];
declare function unique<T, K = T>(array: readonly T[], keyFn?: (item: T) => K): T[];
export { areArraysEqual, arePlainObjectsEqual, areDataEqual, deepClonePlain, deepFreezePlain, differencePrimitives, repeat, pickProperties, hasProperty, hasProperties, isArraySubset, isArrayWhereEvery, isEmptyArray, isEmptyPlainObject, isNullOrUndefined, isPlainObject, isPlainObjectWhereEvery, isPlainObjectSubset, isPrimitive, isPrimitiveWrapper, range, omitProperties, removeArrayElement, removeArrayElementByIndex, removeArrayElements, toSortedObject, unboxPrimitiveWrapper, partitionProperties, unique };

@@ -0,84 +1,31 @@

function isPrimitive(v) {
return v == null || (typeof v !== 'object' && typeof v !== 'function');
}
function isNullOrUndefined(v) {
return v === null || v === undefined;
return v == null; // matches both null and undefined
}
function isObject(o) {
return isObjectLiteral(o) || isObjectInstance(o);
function isPrimitiveWrapper(o) {
return o instanceof Number || o instanceof String || o instanceof Boolean;
}
function isObjectLiteral(o) {
return !isNullOrUndefined(o) && Object.getPrototypeOf(o) === Object.prototype;
function unboxPrimitiveWrapper(v) {
return (isPrimitiveWrapper(v) ? v.valueOf() : v);
}
function isEmptyObjectLiteral(o) {
return isObjectLiteral(o) && Object.keys(o).length === 0;
}
function isObjectInstance(o) {
return !isNullOrUndefined(o)
&& !isArray(o)
&& Object.getPrototypeOf(o) !== Object.prototype
&& typeof o === 'object';
}
function isArray(a) {
return !isNullOrUndefined(a) && Array.isArray(a);
}
function isEmptyArray(a) {
return isArray(a) && a.length === 0;
return Array.isArray(a) && a.length === 0;
}
function isArrayOfObjects(a) {
if (!isArray(a) || a.length === 0) {
function isPlainObject(o) {
if (o == null || typeof o !== 'object')
return false;
}
return !a.some(o => !isObject(o));
const proto = Object.getPrototypeOf(o);
return proto === Object.prototype || proto === null;
}
function isArrayOfObjectLiterals(a) {
if (!isArray(a) || a.length === 0) {
return false;
}
return !a.some(o => !isObjectLiteral(o));
function isEmptyPlainObject(o) {
return isPlainObject(o) && Object.keys(o).length === 0;
}
function isArrayOfPrimitives(a) {
if (!isArray(a) || a.length === 0) {
return false;
}
return !a.some(o => !isPrimitive(o));
function isArrayWhereEvery(a, predicate) {
return Array.isArray(a) && a.every(predicate);
}
function isArrayOfType(a, type) {
if (!isArray(a) || a.length === 0) {
return false;
}
return !a.some(o => typeof o !== type);
function isPlainObjectWhereEvery(o, predicate) {
return isPlainObject(o) && Object.values(o).every(predicate);
}
function isArrayWhereEvery(a, fun) {
if (!isArray(a) || a.length === 0) {
return false;
}
return !a.some(o => !fun(o));
}
function isObjectLiteralWhereEvery(o, fun) {
if (!isObjectLiteral(o) || isEmptyObjectLiteral(o)) {
return false;
}
return isArrayWhereEvery(Object.values(o), fun);
}
function areValuesEqual(a, b) {
if (a === b)
return true;
if (!a || !b)
return false;
if (typeof a !== typeof b)
return false;
if (isArray(a) !== isArray(b))
return false;
if (isArray(a)) {
if (!areArraysEqual(a, b))
return false;
return true;
}
if (isObject(a) !== isObject(b))
return false;
if (isObject(a)) {
if (!areObjectsEqual(a, b))
return false;
return true;
}
return false;
}
export var ComparisonResult;

@@ -88,59 +35,45 @@ (function (ComparisonResult) {

ComparisonResult["NotEqual"] = "NOT_EQUAL";
ComparisonResult["DefaultComparison"] = "DEFAULT_COMPARISON";
ComparisonResult["UseDefault"] = "USE_DEFAULT";
})(ComparisonResult || (ComparisonResult = {}));
function areObjectsEqual(a, b, options) {
if (!isObject(a) || !isObject(b)) {
throw new Error('expected objects');
function areDataEqual(x, y, opts) {
if (opts.unboxPrimitives) {
x = unboxPrimitiveWrapper(x);
y = unboxPrimitiveWrapper(y);
}
if (a === b)
if (x === y)
return true;
// ensure immutability
if (isObjectLiteral(a)) {
a = { ...a };
}
if (isObjectLiteral(b)) {
b = { ...b };
}
switch (options?.compare(a, b)) {
case 'DEFAULT_COMPARISON':
case undefined:
break;
case 'EQUAL':
return true;
case 'NOT_EQUAL':
if (Array.isArray(x) && Array.isArray(y))
return areArraysEqual(x, y, opts);
if (isPlainObject(x) && isPlainObject(y))
return arePlainObjectsEqual(x, y, opts);
if (isPrimitive(x) && isPrimitive(y))
return Object.is(x, y);
const protoX = Object.getPrototypeOf(x);
const protoY = Object.getPrototypeOf(y);
if (!isPrimitiveWrapper(x) && ![Object.prototype, Array.prototype, null].includes(protoX) &&
!isPrimitiveWrapper(y) && ![Object.prototype, Array.prototype, null].includes(protoY)) {
if (protoX?.constructor !== protoY?.constructor)
return false;
return opts.areNonPlainObjectsEqual(x, y);
}
if (isObjectLiteral(a) !== isObjectLiteral(b))
return Object.is(x, y);
}
function arePlainObjectsEqual(a, b, options) {
if (!isPlainObject(a) || !isPlainObject(b))
throw new Error('expected plain objects');
if (a === b)
return true;
const res = options.comparePlainObjects?.(a, b);
if (res === ComparisonResult.Equal)
return true;
if (res === ComparisonResult.NotEqual)
return false;
if (isObjectInstance(a)) {
const str = a.toString();
return str !== '[object Object]' && str === b.toString();
}
if (Object.keys(a).length !== Object.keys(b).length)
const keysA = Object.keys(a);
if (keysA.length !== Object.keys(b).length)
return false;
for (let [key, value] of Object.entries(a)) {
if (!hasProperty(b, key))
for (const k of keysA) {
if (!Object.prototype.hasOwnProperty.call(b, k))
return false;
const b_ = b;
if (value === b_[key])
continue;
if (!value || !b_[key])
if (!areDataEqual(a[k], b[k], options))
return false;
if (typeof value !== typeof b_[key])
return false;
if (isArray(value) !== isArray(b_[key]))
return false;
if (isArray(value)) {
if (!areArraysEqual(value, b_[key], options))
return false;
continue;
}
if (isObject(value) !== isObject(b_[key]))
return false;
if (isObject(value)) {
if (!areObjectsEqual(value, b_[key], options))
return false;
continue;
}
return false;
}

@@ -150,49 +83,56 @@ return true;

function areArraysEqual(a, b, options) {
if (!isArray(a) || !isArray(b)) {
if (!Array.isArray(a) || !Array.isArray(b))
throw new Error('expected arrays');
}
if (a === b)
return true;
// ensure immutability
a = [...a];
b = [...b];
switch (options?.compare(a, b)) {
case 'DEFAULT_COMPARISON':
case undefined:
break;
case 'EQUAL':
return true;
case 'NOT_EQUAL':
return false;
}
if (a.length !== b.length)
return false;
for (let value of a) {
if (isArray(value)) {
const value_ = value;
const index = b.findIndex(e => isArray(e) && areArraysEqual(e, value_, options));
if (index === -1)
return false;
b.splice(index, 1);
continue;
if (a.length === 0)
return true;
// fast-path 1: already aligned
let allMatchByIndex = true;
for (let i = 0; i < a.length; ++i) {
if (!areDataEqual(a[i], b[i], options)) {
allMatchByIndex = false;
break;
}
if (isObject(value)) {
const value_ = value;
const index = b.findIndex(e => isObject(e) && areObjectsEqual(e, value_, options));
if (index === -1)
}
if (allMatchByIndex)
return true;
// fast-path 2: both all-primitive
let allPrimitives = true;
for (let i = 0; i < a.length; ++i) {
if (!isPrimitive(a[i]) || !isPrimitive(b[i])) {
allPrimitives = false;
break;
}
}
if (allPrimitives) {
const multiset = new Map();
for (const v of a)
multiset.set(v, (multiset.get(v) ?? 0) + 1);
for (const v of b) {
const n = multiset.get(v);
if (!n)
return false;
b.splice(index, 1);
continue;
n === 1 ? multiset.delete(v) : multiset.set(v, n - 1);
}
const index = b.findIndex(e => e === value);
if (index === -1)
return false;
b.splice(index, 1);
return true;
}
// fallback: generic O(n²) matcher
const matched = new Array(b.length).fill(false);
outer: for (const elemA of a) {
for (let i = 0; i < b.length; ++i) {
if (!matched[i] && areDataEqual(elemA, b[i], options)) {
matched[i] = true;
continue outer;
}
}
return false;
}
return true;
}
function hasProperty(o, prop) {
if (!isObject(o)) {
if (typeof o !== 'object' || o == null)
throw new Error('expected object');
}
return Object.prototype.hasOwnProperty.call(o, prop);

@@ -203,57 +143,45 @@ }

}
function filterProperties(o, arg) {
return isArray(arg)
? filterPropsByWhitelist(o, arg)
: filterPropsByFun(o, arg);
export function copyOwnStrings(src, filter) {
const kept = [];
for (const key of Object.keys(src)) {
const value = src[key];
if (filter(key, value))
kept.push([key, value]);
}
if (kept.length === Object.keys(src).length)
return src;
return Object.fromEntries(kept);
}
function filterPropsByWhitelist(o, props) {
return props.reduce((newObject, prop) => {
return (prop in o)
? { ...newObject, [prop]: o[prop] }
: newObject;
}, {});
function pickProperties(obj, arg) {
return Array.isArray(arg)
? copyOwnStrings(obj, k => arg.includes(k))
: copyOwnStrings(obj, arg);
}
function filterPropsByFun(o, fun) {
const filteredEntries = Object.entries(o).filter(([key, val]) => fun(key, val));
return Object.fromEntries(filteredEntries);
function omitProperties(obj, arg) {
return Array.isArray(arg)
? copyOwnStrings(obj, k => !arg.includes(k))
: copyOwnStrings(obj, (k, v) => !arg(k, v));
}
function rejectProperties(o, arg) {
return isArray(arg)
? rejectPropsByWhitelist(o, arg)
: rejectPropsByFun(o, arg);
function partitionProperties(obj, arg) {
const isWanted = Array.isArray(arg)
? (k) => arg.includes(k)
: (k, v) => arg(k, v);
const picked = {};
const omitted = {};
const missingKeys = [];
for (const k in obj)
if (Object.prototype.hasOwnProperty.call(obj, k)) {
const v = obj[k];
(isWanted(k, v) ? picked : omitted)[k] = v;
}
if (Array.isArray(arg)) {
for (const k of arg) {
if (!(k in picked))
missingKeys.push(k);
}
}
return { picked, omitted, missingKeys };
}
function rejectPropsByWhitelist(o, props) {
return Object.keys(o).reduce((newObject, prop) => {
return (props.includes(prop))
? newObject
: { ...newObject, [prop]: o[prop] };
}, {});
}
function rejectPropsByFun(o, fun) {
const filteredEntries = Object.entries(o).filter(([key, val]) => !fun(key, val));
return Object.fromEntries(filteredEntries);
}
function takeProperties(o, arg) {
return isArray(arg)
? takePropsByWhitelist(o, arg)
: takePropsByFun(o, arg);
}
function takePropsByWhitelist(o, props) {
const keys = Object.keys(o);
const undefined_ = differenceArraysOfPrimitives(props, keys)
.reduce((acc, key) => ({ ...acc, [key]: undefined }), {});
return keys.reduce(({ filtered, rejected, undefined }, prop) => {
return (props.includes(prop))
? { filtered: { ...filtered, [prop]: o[prop] }, rejected, undefined }
: { filtered, rejected: { ...rejected, [prop]: o[prop] }, undefined };
}, { filtered: {}, rejected: {}, undefined: undefined_ });
}
function takePropsByFun(o, fun) {
const filteredKeys = Object.entries(o)
.filter(([key, val]) => fun(key, val))
.map(([key, _]) => key);
return takePropsByWhitelist(o, filteredKeys);
}
function removeArrayElements(array, listOfValues) {
if (!isArray(array) || !isArray(listOfValues)) {
if (!Array.isArray(array) || !Array.isArray(listOfValues)) {
throw new Error('expected array');

@@ -266,9 +194,9 @@ }

}
function removeArrayElement(array, valueOrFun) {
if (!isArray(array)) {
function removeArrayElement(array, valueOrPredicate) {
if (!Array.isArray(array)) {
throw new Error('expected array');
}
return (typeof valueOrFun === 'function')
? removeArrayElementByFun(array, valueOrFun)
: removeArrayElementByValue(array, valueOrFun);
return (typeof valueOrPredicate === 'function')
? removeArrayElementByPredicate(array, valueOrPredicate)
: removeArrayElementByValue(array, valueOrPredicate);
}

@@ -281,17 +209,8 @@ function removeArrayElementByValue(array, value) {

}
function removeArrayElementByFun(array, fun) {
let indexToRemove = null;
for (let i = 0; i < array.length; ++i) {
if (fun(array[i])) {
indexToRemove = i;
break;
}
}
if (indexToRemove === null) {
return array;
}
return removeArrayElementByIndex(array, indexToRemove);
function removeArrayElementByPredicate(array, fun) {
const idx = array.findIndex(fun);
return idx === -1 ? array : [...array.slice(0, idx), ...array.slice(idx + 1)];
}
function removeArrayElementByIndex(array, index) {
if (!isArray(array)) {
if (!Array.isArray(array)) {
throw new Error('expected array');

@@ -304,4 +223,5 @@ }

}
function differenceArraysOfPrimitives(a1, a2) {
return a1.filter((e) => !a2.includes(e));
function differencePrimitives(a1, a2) {
const exclude = new Set(a2);
return a1.filter(v => !exclude.has(v));
}

@@ -319,142 +239,202 @@ // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/group

// }
function isObjectSubset(superObject, subObject) {
if (!isObject(superObject) || !isObject(subObject)) {
throw new Error('expected objects');
export function isDataSubset(sup, sub, opts) {
if (opts.unboxPrimitives) {
sup = unboxPrimitiveWrapper(sup);
sub = unboxPrimitiveWrapper(sub);
}
if (superObject === subObject)
if (sup === sub)
return true;
if (isObjectLiteral(superObject) !== isObjectLiteral(subObject))
return false;
if (isObjectInstance(superObject)) {
const str = superObject.toString();
return str !== '[object Object]' && str === subObject.toString();
if (Array.isArray(sup) && Array.isArray(sub))
return isArraySubset(sup, sub, opts);
if (isPlainObject(sup) && isPlainObject(sub))
return isPlainObjectSubset(sup, sub, opts);
if (isPrimitive(sup) && isPrimitive(sub))
return Object.is(sup, sub);
const protoSup = Object.getPrototypeOf(sup);
const protoSub = Object.getPrototypeOf(sub);
if (!isPrimitiveWrapper(sup) && ![Object.prototype, Array.prototype, null].includes(protoSup) &&
!isPrimitiveWrapper(sub) && ![Object.prototype, Array.prototype, null].includes(protoSub)) {
if (protoSup?.constructor !== protoSub?.constructor)
return false;
return opts.areNonPlainObjectsEqual(sup, sub);
}
if (Object.keys(superObject).length < Object.keys(subObject).length)
return Object.is(sup, sub);
}
function isPlainObjectSubset(sup, sub, opt) {
if (!isPlainObject(sup) || !isPlainObject(sub))
throw new Error('expected plain objects');
if (sup === sub)
return true;
const res = opt.comparePlainObjects?.(sup, sub);
if (res === ComparisonResult.Equal)
return true;
if (res === ComparisonResult.NotEqual)
return false;
return Object.keys(subObject).every(key => {
if (!hasProperty(superObject, key))
for (const [k, vSub] of Object.entries(sub)) {
if (!hasProperty(sup, k))
return false;
if (superObject[key] === subObject[key])
return true;
if (!superObject[key] || !subObject[key])
if (!isDataSubset(sup[k], vSub, opt))
return false;
if (typeof superObject[key] !== typeof subObject[key])
return false;
if (isObject(superObject[key]) !== isObject(subObject[key]))
return false;
if (isObject(superObject[key])) {
return isObjectSubset(superObject[key], subObject[key]);
}
if (isArray(superObject[key]) !== isArray(subObject[key]))
return false;
if (isArray(superObject[key])) {
return isArraySubset(superObject[key], subObject[key]);
}
return false;
});
}
return true;
}
function isArraySubset(superArray, subArray) {
if (!isArray(superArray) || !isArray(subArray)) {
function isArraySubset(supArr, subArr, opt) {
if (!Array.isArray(supArr) || !Array.isArray(subArr))
throw new Error('expected arrays');
}
if (superArray === subArray)
if (supArr === subArr)
return true;
if (superArray.length < subArray.length)
if (subArr.length === 0)
return true;
if (supArr.length < subArr.length)
return false;
superArray = [...superArray];
subArray = [...subArray];
for (let value of subArray) {
if (isArray(value)) {
const value_ = value;
const index = superArray.findIndex(e => isArray(e) && isArraySubset(e, value_));
if (index === -1)
return false;
superArray.splice(index, 1);
continue;
// fast-path 1: already aligned
let allMatchByIndex = true;
for (let i = 0; i < subArr.length; ++i) {
if (!isDataSubset(supArr[i], subArr[i], opt)) {
allMatchByIndex = false;
break;
}
if (isObject(value)) {
const value_ = value;
const index = superArray.findIndex(e => isObject(e) && isObjectSubset(e, value_));
if (index === -1)
}
if (allMatchByIndex)
return true;
// fast-path 2: both all-primitive
let primitivesOnly = true;
// check overlapping prefix
for (let i = 0; i < subArr.length && primitivesOnly; ++i) {
primitivesOnly = isPrimitive(subArr[i]) && isPrimitive(supArr[i]);
}
// check the tail of supArr only
for (let i = subArr.length; i < supArr.length && primitivesOnly; ++i) {
primitivesOnly = isPrimitive(supArr[i]);
}
if (primitivesOnly) {
const multiset = new Map();
for (const v of supArr)
multiset.set(v, (multiset.get(v) ?? 0) + 1);
for (const v of subArr) {
const n = multiset.get(v);
if (!n)
return false;
superArray.splice(index, 1);
continue;
n === 1 ? multiset.delete(v) : multiset.set(v, n - 1);
}
const index = superArray.findIndex(e => e === value);
if (index === -1)
return false;
superArray.splice(index, 1);
return true;
}
// fallback: generic O(n²) matcher
const matched = new Array(supArr.length).fill(false);
outer: for (const vSub of subArr) {
for (let i = 0; i < supArr.length; ++i) {
if (!matched[i] && isDataSubset(supArr[i], vSub, opt)) {
matched[i] = true;
continue outer;
}
}
return false;
}
return true;
}
function isPrimitive(value) {
return value !== Object(value);
function deepClonePlain(value) {
const seen = new WeakMap();
const walk = (node) => {
if (isPrimitive(node) || typeof node === "function")
return node;
if (seen.has(node))
return seen.get(node);
if (Array.isArray(node)) {
const copy = [];
seen.set(node, copy);
node.forEach((el, i) => (copy[i] = walk(el)));
return copy;
}
if (isPlainObject(node)) {
const copy = {};
seen.set(node, copy);
Object.keys(node).forEach((k) => {
copy[k] = walk(node[k]);
});
return copy;
}
return node;
};
return walk(value);
}
function cloneShape(value) {
if (isObjectLiteral(value)) {
return cloneShapeOfObjectLiteral(value);
function deepFreezePlain(root) {
if (!isPlainObject(root) && !Array.isArray(root)) {
throw new Error('expected plain object or array');
}
if (isArray(value)) {
return cloneShapeOfArray(value);
}
return value;
}
function cloneShapeOfObjectLiteral(o) {
return Object.fromEntries(Object.entries(o).map(([key, val]) => [key, cloneShape(val)]));
}
function cloneShapeOfArray(a) {
return a.map((e) => cloneShape(e));
}
function deepFreeze(o) {
if (!isObject(o) && !isArray(o)) {
throw new Error('expected object or array');
}
Object.keys(o).forEach((prop) => {
const o_ = o;
if ((!isObject(o_[prop]) || !isArray(o_[prop])) && !Object.isFrozen(o_[prop])) {
deepFreeze(o_[prop]);
const seen = new WeakSet();
const walk = (node) => {
if ((!isPlainObject(node) && !Array.isArray(node)) || seen.has(node))
return;
seen.add(node);
for (const key of Object.keys(node)) {
walk(node[key]);
}
});
return Object.freeze(o);
Object.freeze(node);
};
walk(root);
return root;
}
function sortProperties(o) {
return Object.fromEntries(Object.entries(o).sort(([k1], [k2]) => k1 < k2 ? -1 : 1));
function toSortedObject(o) {
const out = {};
for (const k of Object.keys(o).sort())
out[k] = o[k];
return out;
}
function range(options) {
const unknownOptions = rejectProperties(options, ['start', 'count', 'endInclusive', 'endExclusive']);
if (!isEmptyObjectLiteral(unknownOptions)) {
throw new Error(`unknown options: ${Object.keys(unknownOptions).join(', ')}`);
const unknown = omitProperties(options, [
'start',
'count',
'endInclusive',
'endExclusive',
]);
if (!isEmptyPlainObject(unknown)) {
throw new Error(`unknown option(s): ${Object.keys(unknown).join(', ')}`);
}
if (!options.endInclusive && !options.endExclusive && !options.count) {
throw new Error('expected either `endInclusive`, `endExclusive` or `count` to be specified');
const { start: rawStart, count, endInclusive, endExclusive } = options;
const start = rawStart ?? 0;
const hasCount = count !== undefined;
const hasEndInclusive = endInclusive !== undefined;
const hasEndExclusive = endExclusive !== undefined;
const provided = Number(hasCount) + Number(hasEndInclusive) + Number(hasEndExclusive);
if (provided === 0) {
throw new Error('Specify either `count`, `endInclusive`, or `endExclusive`.');
}
if (Number(!!options?.count) + Number(!!options?.endInclusive) + Number(!!options?.endExclusive) > 1) {
throw new Error('expected only one of the properties `endInclusive`, `endExclusive`, or `count` to be specified.');
if (provided > 1) {
throw new Error('Only one of `count`, `endInclusive`, or `endExclusive` may be supplied.');
}
const start = options.start ?? 0;
if (options.endInclusive && start > options.endInclusive) {
throw new Error('`endInclusive` should be greater or equal than `start`');
let len;
if (hasCount) {
if (count < 0)
throw new Error('`count` must be non-negative');
len = count;
}
if (options.endExclusive && start >= options.endExclusive) {
throw new Error('`endExclusive` should be greater than `start`');
else if (hasEndInclusive) {
if (endInclusive < start)
throw new Error('`endInclusive` must be ≥ `start`');
len = endInclusive - start + 1;
}
const count = options.count ?? ((options.endInclusive) ? options.endInclusive - start + 1 : options.endExclusive - start);
return [...Array(count).keys()].map(i => i + start);
else { // endExclusive
if (endExclusive <= start)
throw new Error('`endExclusive` must be > `start`');
len = endExclusive - start;
}
return Array.from({ length: len }, (_, i) => start + i);
}
function duplicate(value, count, transformFun = (v, _i) => v) {
function repeat(value, count, transformFun = (v, _i) => v) {
return [...Array(count).keys()].map(i => transformFun(value, i));
}
function unique(a, fun) {
if (!fun) {
return [...new Set(a)];
function unique(array, keyFn = (x => x)) {
if (array.length < 2)
return array;
const seen = new Set();
const result = [];
for (const item of array) {
const key = keyFn(item);
if (seen.has(key))
continue;
seen.add(key);
result.push(item);
}
const uniqueMap = new Map();
for (const item of a) {
const key = fun(item);
if (!uniqueMap.has(key)) {
uniqueMap.set(key, item);
}
}
return Array.from(uniqueMap.values());
return result.length === array.length ? array : result;
}
export { areArraysEqual, areObjectsEqual, areValuesEqual, cloneShape, deepFreeze, differenceArraysOfPrimitives, duplicate, filterProperties, hasProperty, hasProperties, isArray, isArrayOfObjects, isArrayOfObjectLiterals, isArrayOfPrimitives, isArrayOfType, isArraySubset, isArrayWhereEvery, isEmptyArray, isEmptyObjectLiteral, isNullOrUndefined, isObject, isObjectInstance, isObjectLiteral, isObjectLiteralWhereEvery, isObjectSubset, isPrimitive, range, rejectProperties, removeArrayElement, removeArrayElementByIndex, removeArrayElements, sortProperties, takeProperties, unique };
export { areArraysEqual, arePlainObjectsEqual, areDataEqual, deepClonePlain, deepFreezePlain, differencePrimitives, repeat, pickProperties, hasProperty, hasProperties, isArraySubset, isArrayWhereEvery, isEmptyArray, isEmptyPlainObject, isNullOrUndefined, isPlainObject, isPlainObjectWhereEvery, isPlainObjectSubset, isPrimitive, isPrimitiveWrapper, range, omitProperties, removeArrayElement, removeArrayElementByIndex, removeArrayElements, toSortedObject, unboxPrimitiveWrapper, partitionProperties, unique };
export {};
import { expect, test } from 'vitest';
import { areArraysEqual, areObjectsEqual, areValuesEqual, cloneShape, deepFreeze, differenceArraysOfPrimitives, duplicate, filterProperties, hasProperties, isArrayOfPrimitives, isArrayOfType, isArrayWhereEvery, isEmptyArray, isEmptyObjectLiteral, isObjectLiteral, isObjectLiteralWhereEvery, isPrimitive, range, rejectProperties, removeArrayElement, removeArrayElementByIndex, removeArrayElements, sortProperties, takeProperties, unique } from './index';
test('areValuesEqual', () => {
expect(areValuesEqual(null, null)).toBeTruthy();
expect(areValuesEqual(null, undefined)).toBeFalsy();
expect(areValuesEqual(undefined, undefined)).toBeTruthy();
expect(areValuesEqual(false, false)).toBeTruthy();
expect(areValuesEqual(1, 1)).toBeTruthy();
expect(areValuesEqual(1, '1')).toBeFalsy();
expect(areValuesEqual(new Date(), new Date())).toBeTruthy();
expect(areValuesEqual([{}], [{}])).toBeTruthy();
import { areArraysEqual, arePlainObjectsEqual, areDataEqual, deepClonePlain, deepFreezePlain, differencePrimitives, repeat, pickProperties, omitProperties, partitionProperties, hasProperties, isArrayWhereEvery, isEmptyArray, isEmptyPlainObject, isPlainObject, isPlainObjectWhereEvery, isPrimitive, isPrimitiveWrapper, unboxPrimitiveWrapper, range, removeArrayElement, removeArrayElementByIndex, removeArrayElements, toSortedObject, unique } from './index';
test('areDataEqual', () => {
const areNonPlainObjectsEqual = () => { throw new Error(); };
expect(areDataEqual(null, null, { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeTruthy();
expect(areDataEqual(null, undefined, { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeFalsy();
expect(areDataEqual(undefined, undefined, { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeTruthy();
expect(areDataEqual(false, false, { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeTruthy();
expect(areDataEqual(1, 1, { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeTruthy();
expect(areDataEqual(1, '1', { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeFalsy();
expect(areDataEqual([{}], [{}], { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeTruthy();
expect(areDataEqual(0, -0, { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeTruthy();
expect(areDataEqual([0], [-0], { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeTruthy();
expect(areDataEqual({ foo: 0 }, { foo: -0 }, { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeTruthy();
});
test('areObjectsEqual', () => {
expect(areObjectsEqual({ b: null, c: { d: 1, e: "world" }, a: "foo" }, { a: "foo", b: null, c: { e: "world", d: 1 } })).toBeTruthy();
expect(areObjectsEqual({ b: null, c: { d: [2, 5, 1, 0, { c: 3, d: 4 }], e: "world" }, a: "foo" }, { a: "foo", b: null, c: { e: "world", d: [{ d: 4, c: 3 }, 1, 0, 2, 5] } })).toBeTruthy();
test('areDataEqual containing object instances', () => {
const areNonPlainObjectsEqual = ((o1, o2) => {
if (o1 instanceof Date && o2 instanceof Date) {
return o1.getTime() === o2.getTime();
}
throw new Error();
});
expect(areDataEqual(new Date(), new Date(), { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeTruthy();
});
test('areObjectsEquivalent', () => {
const areNonPlainObjectsEqual = () => { throw new Error(); };
expect(arePlainObjectsEqual({ b: null, c: { d: 1, e: "world" }, a: "foo" }, { a: "foo", b: null, c: { e: "world", d: 1 } }, { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeTruthy();
expect(arePlainObjectsEqual({ b: null, c: { d: [2, 5, 1, 0, { c: 3, d: 4 }], e: "world" }, a: "foo" }, { a: "foo", b: null, c: { e: "world", d: [{ d: 4, c: 3 }, 1, 0, 2, 5] } }, { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeTruthy();
expect(arePlainObjectsEqual({ foo: 0 }, { foo: -0 }, { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeTruthy();
});
test('areArraysEqual', () => {
expect(areArraysEqual([2, 1, 1], [2, 1, 2])).toBeFalsy();
expect(areArraysEqual([{ b: null, c: { d: 1, e: "world" }, a: "foo" }, "foo"], ["foo", { a: "foo", b: null, c: { e: "world", d: 1 } }])).toBeTruthy();
expect(areArraysEqual([1, { b: null, c: { d: [2, 5, 1, 0, { c: 3, d: 4 }], e: "world" }, a: "foo" }], [{ a: "foo", b: null, c: { e: "world", d: [{ d: 4, c: 3 }, 1, 0, 2, 5] } }, 1])).toBeTruthy();
const areNonPlainObjectsEqual = () => { throw new Error(); };
expect(areArraysEqual([2, 1, 1], [2, 1, 2], { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeFalsy();
expect(areArraysEqual([{ b: null, c: { d: 1, e: "world" }, a: "foo" }, "foo"], ["foo", { a: "foo", b: null, c: { e: "world", d: 1 } }], { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeTruthy();
expect(areArraysEqual([1, { b: null, c: { d: [2, 5, 1, 0, { c: 3, d: 4 }], e: "world" }, a: "foo" }], [{ a: "foo", b: null, c: { e: "world", d: [{ d: 4, c: 3 }, 1, 0, 2, 5] } }, 1], { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeTruthy();
expect(areArraysEqual([0], [-0], { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeTruthy();
});
test('areArraysEqual containing object instances', () => {
const date1 = new Date('December 17, 1995 03:24:00');
const date2 = new Date('December 17, 1995 03:24:00');
const date3 = new Date('December 18, 1995 03:24:00');
expect(areObjectsEqual({ date: date1, dates: [date3, date2, date1] }, { date: date2, dates: [date1, date3, date2] })).toBeTruthy();
expect(areArraysEqual([1, 1, 2], [1, 1, 2])).toBeTruthy();
deepFreeze([1, { b: null, c: { d: [2, 5, 1, 0, { c: 3, d: 4 }], e: "world" }, a: "foo" }]);
const areNonPlainObjectsEqual = ((o1, o2) => {
if (o1 instanceof Date && o2 instanceof Date) {
return o1.getTime() === o2.getTime();
}
throw new Error();
});
expect(arePlainObjectsEqual({ date: date1, dates: [date3, date2, date1] }, { date: date2, dates: [date1, date3, date2] }, { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeTruthy();
expect(areArraysEqual([1, 1, 2], [1, 1, 2], { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true })).toBeTruthy();
deepFreezePlain([1, { b: null, c: { d: [2, 5, 1, 0, { c: 3, d: 4 }], e: "world" }, a: "foo" }]);
});

@@ -35,36 +59,36 @@ test('hasProperties', () => {

});
test('filterProperties using whitelist of props', () => {
expect(filterProperties({ foo: 1, bar: 2 }, ['foo'])).toEqual({ foo: 1 });
expect(filterProperties({ foo: 1, bar: 2 }, ['bar'])).toEqual({ bar: 2 });
expect(filterProperties({ foo: 1, bar: 2 }, ['bar', 'foo'])).toEqual({ foo: 1, bar: 2 });
expect(filterProperties({ foo: 1, bar: 2 }, ['bar', 'foo', 'baz'])).toEqual({ foo: 1, bar: 2 });
expect(filterProperties({ foo: 1, bar: 2 }, ['foo', 'foo'])).toEqual({ foo: 1 });
test('pickProperties using whitelist of props', () => {
expect(pickProperties({ foo: 1, bar: 2 }, ['foo'])).toEqual({ foo: 1 });
expect(pickProperties({ foo: 1, bar: 2 }, ['bar'])).toEqual({ bar: 2 });
expect(pickProperties({ foo: 1, bar: 2 }, ['bar', 'foo'])).toEqual({ foo: 1, bar: 2 });
expect(pickProperties({ foo: 1, bar: 2 }, ['bar', 'foo', 'baz'])).toEqual({ foo: 1, bar: 2 });
expect(pickProperties({ foo: 1, bar: 2 }, ['foo', 'foo'])).toEqual({ foo: 1 });
});
test('filterProperties using function', () => {
expect(filterProperties({ foo: 1, bar: 2 }, (_key, val) => val < 2)).toEqual({ foo: 1 });
expect(filterProperties({ foo: 3, bar: 2 }, (_key, val) => val < 2)).toEqual({});
test('pickProperties using function', () => {
expect(pickProperties({ foo: 1, bar: 2 }, (_key, val) => val < 2)).toEqual({ foo: 1 });
expect(pickProperties({ foo: 3, bar: 2 }, (_key, val) => val < 2)).toEqual({});
});
test('rejectProperties using whitelist of props', () => {
expect(rejectProperties({ foo: 1, bar: 2 }, ['foo'])).toEqual({ bar: 2 });
expect(rejectProperties({ foo: 1, bar: 2 }, ['bar'])).toEqual({ foo: 1 });
expect(rejectProperties({ foo: 1, bar: 2 }, ['bar', 'foo'])).toEqual({});
expect(rejectProperties({ foo: 1, bar: 2 }, ['bar', 'foo', 'baz'])).toEqual({});
expect(rejectProperties({ foo: 1, bar: 2 }, ['foo', 'foo'])).toEqual({ bar: 2 });
expect(rejectProperties({ foo: 1, bar: 2 }, ['baz'])).toEqual({ foo: 1, bar: 2 });
test('omitProperties using whitelist of props', () => {
expect(omitProperties({ foo: 1, bar: 2 }, ['foo'])).toEqual({ bar: 2 });
expect(omitProperties({ foo: 1, bar: 2 }, ['bar'])).toEqual({ foo: 1 });
expect(omitProperties({ foo: 1, bar: 2 }, ['bar', 'foo'])).toEqual({});
expect(omitProperties({ foo: 1, bar: 2 }, ['bar', 'foo', 'baz'])).toEqual({});
expect(omitProperties({ foo: 1, bar: 2 }, ['foo', 'foo'])).toEqual({ bar: 2 });
expect(omitProperties({ foo: 1, bar: 2 }, ['baz'])).toEqual({ foo: 1, bar: 2 });
});
test('rejectProperties using function', () => {
expect(rejectProperties({ foo: 1, bar: 2 }, (_key, val) => val < 2)).toEqual({ bar: 2 });
expect(rejectProperties({ foo: 3, bar: 2 }, (_key, val) => val < 2)).toEqual({ foo: 3, bar: 2 });
expect(rejectProperties({ foo: 3, bar: 2 }, (_key, val) => val > 1)).toEqual({});
test('omitProperties using function', () => {
expect(omitProperties({ foo: 1, bar: 2 }, (_key, val) => val < 2)).toEqual({ bar: 2 });
expect(omitProperties({ foo: 3, bar: 2 }, (_key, val) => val < 2)).toEqual({ foo: 3, bar: 2 });
expect(omitProperties({ foo: 3, bar: 2 }, (_key, val) => val > 1)).toEqual({});
});
test('takeProperties using whitelist of props', () => {
expect(takeProperties({ foo: 1, bar: 2 }, ['foo'])).toEqual({ filtered: { foo: 1 }, rejected: { bar: 2 }, undefined: {} });
expect(takeProperties({ foo: 1, bar: 2 }, ['bar'])).toEqual({ filtered: { bar: 2 }, rejected: { foo: 1 }, undefined: {} });
expect(takeProperties({ foo: 1, bar: 2 }, ['bar', 'foo'])).toEqual({ filtered: { foo: 1, bar: 2 }, rejected: {}, undefined: {} });
expect(takeProperties({ foo: 1, bar: 2 }, ['bar', 'foo', 'baz'])).toEqual({ filtered: { foo: 1, bar: 2 }, rejected: {}, undefined: { baz: undefined } });
expect(takeProperties({ foo: 1, bar: 2 }, ['baz'])).toEqual({ filtered: {}, rejected: { foo: 1, bar: 2 }, undefined: { baz: undefined } });
test('partitionProperties using whitelist of props', () => {
expect(partitionProperties({ foo: 1, bar: 2 }, ['foo'])).toEqual({ picked: { foo: 1 }, omitted: { bar: 2 }, missingKeys: [] });
expect(partitionProperties({ foo: 1, bar: 2 }, ['bar'])).toEqual({ picked: { bar: 2 }, omitted: { foo: 1 }, missingKeys: [] });
expect(partitionProperties({ foo: 1, bar: 2 }, ['bar', 'foo'])).toEqual({ picked: { foo: 1, bar: 2 }, omitted: {}, missingKeys: [] });
expect(partitionProperties({ foo: 1, bar: 2 }, ['bar', 'foo', 'baz'])).toEqual({ picked: { foo: 1, bar: 2 }, omitted: {}, missingKeys: ['baz'] });
expect(partitionProperties({ foo: 1, bar: 2 }, ['baz'])).toEqual({ picked: {}, omitted: { foo: 1, bar: 2 }, missingKeys: ['baz'] });
});
test('takeProperties using function', () => {
expect(takeProperties({ foo: 1, bar: 2 }, (_key, val) => val < 2)).toEqual({ filtered: { foo: 1 }, rejected: { bar: 2 }, undefined: {} });
expect(takeProperties({ foo: 3, bar: 2 }, (_key, val) => val < 2)).toEqual({ filtered: {}, rejected: { foo: 3, bar: 2 }, undefined: {} });
test('partitionProperties using function', () => {
expect(partitionProperties({ foo: 1, bar: 2 }, (_key, val) => val < 2)).toEqual({ picked: { foo: 1 }, omitted: { bar: 2 }, missingKeys: [] });
expect(partitionProperties({ foo: 3, bar: 2 }, (_key, val) => val < 2)).toEqual({ picked: {}, omitted: { foo: 3, bar: 2 }, missingKeys: [] });
});

@@ -88,3 +112,2 @@ test('isEmptyArray', () => {

expect(isPrimitive(new String('foo'))).toBeFalsy();
expect(isPrimitive(Symbol('foo'))).toBeTruthy();
expect(isPrimitive(false)).toBeTruthy();

@@ -95,38 +118,54 @@ expect(isPrimitive(new Boolean(false))).toBeFalsy();

});
test('isArrayOfPrimitives', () => {
expect(isArrayOfPrimitives([])).toBeFalsy();
expect(isArrayOfPrimitives([{}])).toBeFalsy();
expect(isArrayOfPrimitives([[]])).toBeFalsy();
expect(isArrayOfPrimitives([false])).toBeTruthy();
expect(isArrayOfPrimitives([false, 'foo', 1])).toBeTruthy();
expect(isArrayOfPrimitives([false, new String('foo'), 1])).toBeFalsy();
expect(isArrayOfPrimitives(1)).toBeFalsy();
test('isPrimitiveWrapper', () => {
expect(isPrimitiveWrapper('foo')).toBeFalsy();
expect(isPrimitiveWrapper(false)).toBeFalsy();
expect(isPrimitiveWrapper(5)).toBeFalsy();
expect(isPrimitiveWrapper(String('foo'))).toBeFalsy();
expect(isPrimitiveWrapper(Boolean(false))).toBeFalsy();
expect(isPrimitiveWrapper(Number(5))).toBeFalsy();
expect(isPrimitiveWrapper(new String('foo'))).toBeTruthy();
expect(isPrimitiveWrapper(new Boolean(false))).toBeTruthy();
expect(isPrimitiveWrapper(new Number(5))).toBeTruthy();
});
test('isArrayOfType', () => {
expect(isArrayOfType([], 'string')).toBeFalsy();
expect(isArrayOfType([{}], 'string')).toBeFalsy();
expect(isArrayOfType(['foo', 'bar'], 'string')).toBeTruthy();
expect(isArrayOfType(['foo', 'bar'], 'number')).toBeFalsy();
expect(isArrayOfType([1, 2], 'number')).toBeTruthy();
expect(isArrayOfType([1, 'bar'], 'number')).toBeFalsy();
expect(isArrayOfType(['foo', 1], 'string')).toBeFalsy();
test('unboxPrimitiveWrapper', () => {
expect(unboxPrimitiveWrapper([])).toEqual([]);
expect(unboxPrimitiveWrapper({})).toEqual({});
expect(unboxPrimitiveWrapper('foo')).toBe('foo');
expect(unboxPrimitiveWrapper(false)).toBe(false);
expect(unboxPrimitiveWrapper(5)).toBe(5);
expect(unboxPrimitiveWrapper(new String('foo'))).toBe('foo');
expect(unboxPrimitiveWrapper(new Boolean(false))).toBe(false);
expect(unboxPrimitiveWrapper(new Number(5))).toBe(5);
});
test('isArrayWhereEvery', () => {
expect(isArrayWhereEvery([[], []], isEmptyArray)).toBeTruthy();
expect(isArrayWhereEvery([], isEmptyArray)).toBeFalsy();
expect(isArrayWhereEvery([{ foo: 1 }, { bar: 2 }], isObjectLiteral)).toBeTruthy();
expect(isArrayWhereEvery([{ foo: 1 }, new Date()], isObjectLiteral)).toBeFalsy();
expect(isArrayWhereEvery([], isEmptyArray)).toBeTruthy();
expect(isArrayWhereEvery([{ foo: 1 }, { bar: 2 }], isPlainObject)).toBeTruthy();
expect(isArrayWhereEvery([{ foo: 1 }, new Date()], isPlainObject)).toBeFalsy();
});
test('isObjectLiteralWhereEvery', () => {
expect(isObjectLiteralWhereEvery([[], []], isEmptyArray)).toBeFalsy();
expect(isObjectLiteralWhereEvery({ foo: [], bar: [] }, isEmptyArray)).toBeTruthy();
expect(isObjectLiteralWhereEvery({}, isEmptyObjectLiteral)).toBeFalsy();
expect(isObjectLiteralWhereEvery({ foo: { a: 1 }, bar: { b: 2 } }, isObjectLiteral)).toBeTruthy();
expect(isPlainObjectWhereEvery([[], []], isEmptyArray)).toBeFalsy();
expect(isPlainObjectWhereEvery({ foo: [], bar: [] }, isEmptyArray)).toBeTruthy();
expect(isPlainObjectWhereEvery({}, isEmptyPlainObject)).toBeTruthy();
expect(isPlainObjectWhereEvery({ foo: { a: 1 }, bar: { b: 2 } }, isPlainObject)).toBeTruthy();
});
test('isEmptyObjectLiteral', () => {
expect(isEmptyObjectLiteral({})).toBeTruthy();
expect(isEmptyObjectLiteral([])).toBeFalsy();
expect(isEmptyObjectLiteral({ foo: 1 })).toBeFalsy();
expect(isEmptyObjectLiteral(new Date())).toBeFalsy();
test('isPlainObject', () => {
expect(isPlainObject([])).toBeFalsy();
expect(isPlainObject({})).toBeTruthy();
expect(isPlainObject(Object.create(null))).toBeTruthy();
expect(isPlainObject(1)).toBeFalsy();
expect(isPlainObject('foo')).toBeFalsy();
expect(isPlainObject(true)).toBeFalsy();
expect(isPlainObject(false)).toBeFalsy();
expect(isPlainObject(new Date())).toBeFalsy();
expect(isPlainObject(new Number(1))).toBeFalsy();
expect(isPlainObject(new String('foo'))).toBeFalsy();
expect(isPlainObject(new Boolean(false))).toBeFalsy();
});
test('isEmptyPlainObject', () => {
expect(isEmptyPlainObject({})).toBeTruthy();
expect(isEmptyPlainObject([])).toBeFalsy();
expect(isEmptyPlainObject({ foo: 1 })).toBeFalsy();
expect(isEmptyPlainObject(new Date())).toBeFalsy();
});
test('removeArrayElementByIndex', () => {

@@ -154,5 +193,5 @@ expect(removeArrayElementByIndex([1, 2, 3], 1)).toEqual([1, 3]);

});
test('sortProperties', () => {
expect(Object.keys(sortProperties({ b: 2, a: 1, c: 3 }))).not.toEqual(['b', 'a', 'c']);
expect(Object.keys(sortProperties({ b: 2, a: 1, c: 3 }))).toEqual(['a', 'b', 'c']);
test('toSortedObject', () => {
expect(Object.keys(toSortedObject({ b: 2, a: 1, c: 3 }))).not.toEqual(['b', 'a', 'c']);
expect(Object.keys(toSortedObject({ b: 2, a: 1, c: 3 }))).toEqual(['a', 'b', 'c']);
});

@@ -168,13 +207,13 @@ test('range', () => {

});
test('duplicate', () => {
expect(duplicate(2, 3)).toEqual([2, 2, 2]);
expect(duplicate(['foo', 0], 3)).toEqual([['foo', 0], ['foo', 0], ['foo', 0]]);
expect(duplicate({ num: 1 }, 2, (value, i) => ({ ...value, id: i + 1 }))).toEqual([{ num: 1, id: 1 }, { num: 1, id: 2 }]);
test('repeat', () => {
expect(repeat(2, 3)).toEqual([2, 2, 2]);
expect(repeat(['foo', 0], 3)).toEqual([['foo', 0], ['foo', 0], ['foo', 0]]);
expect(repeat({ num: 1 }, 2, (value, i) => ({ ...value, id: i + 1 }))).toEqual([{ num: 1, id: 1 }, { num: 1, id: 2 }]);
});
test('differenceArraysOfPrimitives', () => {
expect(differenceArraysOfPrimitives([2], [2])).toEqual([]);
expect(differenceArraysOfPrimitives([2], [3])).toEqual([2]);
expect(differenceArraysOfPrimitives([1, 2, 3, 9], [1, 3, 4])).toEqual([2, 9]);
expect(differenceArraysOfPrimitives(['foo'], ['bar', 'foo'])).toEqual([]);
expect(differenceArraysOfPrimitives(['bar', 'foo'], ['foo'])).toEqual(['bar']);
test('differencePrimitives', () => {
expect(differencePrimitives([2], [2])).toEqual([]);
expect(differencePrimitives([2], [3])).toEqual([2]);
expect(differencePrimitives([1, 2, 3, 9], [1, 3, 4])).toEqual([2, 9]);
expect(differencePrimitives(['foo'], ['bar', 'foo'])).toEqual([]);
expect(differencePrimitives(['bar', 'foo'], ['foo'])).toEqual(['bar']);
});

@@ -186,7 +225,7 @@ test('unique', () => {

});
test('cloneShape', () => {
expect(cloneShape(null)).toEqual(null);
expect(cloneShape('foo')).toEqual('foo');
test('deepClonePlain', () => {
expect(deepClonePlain(null)).toEqual(null);
expect(deepClonePlain('foo')).toEqual('foo');
const o = [1, { b: null, c: { d: [2, 5, 1, 0, { c: 3, d: 4 }], e: "world" }, a: "foo" }];
const clonedO = cloneShape(o);
const clonedO = deepClonePlain(o);
expect(o[1].b).toBe(null);

@@ -193,0 +232,0 @@ expect(clonedO[1].b).toBe(null);

@@ -178,3 +178,3 @@ Apache License

Copyright 2021 Mathieu Decaffmeyer
Copyright 2025 Mathieu Decaffmeyer

@@ -181,0 +181,0 @@ Licensed under the Apache License, Version 2.0 (the "License");

{
"name": "object-array-utils",
"version": "4.0.0",
"version": "5.0.0",
"description": "Utilities for working with arrays and objects",
"funding": "https://github.com/mathieuprog/object-array-utils?sponsor=1",
"source": "src/index.ts",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"type": "module",
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
}
},
"types": "./dist/index.d.ts",
"files": [

@@ -14,2 +18,3 @@ "dist"

"scripts": {
"build": "tsc -p tsconfig.json",
"test": "vitest"

@@ -20,7 +25,6 @@ },

"devDependencies": {
"@tsconfig/node18": "^18.2.2",
"rollup": "^3.29.3",
"typescript": "^5.2.2",
"vite": "^4.4.9",
"vitest": "^0.34.5"
"@tsconfig/node22": "^22.0.2",
"typescript": "^5.8.3",
"vite": "^6.3.5",
"vitest": "^3.2.4"
},

@@ -27,0 +31,0 @@ "repository": {

+63
-82

@@ -6,26 +6,14 @@ # `object-array-utils`

```javascript
import { isObjectLiteral } from 'object-array-utils';
import { isPlainObject } from 'object-array-utils';
isObjectLiteral({ prop: 1 }) // true
isObjectLiteral(new Date()) // false
isObjectLiteral([1]) // false
isPlainObject({ prop: 1 }) // true
isPlainObject(new Date()) // false
isPlainObject([1]) // false
import { isEmptyObjectLiteral } from 'object-array-utils';
import { isEmptyPlainObject } from 'object-array-utils';
isEmptyObjectLiteral({}) // true
isEmptyObjectLiteral(new Date()) // false
isEmptyObjectLiteral([]) // false
isEmptyPlainObject({}) // true
isEmptyPlainObject(new Date()) // false
isEmptyPlainObject([]) // false
import { isObjectInstance } from 'object-array-utils';
isObjectInstance({ prop: 1 }) // false
isObjectInstance(new Date()) // true
isObjectInstance([1]) // false
import { isObject } from 'object-array-utils';
isObject({ prop: 1 }) // true
isObject(new Date()) // true
isObject([1]) // false
import { isArray } from 'object-array-utils';

@@ -39,15 +27,2 @@

import { isArrayOfObjects } from 'object-array-utils';
isArrayOfObjects([{ prop: 1 }, new Date()]) // true
isArrayOfObjects([1]) // false
isArrayOfObjects([]) // false
import { isArrayOfObjectLiterals } from 'object-array-utils';
isArrayOfObjectLiterals([{ prop: 1 }, { prop: 2 }]) // true
isArrayOfObjectLiterals([{ prop: 1 }, new Date()]) // false
isArrayOfObjectLiterals([1]) // false
isArrayOfObjectLiterals([]) // false
import { isNullOrUndefined } from 'object-array-utils';

@@ -66,20 +41,20 @@

import { filterProperties } from 'object-array-utils';
import { pickProperties } from 'object-array-utils';
filterProperties({ prop1: 1, prop2: 2 }, ['prop1', 'prop3']) // { prop1: 1 }
filterProperties<number>({ prop1: 1, prop2: 2 }, (_key, val) => val < 2) // { prop1: 1 }
pickProperties({ prop1: 1, prop2: 2 }, ['prop1', 'prop3']) // { prop1: 1 }
pickProperties<number>({ prop1: 1, prop2: 2 }, (_key, val) => val < 2) // { prop1: 1 }
import { rejectProperties } from 'object-array-utils';
import { omitProperties } from 'object-array-utils';
rejectProperties({ prop1: 1, prop2: 2 }, ['prop1', 'prop3']) // { prop2: 2 }
rejectProperties<number>({ prop1: 1, prop2: 2 }, (_key, val) => val < 2) // { prop2: 2 }
omitProperties({ prop1: 1, prop2: 2 }, ['prop1', 'prop3']) // { prop2: 2 }
omitProperties<number>({ prop1: 1, prop2: 2 }, (_key, val) => val < 2) // { prop2: 2 }
import { takeProperties } from 'object-array-utils';
import { partitionProperties } from 'object-array-utils';
takeProperties({ prop1: 1, prop2: 2 }, ['prop1', 'prop3']) // { filtered: { prop1: 1 }, rejected: { prop2: 2 } }
takeProperties<number>({ prop1: 1, prop2: 2 }, (_key, val) => val < 2) // { filtered: { prop1: 1 }, rejected: { prop2: 2 } }
partitionProperties({ prop1: 1, prop2: 2 }, ['prop1', 'prop3']) // { picked: { prop1: 1 }, omitted: { prop2: 2 }, missingKeys: ['prop3'] }
partitionProperties<number>({ prop1: 1, prop2: 2 }, (_key, val) => val < 2) // { picked: { prop1: 1 }, omitted: { prop2: 2 }, missingKeys: [] }
import { sortProperties } from 'object-array-utils';
import { toSortedObject } from 'object-array-utils';
sortProperties({ prop2: 2, prop1: 1 }) // { prop1: 1, prop2: 2 }
toSortedObject({ prop2: 2, prop1: 1 }) // { prop1: 1, prop2: 2 }

@@ -100,7 +75,7 @@ import { removeArrayElement } from 'object-array-utils';

import { isObjectSubset } from 'object-array-utils';
import { isPlainObjectSubset } from 'object-array-utils';
isObjectSubset({ prop1: 1, prop2: 2 }, { prop1: 1 }) // true
isObjectSubset({ prop1: { foo: 1, bar: 2 } }, prop2: 2 }, { prop1: { bar: 2 } }) // true
isObjectSubset({ prop1: [1, 2], prop2: 2 }, { prop1: [2] }) // true
isPlainObjectSubset({ prop1: 1, prop2: 2 }, { prop1: 1 }) // true
isPlainObjectSubset({ prop1: { foo: 1, bar: 2 } }, prop2: 2 }, { prop1: { bar: 2 } }) // true
isPlainObjectSubset({ prop1: [1, 2], prop2: 2 }, { prop1: [2] }) // true

@@ -112,21 +87,28 @@ import { isArraySubset } from 'object-array-utils';

import { areObjectsEqual } from 'object-array-utils';
import { arePlainObjectsEqual, type AreNonPlainObjectsEqual } from 'object-array-utils';
areObjectsEqual({ prop1: 1, prop2: 2 }, { prop2: 2, prop1: 1 }) // true
const areNonPlainObjectsEqual: AreNonPlainObjectsEqual = ((o1, o2) => {
if (o1 instanceof Date && o2 instanceof Date) return o1.getTime() === o2.getTime();
throw new Error();
});
const opts = { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true };
arePlainObjectsEqual({ prop1: 1, prop2: 2 }, { prop2: 2, prop1: 1 }, opts) // true
import { areArraysEqual } from 'object-array-utils';
import { areArraysEqual, type AreNonPlainObjectsEqual } from 'object-array-utils';
areArraysEqual([1, { prop1: 1, prop2: 2 }], [{ prop2: 2, prop1: 1 }, 1]) // true
const opts = { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true };
areArraysEqual([1, { prop1: 1, prop2: 2 }], [{ prop2: 2, prop1: 1 }, 1], opts) // true
import { areValuesEqual } from 'object-array-utils';
import { areDataEqual } from 'object-array-utils';
areValuesEqual(new Date(), new Date()) // true
const opts = { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true };
areDataEqual(new Date(), new Date(), opts) // true
import { cloneShape } from 'object-array-utils';
import { deepClonePlain } from 'object-array-utils';
cloneShape({ foo: [{ bar: 1 }] })
deepClonePlain({ foo: [{ bar: 1 }] })
import { deepFreeze } from 'object-array-utils';
import { deepFreezePlain } from 'object-array-utils';
deepFreeze({ foo: 1 })
deepFreezePlain({ foo: 1 })

@@ -147,35 +129,33 @@ import { isPrimitive } from 'object-array-utils';

import { isArrayOfPrimitives } from 'object-array-utils';
import { isPrimitiveWrapper } from 'object-array-utils';
isArrayOfPrimitives([1, 'foo']) // true
isArrayOfPrimitives([new Number(1), 'foo']) // false
isArrayOfPrimitives([]) // false
isPrimitiveWrapper(new Number(5)) // true
isPrimitiveWrapper(Number(5)) // false
isPrimitiveWrapper(5) // false
import { isArrayOfType } from 'object-array-utils';
import { unboxPrimitiveWrapper } from 'object-array-utils';
isArrayOfType(['foo', 'bar'], 'string') // true
isArrayOfType(['foo', 1], 'string') // false
isArrayOfType([1, 2], 'number') // true
isArrayOfType([], 'string') // false
unboxPrimitiveWrapper(new Number(5)) // 5
unboxPrimitiveWrapper(5) // 5
import { isArrayWhereEvery, isObjectLiteral } from 'object-array-utils';
import { isArrayWhereEvery, isPlainObject } from 'object-array-utils';
isArrayWhereEvery([{ foo: 1 }, { bar: 2 }], isObjectLiteral) // true
isArrayWhereEvery([{ foo: 1 }, new Date()], isObjectLiteral) // false
isArrayWhereEvery([], isObjectLiteral) // false
isArrayWhereEvery([{ foo: 1 }, { bar: 2 }], isPlainObject) // true
isArrayWhereEvery([{ foo: 1 }, new Date()], isPlainObject) // false
isArrayWhereEvery([], isPlainObject) // false
import { isObjectLiteralWhereEvery, isArray } from 'object-array-utils';
import { isPlainObjectWhereEvery, isArray } from 'object-array-utils';
isObjectLiteralWhereEvery({ foo: [1], bar: [2, 3] }, isArray) // true
isObjectLiteralWhereEvery({}, isArray) // false
isPlainObjectWhereEvery({ foo: [1], bar: [2, 3] }, isArray) // true
isPlainObjectWhereEvery({}, isArray) // false
import { differenceArraysOfPrimitives } from 'object-array-utils';
import { differencePrimitives } from 'object-array-utils';
differenceArraysOfPrimitives([1, 2, 3, 9], [1, 3, 4]) // [2, 9]
differencePrimitives([1, 2, 3, 9], [1, 3, 4]) // [2, 9]
import { duplicate } from 'object-array-utils';
import { repeat } from 'object-array-utils';
duplicate(1, 3) // [1, 1, 1]
duplicate(1, 3, (value, i) => value + 1) // [1, 2, 3]
duplicate({ name: 'John' }, 2, (v, i) => ({ id: i + 1, ...v })) // [{ id: 1, name: 'John' }, { id: 2, name: 'John' }]
repeat(1, 3) // [1, 1, 1]
repeat(1, 3, (value, i) => value + 1) // [1, 2, 3]
repeat({ name: 'John' }, 2, (v, i) => ({ id: i + 1, ...v })) // [{ id: 1, name: 'John' }, { id: 2, name: 'John' }]

@@ -206,4 +186,5 @@ import { range } from 'object-array-utils';

```javascript
isArraySubset([{ foo: 1 }, { bar: 2 }], [{}, { bar: 2 }]) // true
isArraySubset([{ foo: 1 }, { bar: 2 }], [{}, { foo: 1 }]) // false
const opts = { areNonPlainObjectsEqual, unboxPrimitives: true, unorderedArrays: true };
isArraySubset([{ foo: 1 }, { bar: 2 }], [{}, { bar: 2 }], opts) // true
isArraySubset([{ foo: 1 }, { bar: 2 }], [{}, { foo: 1 }], opts) // false
```

@@ -210,0 +191,0 @@