@hyperfrontend/data-utils§

Four objects drawn in a row, state, user, cart and line, joined by their forward references, with three back references drawn as arcs; a cursor walks the graph depth first, and each arc that lands on an object already visited lights up and is numbered, until all three are lit and the count beside locateCircularReference reads threeFour objects drawn in a row, state, user, cart and line, joined by their forward references, with three back references drawn as arcs; a cursor walks the graph depth first, and each arc that lands on an object already visited lights up and is numbered, until all three are lit and the count beside locateCircularReference reads three

Comprehensive data structure manipulation with circular reference handling and custom class support.

What is @hyperfrontend/data-utils?

@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.

Key Features

  • Circular Reference Detection

    Identify and locate self-referential structures without stack overflow

  • Custom Class Registration

    Teach utilities how to traverse Maps, Sets, or domain-specific classes with custom operators

  • Deep Data Traversal

    Walk nested structures with depth control, callbacks, and early exit support

  • Structural Deep Equality

    Compare objects with circular references using position-aware reference tracking

  • Selective Deep Cloning

    Copy data structures with predicate filtering and circular reference preservation

  • Path-Based Search

    Locate keys or text values anywhere in nested structures with regex support

  • In-Place Transformations

    Rename keys, remove properties, or replace text throughout data trees

  • Enhanced Type Detection

    Distinguish null, arrays, and registered classes beyond standard typeof

  • Zero External Dependencies

    Self-contained implementation with no third-party runtime dependencies

  • Prototype Pollution Protection

    Automatically filters __proto__ during cloning operations

Why Use @hyperfrontend/data-utils?

Handle Real-World Data Structures with Circular References

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.

Work with Custom Classes Beyond Plain Objects

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.

Deep Equality Without Manual Implementation

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.

Surgical Data Transformations Without Manual Recursion

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.

Type-Safe Data Inspection for Runtime Validation

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.

Installation

npm install @hyperfrontend/data-utils

Quick Start

Enhanced Type Detection

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'

Deep Equality with Circular References

import { isIdentical, setConfig } from '@hyperfrontend/data-utils'

const obj1 = { a: 1, b: { c: 2 } }
const obj2 = { a: 1, b: { c: 2 } }
isIdentical(obj1, obj2) // true (deep equality)

// Circular references need reference tracking; without it the comparison recurses until the stack overflows
setConfig({ detectCircularReferences: true })

const circular1 = { name: 'node' }
circular1.self = circular1
const circular2 = { name: 'node' }
circular2.self = circular2
isIdentical(circular1, circular2) // true (circular patterns match)

Traverse Data Structures

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

Selective Deep Cloning

import { selectiveCopy } from '@hyperfrontend/data-utils'

const data = {
  user: { id: 1, name: 'Alice', password: 'secret' },
  settings: { theme: 'dark' },
}

// Clone without sensitive fields
const { clone: sanitized, skipped } = selectiveCopy(data, {
  include: (value, path, key) => key !== 'password',
})
// sanitized: { user: { id: 1, name: 'Alice' }, settings: { theme: 'dark' } }
// skipped: [{ target: 'secret', path: ['user', 'password'], key: 'password', dataType: 'string' }]

// Clone only specific paths
const { clone: partial } = selectiveCopy(data, {
  include: (value, path) => path[0] === 'user',
})
// partial: { user: { id: 1, name: 'Alice', password: 'secret' } }

Detect and Locate Circular References

import { hasCircularReference, locateCircularReference } from '@hyperfrontend/data-utils'

const obj = { a: 1 }
obj.self = obj

hasCircularReference(obj) // true

const locations = locateCircularReference(obj)
// locations: [CircularReference { location: { path: ['self'] }, target: { path: [] } }]
// Meaning: path ['self'] references the root object
// One result by default: pass '*' as the second argument to get every cycle in the graph

Search for Keys and Values

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']]

Transform Data In-Place

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' }

Register Custom Classes

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 { clone: g2 } = selectiveCopy(g1) // Deep clone works, and g2 is a Graph
isIdentical(g1, g2) // true

API Overview

