Skip to content

Commit

Permalink
feat(traverse): visitor can return a leave callback
Browse files Browse the repository at this point in the history
  • Loading branch information
aleclarson committed Jul 3, 2024
1 parent 94bb8fe commit 592d088
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 10 deletions.
53 changes: 53 additions & 0 deletions src/object/cloneDeep.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { traverse, TraverseContext } from 'radashi'

export function cloneDeep<T extends object>(
root: T,
map: (obj: object, context: TraverseContext) => object,
filter: (obj: object, context: TraverseContext) => boolean = () => true,
): T {
const out = map(root)
traverse(root, (value, key, parent, context) => {
if (value && typeof value === 'object') {
}
})
}

const complexTypes = [
Map,
Set,
Date,
RegExp,
Error,
WeakMap,
WeakSet,
ArrayBuffer,
SharedArrayBuffer,
DataView,
Int8Array,
Uint8Array,
Uint8ClampedArray,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float32Array,
Float64Array,
BigInt64Array,
BigUint64Array,
Promise,
// Boxed primitive types
String,
Number,
Boolean,
]

function isInstance(
obj: object,
constructors: (new (...args: any[]) => any)[],
) {
return constructors.some(constructor => obj instanceof constructor)
}

function isComplexObject(obj: object) {
return isInstance(obj, complexTypes)
}
24 changes: 14 additions & 10 deletions src/object/traverse.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isArray, isIterable, isPlainObject, last } from 'radashi'
import { isArray, isFunction, isIterable, isPlainObject, last } from 'radashi'

/**
* Iterate an object's properties and those of any nested objects.
Expand Down Expand Up @@ -66,14 +66,14 @@ export function traverse(
}

context.path.push(key)
if (
visitor(
(context.value = value),
(context.key = key),
context.parent,
context,
) === false
) {
const result = visitor(
(context.value = value),
(context.key = key),
context.parent,
context,
)

if (result === false) {
return (ok = false)
}

Expand All @@ -87,6 +87,10 @@ export function traverse(
!context.parents.includes(value)
) {
traverse(value)

if (isFunction(result)) {
result()
}
}

context.path.pop()
Expand Down Expand Up @@ -147,7 +151,7 @@ export type TraverseVisitor = (
key: keyof any,
parent: object,
context: TraverseContext,
) => boolean | void
) => (() => void) | boolean | void

/**
* The context object for the `traverse` function.
Expand Down
16 changes: 16 additions & 0 deletions tests/object/traverse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,4 +301,20 @@ describe('traverse', () => {
expect(paths).toEqual([['a'], ['a', 'b']])
expect(parents).toEqual([[obj], [obj, obj.a]])
})

test('visitor can return a leave callback', () => {
const obj = { a: { b: 2 } }
const visited: [keyof any, unknown][] = []
_.traverse(obj, (value, key) => {
visited.push([key, value])
return () => {
visited.push([key, value])
}
})
expect(visited).toEqual([
['a', { b: 2 }],
['b', 2],
['a', { b: 2 }],
])
})
})

0 comments on commit 592d088

Please sign in to comment.