# @bemoje/object

Comprehensive object manipulation utilities for property definition, traversal, filtering, mapping, prototype chains, and descriptor management.

[![TypeScript](https://img.shields.io/badge/TypeScript-5-blue)](https://www.typescriptlang.org/) [![Module](https://img.shields.io/badge/Module-ESM-yellow)](https://nodejs.org/api/esm.html)

## Exports

<!-- EXPORTS_START -->

- **arrAssign**: Array assignment function that merges arrays excluding null and undefined values.
- **className**: Get the class name of an object from its constructor.
- **constructorOf**: Returns the constructor of the given object.
- **createArrayMerger**: Creates a function that merges arrays based on a predicate function.
- **createObjectMerger**: Creates a function that merges objects based on a predicate function.
- **defineAccessors** on an object with enhanced descriptor handling.
- **defineGetter**: Define a getter property on an object with enhanced descriptor handling.
- **defineLazyProperty**: Define a lazy property that evaluates its getter on first access and then caches the value.
- **defineMethod**: Define a method property on an object with enhanced descriptor handling.
- **defineProperty**: Utility function for defining properties on objects with enhanced descriptor handling.
- **defineSetter**: Define a setter property on an object with enhanced descriptor handling.
- **defineValue**: Define a value property on an object with enhanced descriptor handling.
- **deleteNullishPropsMutable**: Mutably delete enumerable properties with null or undefined values.
- **entriesOf**: Same as Object.entries except the keys are typed as keyof T.
- **filterObject**: Filter an object's own enumerable properties by predicate.
- **filterObjectMutable**: Mutably filter an object's own properties based on a given predicate.
- **getClassChain**.
- **getConfigurableMethodOrGetterKeys**: Returns an array of keys representing configurable methods or getters of an object.
- **getKeys**: Returns an array of the own property keys of an object. Every combination of ways to toggle enumerable/non-enumerable/strings/symbols are available. Ignoring specific keys is also possible.
- **getKeysPreset**: Creates a preset function for getting object keys with specific filtering options.
- **getOwnProperty**: Returns a given own property value of a given object.
- **getPrototypeChain**: Get the prototype chain of any object. Returns prototype objects, not constructors.
- **getSuperClass**: Get the immediate superclass of a target. Returns Object if no meaningful superclass exists.
- **getSuperClasses**. Simpler version without overloads - just returns the class chain.
- **hasOwnProperty**: Object.prototype.hasOwnProperty.call
- **hasProperty**: Determines if a property is defined on an object, including 'own' and prototype chain.
- **hasPrototypeChainProperty**: Determines if a property is defined on an object's prototype prototype chain, not including the object itself.
- **inheritPrototypeMembers**: Copies prototype members from a source constructor to a target constructor, excluding specified keys.
- **inheritStaticMembers**: Copies static members from a source constructor to a target constructor, excluding specified keys.
- **isAccessorDescriptor**: Check if the given descriptor is an accessor descriptor.
- **isEnumerable**: Check if the property is enumerable.
- **isMethodValueDescriptor**.
- **isValueDescriptor**: Check if the given descriptor is a value descriptor.
- **iterableFirstElement**: Returns the first element of an iterable object.
- **iterateObject** - Prevents circular reference loops - Preserves traversal order
- **keysOf**: Same as Object.keys except the keys are typed as string keys of T.
- **mapObjectEntries**: Maps over an object's entries, transforming both keys and values using the provided function.
- **mapObjectKeys**: Maps over an object's keys, transforming each key using the provided function while preserving values.
- **objAssign**: Like Object.assign, but only copies source object property values != null.
- **objDeepFreeze**: Deep freezes an object. Note: Deep recursion may cause stack overflow for very deeply nested objects.
- **objDefineLazyProperty**: Defines a lazy property on an object. The property will be lazily evaluated on the first access and then cached for subsequent accesses. The property is both enumerable and configurable.
- **objDelete**: Deletes a property from an object and returns the modified object.
- **objGet**: Retrieves the value associated with the specified key from an object.
- **objGetOrDefault**: Gets a property value from an object or creates it using a factory function if it doesn't exist.
- **objGetOrDefaultValue**: This function attempts to retrieve a value from an object using a provided key. If the key does not exist in the object, it sets the provided default value in the object and returns it.
- **objHas**: Checks if an object has a specific key.
- **objOmitKeysMutable**: Deletes the specified keys from an object in a mutable way.
- **objPropertyValueToGetter**: Converts the specified properties of an object into getter functions.
- **objSet**: Sets a value for a key in an object and returns the value.
- **objSize**: Returns the number of enumerable keys in an object.
- **objSortKeys**: Sorts the keys of an object in alphabetical order unless a custom compare function is provided.
- **objToMap**: Converts an object to a Map.
- **objUpdate**: Updates the value of a specific key in an object using a callback function.
- **objUpdatePropertyDescriptors**: Updates the property descriptors of the specified properties on the given object.
- **propertyIsEnumerable**: Calls Object.prototype.propertyIsEnumerable on the given object.
- **setEnumerable**: Sets the enumerable property of the specified properties of an object to true.
- **setNonConfigurable**: Sets the specified properties of an object as non-configurable.
- **setNonEnumerable**: Sets the specified properties of an object as non-enumerable.
- **setNonWritable**: Sets the specified properties of an object to be non-writable.
- **setWritable**: Sets the specified properties of an object to be non-writable.
- **sortKeys**: Sort an object's keys.
- **sortKeysLike**: Sorts the keys of an object in the given order.
- **staticClassKeysOf**: Returns the static string-property keys of a class but without the natively built-in keys 'length', 'name', and 'prototype'.
- **valuesOf**: Get the values of an object with type-safe return value.

<!-- EXPORTS_END -->

## Installation

```bash
npm install @bemoje/object
```

## Usage

### Object Assignment

```ts
import { objAssign } from '@bemoje/object'

// Like Object.assign but skips null/undefined values
objAssign({ a: 1, b: 2 }, { b: null, c: 3 })
// { a: 1, b: 2, c: 3 }
```

### Property Definition

```ts
import { defineGetter, defineSetter, defineMethod, defineValue, defineLazyProperty } from '@bemoje/object'

const obj = {}

defineGetter(obj, 'now', () => Date.now())
defineMethod(obj, 'greet', function () {
  return 'hello'
})
defineValue(obj, 'version', '1.0.0')

// Lazy property: computed once on first access, then cached
defineLazyProperty(obj, 'config', () => loadExpensiveConfig())
```

### Filter and Map Objects

```ts
import { filterObject, mapObject, mapObjectKeys, mapObjectEntries } from '@bemoje/object'

const data = { a: 1, b: 2, c: 3 }

filterObject(data, (value) => value > 1)
// { b: 2, c: 3 }

mapObject(data, (value) => value * 10)
// { a: 10, b: 20, c: 30 }

mapObjectKeys(data, (key) => key.toUpperCase())
// { A: 1, B: 2, C: 3 }
```

### Prototype Chain Inspection

```ts
import { getPrototypeChain, getClassChain, getSuperClasses } from '@bemoje/object'

class Animal {}
class Dog extends Animal {}

getPrototypeChain(new Dog()) // [Dog.prototype, Animal.prototype, Object.prototype, null]
getClassChain(Dog) // [Animal, Object]
getSuperClasses(Dog) // [Animal, Object]
```

### Inheritance Utilities

```ts
import { inheritPrototypeMembers, inheritStaticMembers } from '@bemoje/object'

// Copy prototype methods from source to target class
inheritPrototypeMembers(TargetClass, SourceClass, ['excludeMethod'])
inheritStaticMembers(TargetClass, SourceClass)
```

### Deep Operations

```ts
import { objDeepFreeze, iterateObject } from '@bemoje/object'

// Deep freeze an object
const frozen = objDeepFreeze({ nested: { deep: { value: 42 } } })

// Traverse all properties depth-first
for (const node of iterateObject({ a: { b: [1, 2] } })) {
  console.log(node.propertyPath, node.value, node.isLeaf)
}
// 'a'       { b: [1, 2] }  false
// 'a.b'     [1, 2]         false
// 'a.b[0]'  1              true
// 'a.b[1]'  2              true
```

### Sort, Delete, Reduce

```ts
import { objSortKeys, objDelete, objReduce, objIsEmpty } from '@bemoje/object'

objSortKeys({ c: 3, a: 1, b: 2 }) // { a: 1, b: 2, c: 3 }
objDelete({ name: 'John', age: 30 }, 'age') // { name: 'John' }
objReduce({ a: 1, b: 2 }, (acc, val) => acc + val, 0) // 3
objIsEmpty({}) // true
```

### Typed Helpers

```ts
import { keysOf, valuesOf, entriesOf } from '@bemoje/object'

const obj = { name: 'Alice', age: 30 }
keysOf(obj) // ['name', 'age']  (typed as ('name' | 'age')[])
valuesOf(obj) // ['Alice', 30]
entriesOf(obj) // [['name', 'Alice'], ['age', 30]]
```