There is one walker. traverse recurses through anything iterable and calls your callback at every data point with (key, value, path, state, parent), where path is the list of keys that got there and state is an object you hand in and get back. Most of the rest of the package is a callback over it: locateKey, locateText, renameKey, removeKey and replaceText differ only in what their callback does at each node, and all five return the same string[][] of paths they acted on. The factory behind it, createTraversal, is exported too, so a walk with a different admission rule is one call away.

Back references are opt in, because tracking them costs. setConfig with { detectCircularReferences: true } swaps that plain recursion for one that keeps a stack of the references on the path down to the value it is visiting, which is what lets isIdentical compare two self-referential graphs and selectiveCopy rebuild the loops inside its clone. With the flag off both assume an acyclic structure, and a cycle overflows the stack.

Two functions never need the flag, because they set it for the length of their own call: hasCircularReference answers yes or no, and locateCircularReference reports where each cycle was found and what it points back to, one by default and all of them if you pass '*'. Note that selectiveCopy resolves to { clone, skipped }, so the data points it left out stay inspectable instead of vanishing.

Out of the box only arrays and plain objects are traversable; everything else is a leaf the walk stops at. registerIterableClass is how that list grows. Give it a class plus four operators (getKeys, read, write, remove) and an optional instantiate, and from that point every function above reads and writes inside its instances exactly as it does a plain object: getType reports the class name rather than 'object', searches descend into it, and selectiveCopy rebuilds a real instance rather than an object literal. One registration is what turns a Map, a Set or your own domain model into a first-class traversable type.

Every option, callback signature and result type is in the API reference.

Compatibility

Runs on

  • Node.js>=18.0.0supported
  • Browserssupported
  • Web Workerssupported

Ships as

  • ESMTree-shakeable
  • CJSNode and older bundlers
  • IIFEHyperfrontendDataUtils
  • UMDHyperfrontendDataUtils

CDN Usage

<!-- unpkg -->
<script src="https://unpkg.com/@hyperfrontend/data-utils"></script>

<!-- jsDelivr -->
<script src="https://cdn.jsdelivr.net/npm/@hyperfrontend/data-utils"></script>

<script>
  const { isIdentical, selectiveCopy, getType } = HyperfrontendDataUtils
</script>

Global variable: HyperfrontendDataUtils

Dependencies

None: zero external dependencies.

Architecture Highlights§

Custom types are taught to the library through registerIterableClass, which takes a class plus four operators (getKeys, read, write, remove) and an optional instantiate. Once registered, a class is traversed, compared, and cloned by the same functions that handle plain objects. Circular references are found by tracking the references actually visited, not by capping depth, so a deep but acyclic structure is never mistaken for a loop.

API Reference§

Filter:

ƒFunctions

§function

containsKeys(target: unknown, keys: string[]): boolean

Checks if the target contains all specified keys.
Parameters
NameTypeDescription
§target
unknownThe target to check.
§keys
string[]The keys to check for.
Returns
boolean
True if the target contains all specified keys, false otherwise.
Example

Checking if object contains specific keys

containsKeys({ a: 1, b: 2 }, ['a', 'b']) // true
containsKeys({ a: 1 }, ['a', 'b']) // false
§function

deregisterClassTypes(...classRefs: UnknownClass<unknown>[]): void

Removes one or more registered classes used to identify values as distinct data types.
Parameters
NameTypeDescription
§...classRefs
UnknownClass<unknown>[]One or more class references to deregister. If none provided, all registered classes will be deregistered.
Example

Deregistering class types

deregisterClassTypes(MyCustomClass)
deregisterClassTypes() // clears all
§function

deregisterIterableClass<T>(...classRefs: UnknownClass<T>[]): void

Removes one or more registered iterable classes. Removes all registered iterable classes except built-ins (Array and Object) when no references are provided.
Parameters
NameTypeDescription
§...classRefs
UnknownClass<T>[]The class constructors to deregister
Example

Deregistering iterable classes

deregisterIterableClass(MyCollection)
deregisterIterableClass() // clears all except Array/Object
§function

getConfig(): Config

Returns the global settings.
Returns
Config
The current global configuration object
Example

Retrieving configuration

const { detectCircularReferences } = getConfig()
§function

getDepth(target: unknown): [number, string[][]]

