UNPKG

@casoon/dragonfly

Version:

Modular, lightweight CSS framework and design system for modern web projects. Optimized for Astro JS, LightningCSS and Container Queries with @layer-based architecture and comprehensive accessibility.

154 lines (141 loc) 3.78 kB
/** * Object Helper Functions * * Utilities for working with objects, checking emptiness, and manipulation. */ /** * Check if object is empty * * Works better than Object.keys(obj).length === 0 in edge cases. * Properly handles null, undefined, and non-objects. * * @param {*} obj - The object to check * @returns {boolean} True if object is empty * * @example * if (isEmpty(formErrors)) submitForm(); * * @example * isEmpty({}) // true * isEmpty({ name: 'John' }) // false * isEmpty(null) // false * isEmpty([]) // false (arrays are not plain objects) */ export function isEmpty(obj) { return ( obj && typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0 && obj.constructor === Object ); } /** * Check if value is a plain object * * @param {*} obj - Value to check * @returns {boolean} True if plain object * * @example * isPlainObject({}) // true * isPlainObject([]) // false * isPlainObject(new Date()) // false */ export function isPlainObject(obj) { return obj !== null && typeof obj === 'object' && obj.constructor === Object; } /** * Deep merge objects * * Recursively merges objects, with later objects taking precedence. * * @param {...Object} objects - Objects to merge * @returns {Object} Merged object * * @example * const defaults = { theme: 'light', size: 'medium' }; * const userPrefs = { theme: 'dark' }; * const config = deepMerge(defaults, userPrefs); * // Result: { theme: 'dark', size: 'medium' } */ export function deepMerge(...objects) { const result = {}; for (const obj of objects) { if (!isPlainObject(obj)) continue; for (const key in obj) { if (Object.hasOwn(obj, key)) { if (isPlainObject(obj[key]) && isPlainObject(result[key])) { result[key] = deepMerge(result[key], obj[key]); } else { result[key] = obj[key]; } } } } return result; } /** * Pick specific keys from object * * @param {Object} obj - Source object * @param {Array<string>} keys - Keys to pick * @returns {Object} New object with only specified keys * * @example * const user = { id: 1, name: 'John', email: 'john@example.com', password: 'secret' }; * const publicUser = pick(user, ['id', 'name', 'email']); * // Result: { id: 1, name: 'John', email: 'john@example.com' } */ export function pick(obj, keys) { const result = {}; for (const key of keys) { if (key in obj) { result[key] = obj[key]; } } return result; } /** * Omit specific keys from object * * @param {Object} obj - Source object * @param {Array<string>} keys - Keys to omit * @returns {Object} New object without specified keys * * @example * const user = { id: 1, name: 'John', password: 'secret' }; * const safeUser = omit(user, ['password']); * // Result: { id: 1, name: 'John' } */ export function omit(obj, keys) { const result = { ...obj }; for (const key of keys) { delete result[key]; } return result; } /** * Get nested object value safely * * @param {Object} obj - Source object * @param {string} path - Dot-notation path (e.g., 'user.profile.name') * @param {*} defaultValue - Default value if path doesn't exist * @returns {*} Value at path or default value * * @example * const data = { user: { profile: { name: 'John' } } }; * const name = get(data, 'user.profile.name', 'Unknown'); * const age = get(data, 'user.profile.age', 0); */ export function get(obj, path, defaultValue = undefined) { const keys = path.split('.'); let result = obj; for (const key of keys) { if (result === null || result === undefined || !(key in result)) { return defaultValue; } result = result[key]; } return result; } export { isEmpty as default };