@js-utility/object
Version:
Comprehensive utility library for advanced object manipulation in JavaScript: deep get/set, clone, merge, flatten, and more. Ideal for Node.js and browser projects as a lightweight lodash alternative.
369 lines (357 loc) • 14.6 kB
text/typescript
declare const cloneDeep: <T>(obj: T) => T;
/**
* Check if an object has a specific property.
* @param obj The object to check.
* @param key The property to check for.
* @returns True if the property exists, false otherwise.
*/
declare const hasProperty: (obj: object, key: string | number) => boolean;
/**
* Converts an array of dot-separated strings into a nested JSON object with the specified value.
*
* @param {string[]} arr - An array of strings where each string represents a path in dot notation.
* @param {any} [value=1] - The value to assign to the deepest key in the nested structure.
* @returns {object} - A nested JSON object based on the provided array of strings.
*
* @example
* const input = ['a.b.c', 'a.b.d', 'e'];
* const result = toNestedJson(input);
* // Output: { a: { b: { c: 1, d: 1 } }, e: 1 }
*/
declare const toNestedJson: (arr: string[], value?: any) => any;
/**
* Converts a nested JSON object into an array of dot-separated strings.
*
* @param {object} obj - The nested JSON object to convert.
* @param {string} [prefix=''] - The prefix for the current level of keys (used for recursion).
* @returns {string[]} - An array of strings where each string represents a path in dot notation.
*
* @example
* const input = { a: { b: { c: 1, d: 1 } }, e: 1 };
* const result = fromNestedJson(input);
* // Output: ['a.b.c', 'a.b.d', 'e']
*/
declare const fromNestedJson: (obj: any, prefix?: string) => string[];
/**
* Removes duplicate values from an array.
* @param arr The array to process.
* @returns A new array with duplicates removed.
*/
declare const removeDuplicates: (arr: any[]) => any[];
/**
* Removes duplicate values from an array.
* @param arr The array to process.
* @returns A new array with duplicates removed.
*/
declare const union: (arr: any[]) => any[];
/**
* Deeply compares two arrays for equality.
* @param arr1 The first array.
* @param arr2 The second array.
* @returns True if both arrays are deeply equal, false otherwise.
*/
declare const arrayEquals: (arr1: any[], arr2: any[]) => boolean;
/**
* Removes duplicate values from an array.
* @param arr The array to process.
* @returns A new array with duplicates removed.
*/
declare const intersect: (arr1: any[], arr2: any[]) => any[];
/**
* Sorts an array of objects based on multiple sorting criteria,
* with optional prefix-based prioritization for string fields.
*
* @param data - The array of objects to be sorted.
* @param sort_by - An array of sort conditions, each containing:
* - `key`: The field (can be a nested path) to sort by.
* - `order`: `1` for ascending or `-1` for descending order.
* - `priority_prefix` (optional): A string prefix that, if present,
* gives higher priority to values starting with this prefix.
*
* @returns The sorted array of objects.
*
* @example
* ```ts
* const data = [
* { name: 'apple', rank: 2 },
* { name: 'banana', rank: 1 },
* { name: 'apricot', rank: 1 },
* ];
*
* const sorted = sort(data, [
* { key: 'name', order: 1, priority_prefix: 'ap' },
* { key: 'rank', order: -1 }
* ]);
*
* // Result:
* // [
* // { name: 'apricot', rank: 1 },
* // { name: 'apple', rank: 2 },
* // { name: 'banana', rank: 1 }
* // ]
* ```
*/
declare const sort: (data: any[], sort_by: {
key: string;
order: 1 | -1;
priority_prefix?: string;
}[]) => any[];
/**
* Groups an array of objects by a specified key.
*
* This function takes an array of items and groups them into an object based on the value of a specified key.
* The key can be a deep path (e.g., "user.id"), and values are converted to strings for grouping.
*
* @template T - The type of the elements in the input array.
* @param {T[]} arr - The array of items to group.
* @param {string} key - The key (can be a deep path) to group by.
* @returns {Record<string, T[]>} An object where each key is a group identifier, and the value is an array of items in that group.
*
* @example
* ```ts
* const users = [
* { id: 1, info: { role: 'admin' } },
* { id: 2, info: { role: 'user' } },
* { id: 3, info: { role: 'admin' } }
* ];
*
* const grouped = groupBy(users, 'info.role');
* // Result:
* // {
* // admin: [{...}, {...}],
* // user: [{...}]
* // }
* ```
*/
declare function groupBy<T>(arr: T[], key: string): Record<string, T[]>;
/**
* Compares two values deeply to determine if they are equal.
*
* This function performs a deep equality check between two values. It handles
* primitive types, objects, and arrays. If the values are objects or arrays,
* it recursively compares their properties or elements.
*
* @param value1 - The first value to compare.
* @param value2 - The second value to compare.
* @returns `true` if the two values are deeply equal, otherwise `false`.
*
* @example
* ```typescript
* deepEqual(1, 1); // true
* deepEqual({ a: 1 }, { a: 1 }); // true
* deepEqual([1, 2], [1, 2]); // true
* deepEqual({ a: 1 }, { b: 1 }); // false
* deepEqual(null, null); // true
* deepEqual(null, {}); // false
* ```
*/
declare function deepEqual(a: any, b: any): boolean;
type Path = string | Array<string | number>;
type DataObject$1 = Record<string, any> | null | undefined;
interface DeepExtractOptions {
/**
* Whether to resolve references like "ID:2" or ["ID:3"] from the root.
* Default: true
*/
resolveRefs?: boolean;
/**
* The maximum number of times the same reference can be visited during the traversal.
* Default: 5 (to prevent infinite loops or excessive resolution in case of deep cycles).
*/
maxRefVisits?: number;
/**
* Default value to return if the path is not found or the root is null/undefined.
*/
default?: any;
}
/**
* Extracts a deeply nested value from an object using a dot/bracket path.
*
* Supports:
* - Arrays at any level
* - Wildcards (*) for collecting from all array elements
* - Optional reference resolution (string/array pointing to root-level keys)
* - Maximum number of reference visits before aborting further resolution (to avoid infinite loops)
*
* @param root The root object (used for value and reference resolution)
* @param path The path to extract (e.g. "items[0].ref.name", "items[*].prop")
* @param options Optional settings (e.g. resolveRefs: false to disable ref following, maxRefVisits: 3)
* @returns The extracted value (array, value, or undefined)
*/
declare function deepExtract(root: DataObject$1, path: Path, options?: DeepExtractOptions): any | undefined;
declare const getDeep: typeof deepExtract;
/**
* Creates a deep copy of the given object and removes properties or elements
* specified by the provided paths. The original object remains unmodified.
*
* @param obj - The source object from which properties or elements will be omitted.
* @param paths - An array of string paths specifying the properties or elements to omit.
* Each path is a dot-separated string representing the property hierarchy.
* For example, "a.b.c" targets the `c` property of the `b` object within `a`.
*
* @returns A new object with the specified properties or elements removed.
*
* @example
* ```typescript
* const obj = { a: { b: { c: 1, d: 2 } }, e: 3 };
* const result = omit(obj, ["a.b.c", "e"]);
* console.log(result); // Output: { a: { b: { d: 2 } } }
* ```
*/
declare function deepOmit(obj: any, paths: string[]): any;
/**
* Recursively picks specific properties from an object or array based on the provided paths.
*
* @param obj - The source object or array from which properties will be picked.
* @param paths - An array of string paths specifying the properties to pick.
* Paths can include nested keys separated by dots (e.g., "a.b.c")
* and wildcard '*' to match all elements in an array.
*
* @returns A new object or array containing only the picked properties,
* preserving the structure of the original object or array.
*
* @example
* const obj = { a: { b: { c: 1, d: 2 } }, e: [ { f: 3 }, { f: 4 } ] };
* const paths = ["a.b.c", "e.*.f"];
* const result = pickDeep(obj, paths);
* // result: { a: { b: { c: 1 } }, e: [ { f: 3 }, { f: 4 } ] }
*/
declare function pickDeep(obj: any, paths: string[]): any;
type DataObject = Record<string, any> | null | undefined;
interface DeepAssignOptions {
/**
* Whether to resolve references like "ID:2" or ["ID:3"] from the root.
* Default: true
*/
resolveRefs?: boolean;
/**
* The maximum number of times the same reference can be visited during the traversal.
* Default: 5 (to prevent infinite loops or excessive resolution in case of deep cycles).
*/
maxRefVisits?: number;
/**
* It forcefully sets the value even if the path already exists or type mismatch.
*/
set_forcefully?: boolean;
}
/**
* Recursively assigns a value to a deeply nested property within an object, creating intermediate
* objects or arrays as needed. Supports resolving references and handling wildcard paths.
*
* @param root - The root object where the value will be assigned. If `null` or `undefined`, the function exits early.
* @param path - The path to the property where the value should be assigned. Can include wildcard (`*`) for arrays.
* @param value - The value to assign to the specified path.
* @param options - Optional configuration for the assignment process.
*
* @param options.resolveRefs - Whether to resolve references (e.g., "ID:2") from the root object. Default is `true`.
* @param options.maxRefVisits - The maximum number of times the same reference can be visited during traversal.
* Default is `5` to prevent infinite loops or excessive resolution.
* @param options.set_forcefully - If `true`, forcefully sets the value even if the path already exists or there is a type mismatch.
* Default is `false`.
*
* @remarks
* - If the path includes a wildcard (`*`), the function will iterate over arrays at that level and apply the value to each element.
* - If `resolveRefs` is enabled, the function will attempt to resolve string references within the object.
* - The function ensures intermediate objects or arrays are created as needed to complete the assignment.
*
* @example
* ```typescript
* const obj = { a: { b: { c: 1 } } };
* deepAssign(obj, 'a.b.c', 42);
* console.log(obj); // { a: { b: { c: 42 } } }
*
* const arr = { items: [{ id: 1 }, { id: 2 }] };
* deepAssign(arr, 'items.*.id', 99);
* console.log(arr); // { items: [{ id: 99 }, { id: 99 }] }
* ```
*/
declare function deepAssign(root: DataObject, path: Path, value: any, options?: DeepAssignOptions): void;
declare const setDeep: typeof deepAssign;
/**
* Computes the difference between two objects or arrays.
*
* - If either `obj1` or `obj2` is `null` or `undefined`, returns `obj1`.
* - If both are arrays, returns an array of items from `obj1` that are not deeply equal to any item in `obj2`.
* - If both are objects, returns a new object containing keys from `obj1` whose values are not deeply equal to the corresponding values in `obj2`.
* - For primitive values, returns `obj1`.
*
* @param obj1 - The first object or array to compare.
* @param obj2 - The second object or array to compare against.
* @returns The difference between `obj1` and `obj2`, preserving the structure of `obj1`.
*/
declare const difference: (obj1: any, obj2: any) => any;
/**
* Determines whether a given value is not null, undefined, or an empty/invalid representation
* for its type (e.g., empty string, NaN, invalid date, empty array, empty object, etc.).
*
* @param value - The value to be checked.
* @returns `true` if the value is not null, undefined, or an empty/invalid representation; otherwise, `false`.
*
* @remarks
* - For primitive wrappers like `new Number()`, `new String()`, or `new Boolean()`, the function unwraps the value.
* - Strings are considered valid if they are non-empty after trimming whitespace.
* - Numbers are considered valid if they are not `NaN`.
* - Dates are considered valid if they represent a valid date.
* - Arrays, Maps, and Sets are considered valid if they are not empty.
* - Objects are considered valid if they have at least one enumerable property.
* - Booleans are always considered valid since they cannot be null or undefined.
*
* @example
* ```typescript
* isNotNull("Hello"); // true
* isNotNull(""); // false
* isNotNull(42); // true
* isNotNull(NaN); // false
* isNotNull(null); // false
* isNotNull(undefined); // false
* isNotNull([]); // false
* isNotNull([1, 2, 3]); // true
* isNotNull({}); // false
* isNotNull({ key: "value" }); // true
* isNotNull(new Date()); // true
* isNotNull(new Date("invalid date")); // false
* ```
*/
declare function isNotNull(value: any): boolean;
/**
* Determines whether a given value is null or undefined.
*
* @param value - The value to be checked.
* @returns `true` if the value is null or undefined; otherwise, `false`.
*
* @example
* ```typescript
* isNull(null); // true
* isNull(undefined); // true
* isNull(0); // false
* isNull(""); // false
* ```
*/
declare function isNull(value: any): boolean;
/**
* Attempt to parse a string into its original value.
* Falls back to the original string if parsing fails.
* @param str The string to parse.
* @param default_val The default value to return on failure.
* @returns The parsed value or default.
*/
declare const jsonify: (str: any, default_val?: any) => any;
/**
* Merges multiple source objects into a target object recursively, performing a deep merge.
* If a property in both the target and source objects is an object, the function merges them recursively.
* Otherwise, the source property overwrites the target property.
*
* @param target - The target object to which properties will be merged.
* @param sources - One or more source objects whose properties will be merged into the target.
* @returns The merged target object.
*
* @example
* ```typescript
* const target = { a: 1, b: { c: 2 } };
* const source = { b: { d: 3 }, e: 4 };
* const result = mergeObjs(target, source);
* // result: { a: 1, b: { c: 2, d: 3 }, e: 4 }
* ```
*/
declare const mergeObjs: (target: any, ...sources: any[]) => any;
export { arrayEquals, cloneDeep, deepAssign, deepEqual, deepExtract, deepOmit, difference, fromNestedJson, getDeep, groupBy, hasProperty, intersect, isNotNull, isNull, jsonify, mergeObjs, pickDeep, removeDuplicates, setDeep, sort, toNestedJson, union };