Returns the total depth of a value's data structure, and returns a list of locations that are the most deeply nested. It supports other iterable data types, provided these have been made known using registerIterableClass.
Parameters
NameTypeDescription
§target
unknownThe target value to analyze for depth
Returns
[number, string[][]]
A tuple containing the maximum depth and an array of paths to the deepest locations
Example

Getting depth of nested object

getDepth({ a: { b: { c: 1 } } }) // [3, [['a', 'b', 'c']]]
§function

getIterableOperators<T>(dataType: T): IterableOperators

Retrieves iterable operators for a given data type.
Parameters
NameTypeDescription
§dataType
TThe type of data to get operators for
Returns
IterableOperators
Object containing getKeys, read, write, remove, and instantiate operators
Example

Retrieving operators for array type

const ops = getIterableOperators('array')
const keys = ops.getKeys([1, 2, 3]) // ['0', '1', '2']
§function

getIterableTypes<T>(): T[]

Returns a list of iterable data types. By default 'array' and 'object' are included., but can be extended by using registerIterableClass.
Returns
T[]
Array of iterable data types.
Example

Listing registered iterable types

getIterableTypes() // ['array', 'object', ...registered types]
§function

getKeysFromIterable<T>(target: unknown, dataType: T): string[]

Gets the keys from an iterable target based on its data type.
Parameters
NameTypeDescription
§target
unknownThe target to get the keys from.
§dataType
TThe data type of the target.
Returns
string[]
The keys from the iterable target.
Example

Extracting keys from object

getKeysFromIterable({ a: 1, b: 2 }, 'object') // ['a', 'b']
§function

getType<T>(target: unknown): T

Returns the data type of the target. Uses native typeof operator, however, makes distinction between null, array, and object. Also, when classes are registered via registerClass, it checks if objects are instance of any known registered class.
Parameters
NameTypeDescription
§target
unknownThe target to get the data type of.
Returns
T
The data type of the target.
Example

Determining data types

getType([1, 2]) // 'array'
getType({ a: 1 }) // 'object'
getType(null) // 'null'
§function

getUniqueKeys(target: unknown, pattern: string | RegExp, options?: DepthConfig): string[]

Returns a list of unique key names that match a pattern or an exact value anywhere in the data structure of the target. A depth option is available to narrow down the iteration scope. It supports other iterable data types, provided these have been made known using registerIterableClass.
Parameters
NameTypeDescription
§target
unknownThe target value to search within
§pattern
string | RegExpThe string or regular expression pattern to match against key names (defaults to matching all keys)(default: ...)
§options?
DepthConfigOptional configuration to control traversal depth
Returns
string[]
An array of unique key names that match the pattern
Example

Finding unique keys by pattern

getUniqueKeys({ a: { b: 1 }, c: { b: 2 } }, 'b') // ['b']
getUniqueKeys(data, /^user/) // keys starting with 'user'
§function

getValue<T>(target: unknown, path: [string, ...string[]], defaultValue?: DefaultValueOptions<T>): T

Gets the value at the specified path from the target.
Parameters
NameTypeDescription
§target
unknownThe target to get the value from.
§path
[string, ...string[]]The path to the value.
§defaultValue?
DefaultValueOptions<T>The default value to return if the path does not exist or an error occurs.
Returns
T
The value at the specified path or the default value.
Example

Retrieving nested values

getValue({ a: { b: 1 } }, ['a', 'b']) // 1
getValue({ a: 1 }, ['x'], { onMissingKey: 0 }) // 0
§function

hasCircularReference(target: unknown): boolean

Returns true for values that have circular references. A reference that is shared between two branches is not a cycle; only a value that contains itself is. It supports other iterable data types, provided these have been made known using registerIterableClass.
Parameters
NameTypeDescription
§target
unknownThe value to check for circular references
Returns
boolean
True if the value contains circular references, false otherwise
Example

Detecting circular references

const obj = { a: {} }
obj.a.self = obj
hasCircularReference(obj) // true
hasCircularReference({ a: 1 }) // false
§function

isIdentical(targetA: unknown, targetB: unknown): boolean

Returns true when both values are identical. For primitive values, use strict equality comparison. For non-primitive values, it checks equality by reviewing values' properties and values. It supports other iterable data types, provided these have been made known using registerIterableClass.
Parameters
NameTypeDescription
§targetA
unknownThe first value to compare
§targetB
unknownThe second value to compare
Returns
boolean
True if the values are identical, false otherwise
Example

