
Research
/Security News
Miasma Mini Shai-Hulud Hits ImmobiliareLabs npm Packages
Miasma Mini Shai-Hulud hits @immobiliarelabs Backstage plugins, targeting GitLab and LDAP auth packages on npm.
@hyperfrontend/data-utils
Advanced tools
Comprehensive data structure manipulation with circular reference handling and custom class support.
@hyperfrontend/data-utils provides industrial-strength utilities for inspecting, transforming, and comparing complex JavaScript data structures. Unlike basic utility libraries that fail on circular references or treat custom classes as generic objects, this library handles self-referential structures safely and allows registration of custom classes (Maps, Sets, domain models) with specialized traversal logic.
The library centers around a powerful traverse() function that recursively walks any data structure with configurable depth control, executing callbacks at each node. Built on this foundation are specialized utilities: deep equality comparison (isIdentical), selective cloning with filtering (selectiveCopy), circular reference detection (hasCircularReference), path-based searches (locateKey, locateText), and structural transformations (renameKey, removeKey, replaceText). An enhanced type system via getType() distinguishes null, arrays, and custom classes beyond native typeof.
__proto__ during cloning operationsUses a class registration system where custom types (Map, Set, domain models) define traversal operators (getKeys, read, write, remove, instantiate). Reference stacks track visited objects during traversal to detect circular references without WeakMap dependencies. Traversal functions use functional composition with configurable predicates and callbacks, allowing complex operations to be built from simple building blocks.
Production applications frequently encounter circular references in DOM nodes, framework state (React, Vue), ORM models with bidirectional relationships, and graph structures. Standard JSON.stringify() throws on circular references, and naive recursive algorithms cause stack overflow. This library detects circular dependencies safely and handles them appropriately - isIdentical() compares structures with matching circular patterns, selectiveCopy() preserves or breaks cycles as needed, and hasCircularReference() validates data before serialization.
Generic utility libraries treat all objects identically, failing to traverse Maps, Sets, or custom data structures correctly. If your application uses Map for caching, Set for unique collections, or domain classes (User, Order, Graph nodes), generic utilities miss their internal state. Register custom classes once with registerIterableClass(), defining how to read keys, access values, and create instances - then every utility (traverse, isIdentical, selectiveCopy) automatically handles your custom types.
Implementing reliable deep equality is deceptively complex - must handle primitives, nested objects, arrays, functions, dates, circular references, and custom classes. Testing frameworks often provide basic deep equality that fails on edge cases. This library's isIdentical() handles all JavaScript types correctly, compares functions by string representation, tracks circular reference positions (not just existence), and works with registered custom classes. Replace brittle manual comparisons with battle-tested equality checking.
Common operations like "rename all 'id' keys to '_id'" or "remove all null values from nested config" require recursive tree walking with careful state management. Manual implementations are error-prone (stack overflow, circular references, prototype pollution). Functions like renameKey(), removeKey(), and replaceText() handle recursion, depth control, and edge cases automatically. Transform deeply nested API responses, sanitize user data, or migrate data structures without writing custom traversal logic.
Runtime type validation requires distinguishing null from objects, arrays from plain objects, and custom classes from generic objects - but typeof null === 'object' and typeof [] === 'object'. The getType() function returns precise types ('null', 'array', 'CustomClassName') and integrates with class registration. Use it to build robust runtime validators, safely access properties, or implement multi-method dispatch based on actual runtime types.
npm install @hyperfrontend/data-utils
import { getType } from '@hyperfrontend/data-utils'
getType(null) // 'null' (not 'object')
getType([1, 2, 3]) // 'array' (not 'object')
getType(new Map()) // 'object' (unless registered)
// After registering custom class
class User {}
registerClassTypes(User)
getType(new User()) // 'User'
import { isIdentical } from '@hyperfrontend/data-utils'
const obj1 = { a: 1, b: { c: 2 } }
const obj2 = { a: 1, b: { c: 2 } }
isIdentical(obj1, obj2) // true (deep equality)
// Handles circular references
const circular1 = { name: 'node' }
circular1.self = circular1
const circular2 = { name: 'node' }
circular2.self = circular2
isIdentical(circular1, circular2) // true (circular patterns match)
import { traverse } from '@hyperfrontend/data-utils'
const data = { user: { name: 'Alice', age: 30 }, settings: { theme: 'dark' } }
// Collect all string values
const strings = []
traverse(
data,
(key, value, path, state) => {
if (typeof value === 'string') state.strings.push(value)
},
{ depth: [0, '*'] },
{ strings }
)
// strings: ['Alice', 'dark']
// Search with depth limits
traverse(data, callback, { depth: [0, 2] }, state) // Only 2 levels deep
import { selectiveCopy } from '@hyperfrontend/data-utils'
const data = {
user: { id: 1, name: 'Alice', password: 'secret' },
settings: { theme: 'dark' },
}
// Clone without sensitive fields
const sanitized = selectiveCopy(data, {
includeKey: (value, path, key) => key !== 'password',
})
// sanitized: { user: { id: 1, name: 'Alice' }, settings: { theme: 'dark' } }
// Clone only specific paths
const partial = selectiveCopy(data, {
includeKey: (value, path) => path[0] === 'user',
})
// partial: { user: { id: 1, name: 'Alice', password: 'secret' } }
import { hasCircularReference, locateCircularReference } from '@hyperfrontend/data-utils'
const obj = { a: 1 }
obj.self = obj
hasCircularReference(obj) // true
const locations = locateCircularReference(obj)
// locations: [{ startPath: ['self'], destinationPath: [] }]
// Meaning: path ['self'] references the root object
import { locateKey, locateText } from '@hyperfrontend/data-utils'
const data = {
user: { userId: 1, name: 'Alice' },
admin: { userId: 2, name: 'Bob' },
}
// Find all paths containing 'userId'
locateKey(data, 'userId')
// [['user', 'userId'], ['admin', 'userId']]
// Find keys matching pattern
locateKey(data, /user/i)
// [['user'], ['user', 'userId'], ['admin', 'userId']]
// Find values containing text
locateText(data, 'Alice')
// [['user', 'name']]
import { renameKey, removeKey, replaceText } from '@hyperfrontend/data-utils'
const data = { user_id: 1, user_name: 'Alice' }
// Rename keys throughout structure
renameKey(data, 'user_id', 'userId')
// { userId: 1, user_name: 'Alice' }
// Remove keys by pattern
removeKey(data, /^user_/)
// { userId: 1 } (removes keys starting with 'user_')
// Replace text in all string values
replaceText(data, 'Alice', 'Bob')
// { userId: 1, user_name: 'Bob' }
import { registerIterableClass, registerClassTypes } from '@hyperfrontend/data-utils'
class Graph {
nodes = new Map()
addNode(id, value) {
this.nodes.set(id, value)
}
}
// Register as traversable type
registerIterableClass(
Graph,
(graph) => Array.from(graph.nodes.keys()).map(String), // getKeys
(graph, key) => graph.nodes.get(key), // read
(graph, value, key) => graph.nodes.set(key, value), // write
(graph, key) => graph.nodes.delete(key), // remove
() => new Graph() // instantiate
)
// Now all utilities work with Graph instances
const g1 = new Graph()
g1.addNode('a', 1)
const g2 = selectiveCopy(g1) // Deep clone works
isIdentical(g1, g2) // true
getType(target): DataType | string - Enhanced typeof with null/array/class distinctionsameType(a, b): boolean - Check if two values have identical typessameStructure(a, b): boolean | DataType - Check if values share structure/typeisIdentical(a, b): boolean - Deep equality with circular reference supporttraverse(target, callback, options, state): state - Recursively walk data structures with callbackslocateKey(target, pattern, options?): string[][] - Find all paths matching key patternlocateText(target, pattern, options?): string[][] - Find all paths containing text valuegetValue(target, path): unknown - Safely access nested values by pathgetDepth(target): number - Calculate maximum nesting depthselectiveCopy(target, options): Partial<T> - Deep clone with filtering and circular reference handlingrenameKey(target, oldKey, newKey, options?): void - Rename keys throughout structureremoveKey(target, pattern, options?): void - Remove keys matching patternreplaceText(target, pattern, replacement, options?): void - Replace text in all string valueshasCircularReference(target): boolean - Check if structure contains circular referenceslocateCircularReference(target): CircularReference[] - Find all circular reference locationscircularReference(target): CircularReference[] - Alias for locateCircularReferenceregisterClassTypes(...classes): void - Register classes for type detectionregisterIterableClass(classRef, getKeys, read, write, remove, instantiate?): void - Register custom traversable classesderegisterClassTypes(...classes): void - Remove registered classesderegisterIterableClass(classRef): void - Remove registered iterable classisIterable(target): boolean - Check if value is iterable (object/array/custom)isIterableType(type): boolean - Check if type string represents iterablegetIterableTypes(): string[] - Get all registered iterable type namesgetIterableOperators(type): IterableOperators - Get traversal operators for typegetKeysFromIterable(target, type): string[] - Get all keys from iterable valuegetUniqueKeys(...targets): string[] - Get all unique keys from multiple iterablescontainsKeys(target, keys): boolean - Check if target contains all specified keysisMarker(key): boolean - Check if key is internal marker (for circular reference tracking)| Platform | Support |
|---|---|
| Browser | ✅ |
| Node.js | ✅ |
| Web Workers | ✅ |
| Deno, Bun, Cloudflare Workers | ✅ |
| Format | File | Tree-Shakeable |
|---|---|---|
| ESM | index.esm.js | ✅ |
| CJS | index.cjs.js | ❌ |
| IIFE | bundle/index.iife.min.js | ❌ |
| UMD | bundle/index.umd.min.js | ❌ |
Bundle size: 12 KB (minified, self-contained)
<!-- unpkg -->
<script src="https://unpkg.com/@hyperfrontend/data-utils"></script>
<!-- jsDelivr -->
<script src="https://cdn.jsdelivr.net/npm/@hyperfrontend/data-utils"></script>
<script>
const { isEqual, deepClone, getType } = HyperfrontendDataUtils
</script>
Global variable: HyperfrontendDataUtils
None — zero external dependencies.
This library is part of the hyperfrontend monorepo.
MIT
FAQs
Data manipulation and transformation utilities.
The npm package @hyperfrontend/data-utils receives a total of 165 weekly downloads. As such, @hyperfrontend/data-utils popularity was classified as not popular.
We found that @hyperfrontend/data-utils demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
Miasma Mini Shai-Hulud hits @immobiliarelabs Backstage plugins, targeting GitLab and LDAP auth packages on npm.

Security News
Rolldown paused Rust React Compiler integration after a 5MB binary size increase raised concerns about shipping React-specific code to all Vite users.

Security News
/Research
Mini Shai-Hulud expands into the Go ecosystem after hitting LeoPlatform npm packages and targeting GitHub Actions workflows.