Comparing values for identity

isIdentical({ a: 1 }, { a: 1 }) // true
isIdentical([1, 2], [1, 2]) // true
isIdentical({ a: 1 }, { a: 2 }) // false
§function

isIterable(target: unknown): boolean

Checks if the target is iterable.
Parameters
NameTypeDescription
§target
unknownThe target to check.
Returns
boolean
true if the target is iterable, false otherwise.
Example

Checking if value is iterable

isIterable([1, 2]) // true
isIterable({ a: 1 }) // true
isIterable('string') // false
§function

isIterableType<T>(dataType: T): boolean

Checks if the provided data type is registered as an iterable type.
Parameters
NameTypeDescription
§dataType
TThe data type to check
Returns
boolean
true if the data type is iterable, otherwise false
Example

Checking iterable types

isIterableType('array') // true
isIterableType('object') // true
isIterableType('string') // false
§function

isMarker(text: string): boolean

Checks if a string is a valid marker format.
Parameters
NameTypeDescription
§text
stringThe string to check
Returns
boolean
True if the string matches the marker pattern
Example

Validating marker format

isMarker('__$0') // true
isMarker('__$123') // true
isMarker('regular') // false
§function

locateCircularReference(target: unknown, maxResults: number | "*"): CircularReference[]

Returns a list of locations where circular references occur. It supports other iterable data types, provided these have been made known using registerIterableClass.
Parameters
NameTypeDescription
§target
unknownThe value to search for circular references
§maxResults
number | "*"Maximum number of circular references to find (number or '*' for all)(default: 1)
Returns
CircularReference[]
An array of CircularReference objects indicating locations of circular references
Example

Locating circular references

const obj = { a: {} }
obj.a.self = obj
locateCircularReference(obj) // [CircularReference { location: ['a', 'self'], target: [] }]
§function

locateCircularReferenceRecursive(target: unknown, maxResults: number | "*", path: string[], stack: ReferenceStack, result: CircularReference[], root: boolean): CircularReference[]

Recursively searches for circular references in an object graph.
Parameters
NameTypeDescription
§target
unknownThe value to search
§maxResults
number | "*"Maximum number of results to find
§path
string[]Current path in the object graph
§stack
ReferenceStackReference stack for tracking visited objects
§result
CircularReference[]Array to collect found circular references
§root
booleanWhether this is the root call(default: false)
Returns
CircularReference[]
Array of CircularReference objects found
Example

Recursively locating circular references

const stack = referenceStack()
locateCircularReferenceRecursive(obj, 1, [], stack, [], true)
§function

locateKey(target: unknown, pattern: string | RegExp, options?: DepthConfig): string[][]

Returns a list of locations where the key name matches a pattern or an exact value anywhere in the data structure of the target. A depth option is available to narrow down the iteration scope. It supports other iterable data types, provided these have been made known using registerIterableClass.
Parameters
NameTypeDescription
§target
unknownThe target value to search within
§pattern
string | RegExpThe string or regular expression pattern to match against key names
§options?
DepthConfigOptional configuration to control traversal depth
Returns
string[][]
An array of paths to locations where the key pattern was found
Example

Locating keys in nested structure

locateKey({ a: { b: 1 }, c: { b: 2 } }, 'b') // [['a', 'b'], ['c', 'b']]
§function

locateText(target: unknown, pattern: string | RegExp, options?: DepthConfig): string[][]

Returns a list of locations where a text value matches a pattern or an exact value anywhere in the data structure of the target. A depth option is available to narrow down the iteration scope. It supports other iterable data types, provided these have been made known using registerIterableClass.
Parameters
NameTypeDescription
§target
unknownThe target value to search within
§pattern
string | RegExpThe string or regular expression pattern to match against text values
§options?
DepthConfigOptional configuration to control traversal depth
Returns
string[][]
An array of paths to locations where the text pattern was found
Example

Locating text values in structure

locateText({ a: 'hello', b: { c: 'hello' } }, 'hello') // [['a'], ['b', 'c']]
§function

marker(): string

Generates a unique marker string for object tagging.
Returns
string
A unique marker string prefixed with __$
Example

Generating unique marker

const tag = marker() // '__$16789012345001234567890'
§function

referenceStack(): ReferenceStack

Creates a new ReferenceStack instance.
Returns
ReferenceStack
A new ReferenceStack instance.
Example

Tracking object references

const stack = referenceStack()
stack.add(myObject)
stack.exists(myObject) // true
stack.remove(myObject)
stack.exists(myObject) // false
§function

registerClassTypes(...classRefs: UnknownClass[]): void

Registers one or more classes which will be used to identify values as distinct data types.
Parameters
NameTypeDescription
§...classRefs
UnknownClass[]One or more class references to register.
Returns
void
The result of the forEach operation (void)
Example

Registering custom class types

registerClassTypes(MyCustomClass, AnotherClass)
getType(new MyCustomClass()) // 'MyCustomClass'
§function

registerIterableClass<T>(classRef: UnknownClass<T>, getKeys: (target: T) => string[], read: (target: T, key: unknown) => unknown, write: (instance: T, value: unknown, key?: unknown) => void, remove: (instance: T, key: unknown) => void, instantiate: () => T): void

Registers a custom class as iterable, allowing the data utilities API to treat instances as map-like objects with their own unique data type.
Parameters
NameTypeDescription
§classRef
UnknownClass<T>The class constructor to register
§getKeys
(target: T) => string[]Function that returns all keys from an instance
§read
(target: T, key: unknown) => unknownFunction to read a value from an instance by key
§write
(instance: T, value: unknown, key?: unknown) => voidFunction to write a value to an instance (with optional key)
§remove
(instance: T, key: unknown) => voidFunction to remove a key from an instance
§instantiate
() => TFactory function to create new instances (defaults to calling constructor)(default: ...)
Example

Registering custom iterable class

registerIterableClass(
  MyMap,
  (m) => [...m.keys()],
  (m, k) => m.get(k),
  (m, v, k) => m.set(k, v),
  (m, k) => m.delete(k)
)
§function

removeKey(target: unknown, pattern: string | RegExp, options?: DepthConfig): string[][]

Removes any key names that match a pattern or an exact value anywhere in the data structure of the target and returns the location of keys that were removed. A depth option is available to narrow down the iteration scope. It supports other iterable data types, provided these have been made known using registerIterableClass.
Parameters
NameTypeDescription
§target
unknownThe target value to modify
§pattern
string | RegExpThe string or regular expression pattern to match against key names for removal
§options?
DepthConfigOptional configuration to control traversal depth
Returns
string[][]
An array of paths to locations where keys were removed
Example

Removing keys by pattern

const obj = { a: 1, temp: 2, b: { temp: 3 } }
removeKey(obj, 'temp') // [['temp'], ['b', 'temp']]
§function

renameKey(target: unknown, pattern: string | RegExp, name: string, options?: DepthConfig): string[][]

Renames any key names that match a pattern or an exact value anywhere in the data structure of the target and returns the location of keys that were edited. A depth option is available to narrow down the iteration scope. It supports other iterable data types, provided these have been made known using registerIterableClass.
Parameters
NameTypeDescription
§target
unknownThe target value to modify
§pattern
string | RegExpThe string or regular expression pattern to match against key names
§name
stringThe new name to assign to matching keys
§options?
DepthConfigOptional configuration to control traversal depth
Returns
string[][]
An array of paths to locations where keys were renamed
Example

Renaming keys in structure

const obj = { old: 1, nested: { old: 2 } }
renameKey(obj, 'old', 'new') // [['new'], ['nested', 'new']]
§function

replaceText(target: unknown, pattern: string | RegExp, text: string, options?: DepthConfig): string[][]

Edits any text by replacing any string or substring that matches a pattern or an exact value anywhere in the data structure of the target and returns the location of the original text that were edited. A depth option is available to narrow down the iteration scope. It supports other iterable data types, provided these have been made known using registerIterableClass.
Parameters
NameTypeDescription
§target
unknownThe target value to modify
§pattern
string | RegExpThe string or regular expression pattern to match against text values
§text
stringThe replacement text for matching values
§options?
DepthConfigOptional configuration to control traversal depth
Returns
string[][]
An array of paths to locations where text was replaced
Example

Replacing text in structure

const obj = { a: 'hello world', b: { c: 'hello' } }
replaceText(obj, 'hello', 'hi') // [['a'], ['b', 'c']]
§function

sameStructure(targetA: unknown, targetB: unknown): false | DataType

Checks whether two targets have the same structure.
Parameters
NameTypeDescription
§targetA
unknowndata to compare
§targetB
unknowndata to compare
Returns
false | DataType
The data type if both targets have the same structure, otherwise false.
Example

Comparing structures

sameStructure({ a: 1, b: 2 }, { a: 'x', b: 'y' }) // 'object'
sameStructure({ a: 1 }, { b: 1 }) // false
§function

sameType<T>(targetA: unknown, targetB: unknown): false | T

Checks if two targets are of the same data type.
Parameters
NameTypeDescription
§targetA
unknownThe first target to compare
§targetB
unknownThe second target to compare
Returns
false | T
The common data type if both targets are of the same type; otherwise, false.
Example

Comparing data types

sameType([1], [2]) // 'array'
sameType({}, []) // false
§function

selectiveCopy<T>(target: T, options?: SelectiveCopyOptions): SelectiveCopyResult<T>

Creates a clone of the target. Options can be provided to selectively copy values. Due to JavaScript language limitations context of bound functions is not known, thus functions cannot be reliably cloned. This algorithm instead copies function references by default instead. For the same reason getters and setters are not replicate, only their return values. This algorithm can replicate circular references, when configured. It supports other iterable data types, provided these have been made known using registerIterableClass.
Parameters
NameTypeDescription
§target
TThe value to clone
§options?
SelectiveCopyOptionsConfiguration options for selective copying
Returns
SelectiveCopyResult<T>
An object containing the cloned value and array of skipped data points
Example

Selective copying with options

const { clone, skipped } = selectiveCopy({ a: 1, b: 2 }, { includeKeys: ['a'] })
// clone = { a: 1 }, skipped = [{ path: ['b'], ... }]
§function

selectiveCopyForCircularReferencesRecursive<T>(target: T, path: string[], includeKey: SelectiveCopyPredicate, skipFunctions: boolean, recordSkip: DataPointOperation, stack: ReferenceStack, circularRefs: ReferenceLoop[], root: boolean): Partial<T>

Creates a clone of the target. Options can be provided to selectively copy values. This algorithm is able detect circular references, and optionally clone them.
Parameters
NameTypeDescription
§target
TThe object to clone
§path
string[]The current path in the data structure
§includeKey
SelectiveCopyPredicatePredicate function to determine if a key should be included
§skipFunctions
booleanWhether to skip function values
§recordSkip
DataPointOperationCallback to record skipped data points
§stack
ReferenceStackReference stack for tracking circular references
§circularRefs
ReferenceLoop[]Array to store circular reference information
§root
booleanWhether this is the root call(default: false)
Returns
Partial<T>
A partial clone of the target object
Example

Copying with circular reference handling

selectiveCopyForCircularReferencesRecursive(obj, [], () => true, false, () => {}, referenceStack(), [], true)
§function

selectiveCopyRecursive<T>(target: T, path: string[], includeKey: SelectiveCopyPredicate, skipFunctions: boolean, recordSkip: DataPointOperation): Partial<T>

Recursively creates a selective copy of an object based on predicate conditions.
Parameters
NameTypeDescription
§target
TThe object to copy
§path
string[]Current path in the object
§includeKey
SelectiveCopyPredicatePredicate to determine if a key should be included
§skipFunctions
booleanWhether to skip function values
§recordSkip
DataPointOperationCallback to record skipped data points
Returns
Partial<T>
Partial copy of the target based on predicate
Example

Basic recursive copy

selectiveCopyRecursive(obj, [], () => true, false, () => {})
§function

setConfig(config: Partial<Config>): void

Sets the global settings.
Parameters
NameTypeDescription
§config
Partial<Config>Partial configuration object to merge with current settings
Example

Configuring settings

setConfig({ detectCircularReferences: true })
§function

traverse<T, S>(target: T, callback: Callback, options?: DepthConfig, state?: S): S

Invokes a callback function for every data point in the data structure of the target value to let you do read and write operations. A depth option is available to narrow down the iteration scope.
Parameters
NameTypeDescription
§target
TThe value to traverse
§callback
CallbackFunction to invoke for each data point
§options?
DepthConfigOptional configuration to control traversal depth
§state?
SOptional state object to maintain across traversal callbacks
Returns
S
The state object after traversal completes
Example

Traversing data structure

traverse({ a: { b: 1 } }, (key, value, path) => {
  console.log(path.join('.'), '=', value)
})

◇Classes

§class

CircularReference

Represents a detected circular reference in an object graph. Tracks the location where the reference was found and its target.
Constructor
§new CircularReference(location: [string, ...string[]], target: string[])
Records a circular reference by the two paths that describe it.

Parameters

NameTypeDescription
§location
[string, ...string[]]Path from the root to where the reference was found; needs at least one segment
§target
string[]Path from the root to the value the reference points back to
Properties
§readonly location:LocationWhere in the object graph the reference was found, as the path from the root.
§readonly target:TargetWhat the reference points back to, as the path from the root; empty when that is the root itself.
§readonly keyDelimiter:"·"Separator placed between path segments when a path is rendered as text.
§get depth:numberDepth of the circular reference
Methods
§readonly toJSON(): string
Serializes the reference for JSON.stringify, which calls this in place of the object.

Returns

string
The same text toString produces
§readonly toString(): string
Renders the reference as location → target, each path joined with keyDelimiter.

Returns

string
The reference as one line of text
Example

Creating a circular reference instance

const ref = new CircularReference(['root', 'child'], ['root'])
console.log(ref.depth) // 1

◈Interfaces

§interface

Config

Configuration options for comparison and traversal
Properties
§samePositionOfOwnProperties:booleanA flag that indicates the API that two values can match only if their properties are in the same order when set to true
§detectCircularReferences:booleanA flag that indicates the API that circular references may exist and should keep a tally of reference stack. Turning this flag ON comes at a performance cost, so enable only when necessary.
§interface

DataPoint

Represents a single data point in an object graph.
Properties
§target:unknownThe value at this data point
§path:string[]Path segments from root to this point
§key:stringProperty key at this point
§dataType:DataTypeType of the data at this point
§interface

DefaultValueOptions

Options for providing default values when retrieving data.
Properties
§onMissingKey?:TDefault value to return when a key in the path is missing.
§onError?:TDefault value to return when an error occurs during retrieval.
§interface

DepthConfig

Configuration specifying traversal depth range
Properties
§depth:[] | [number, number | "*"] | [number]Depth range: [min, max] or [min] or empty
§interface

ICircularReference

Describes a circular reference in an object graph.
Properties
§readonly location:LocationLocation where the circular reference was detected
§readonly target:TargetTarget of the circular reference
§readonly depth:numberDepth of the circular reference
§interface

IterableOperators

Operators for iterating over custom class instances
Properties
§instantiate:() => TReturns a new (empty) instance.
§getKeys:(target: any) => string[]Returns list of iterable keys.
§read:(target: any, key: unknown) => unknownReturns a value corresponding to a key of class instance.
§write:(instance: T, value: unknown, key?: unknown) => voidSets a new value with specific key optionally on class instance.
§remove:(instance: T, key: unknown) => voidRemoves a key from the class instance.
§interface

Location

Represents the location where a circular reference was detected.
Properties
§path:[string, ...string[]]Path segments from root to the location
§interface

ReferenceLoop

Describes a reference loop detected during traversal.
Properties
§startPath:string[]Path where the loop starts
§destinationPath:string[]Path where the loop leads to
§interface

ReferenceStack

Stack for tracking object references during traversal
Properties
§size:numberTotal number of references in the stack.
§exists:(reference: unknown) => booleanReturns true if reference is already registered.
§lastSeen:(reference: unknown) => numberReturns a negative number corresponding to how many iterations ago the reference was registered in the stack relative to the last entry or null when it is not in the stack.
§add:(reference: unknown) => voidAdds a new reference into the stack.
§remove:(reference: unknown) => voidRemoves a reference from the stack. Walkers call it once the reference's children have been visited, so the stack only ever holds the path from the root to the value being processed.
§clear:() => voidEmpties the reference stack.
§interface

RegisteredIterableClassEntry

Registered iterable class with operators for traversal
Properties
§classRef:UnknownClass<T>A reference to a class definition.
§instantiate:() => TReturns a new (empty) instance.
§getKeys:(target: any) => string[]Returns list of iterable keys.
§read:(target: any, key: unknown) => unknownReturns a value corresponding to a key of class instance.
§write:(instance: T, value: unknown, key?: unknown) => voidSets a new value with specific key optionally on class instance.
§remove:(instance: T, key: unknown) => voidRemoves a key from the class instance.
§interface

SelectiveCopyOptions

Settings used to determine what to copy.
Properties
§skipFunctions?:booleanSet flag true to ignore all functions.
§includeKeys?:string[]A list of top-level properties that should be included.
§excludeKeys?:string[]A list of top-level properties that should be excluded.
§include?:SelectiveCopyPredicateA condition that is evaluated to determine if data point should be included.
§exclude?:SelectiveCopyPredicateA condition that is evaluated to determine if data point should be excluded.
§interface

SelectiveCopyResult

Result of selectiveCopy: the partial clone and any skipped data points.
Properties
§clone:Partial<T>Cloned value
§skipped:DataPoint[]Skipped data points
§interface

Target

Represents the target of a circular reference.
Properties
§path:string[]Path segments from root to the target
§interface

TraverseConfig

Internal traversal configuration
Properties
§depth:[number, number | "*"]Depth range with resolved max value
§exitEarly:booleanWhether to exit traversal early

◆Types

§type

Callback

Callback function invoked for each traversed node
type Callback = (key: string, value: unknown, path: string[], state: any, parent: unknown) => void
§type

Condition

Condition function to determine if a node should be processed
type Condition = (config: TraverseConfig, key: string, value: unknown, path: string[], parent: unknown) => boolean
§type

DataPointOperation

Operation function applied to each data point during traversal
type DataPointOperation = (target: unknown, path: string[], key: string, dataType: T) => void
§type

DataType

JavaScript data type names including 'null' and 'array'
type DataType = "undefined" | "object" | "boolean" | "number" | "bigint" | "string" | "symbol" | "function" | "null" | "array"
§type

Predicate

Function that tests if a value matches a condition
type Predicate = (x: unknown) => boolean
§type

SelectiveCopyPredicate

Predicate function to determine if a data point should be included/excluded
type SelectiveCopyPredicate = (target: unknown, path: string[], key: string, dataType: T) => boolean
§type

Traversal

Generic traversal function
type Traversal = (target: T, condition: Condition, callback: Callback, options: DepthConfig, state: any) => any
§type

TraversalArgs

Arguments tuple for traversal functions
type TraversalArgs = [Condition, Callback, TraverseConfig, string, string[], T, unknown, S]
§type

TraversalCircular

Traversal function for structures with circular references
type TraversalCircular = (condition: Condition, callback: Callback, config: TraverseConfig, key: string, path: string[], value: unknown, parent: unknown, state: any, stack: ReferenceStack, root?: boolean) => any
§type

TraversalCreator

Factory function that creates a traverse function with a fixed condition
type TraversalCreator = (condition: Condition) => Traverse<T>
§type

TraversalNonCircular

Traversal function for non-circular structures
type TraversalNonCircular = (condition: Condition, callback: Callback, config: TraverseConfig, key: string, path: string[], value: unknown, parent: unknown, state: S) => S
§type

Traverse

Function to traverse a target with callback and options
type Traverse = (target: T, callback: Callback, options?: DepthConfig, state?: any) => any
§type

UnknownClass

Constructor type for unknown class instances
type UnknownClass = (args: any[]) => T
§type

UnknownIterable

Any iterable of unknown values
type UnknownIterable = Iterable<unknown>
§type

UnknownIterableKey

String keys of UnknownIterable
type UnknownIterableKey = unknown & string

●Variables

§const

createTraversal

Type: TraversalCreator<unknown>
Value: ...
§const

registeredClasses

Type: UnknownClass[]
Value: []
§const

registeredIterableClasses

Value: ...

Browse guides filtered to this packageSuggest a guide