-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into feat/cloneDeep
- Loading branch information
Showing
142 changed files
with
1,773 additions
and
98 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,8 @@ jobs: | |
PR_TITLE: '${{ github.event.pull_request.title }}' | ||
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 | ||
- uses: pnpm/action-setup@v4 | ||
- uses: actions/setup-node@v4 | ||
with: | ||
|
@@ -43,6 +45,8 @@ jobs: | |
run: echo "$PR_TITLE" | pnpm -s dlx [email protected] | ||
- name: Refresh Bundle Impact | ||
uses: actions/github-script@v6 | ||
env: | ||
TARGET_BRANCH: ${{ github.event.pull_request.base.ref }} | ||
with: | ||
github-token: ${{ secrets.GITHUB_TOKEN }} | ||
script: | | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import * as _ from 'radashi' | ||
import { bench } from 'vitest' | ||
|
||
describe('traverse', () => { | ||
const root = { | ||
a: { b: { c: { d: { e: 1 } } } }, | ||
} | ||
bench('basic traversal', () => { | ||
_.traverse(root, () => {}) | ||
}) | ||
}) |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,244 @@ | ||
--- | ||
title: traverse | ||
description: Deeply enumerate an object and any nested objects | ||
--- | ||
|
||
### Usage | ||
|
||
Recursively visit each property of an object (or each element of an array) and its nested objects or arrays. To traverse non-array iterables (e.g. `Map`, `Set`) and class instances, see the [Traversing other objects](#traversing-other-objects) section. | ||
|
||
Traversal is performed in a depth-first manner. That means the deepest object will be visited before the last property of the root object. | ||
|
||
```ts | ||
import * as _ from 'radashi' | ||
|
||
const root = { a: { b: 2 }, c: [1, 2] } | ||
|
||
_.traverse(root, (value, key, parent, context) => { | ||
const depth = context.parents.length | ||
console.log(' '.repeat(depth * 2), key, '=>', value) | ||
}) | ||
// Logs the following: | ||
// a => { b: 2 } | ||
// b => 2 | ||
// c => [1, 2] | ||
// 0 => 1 | ||
// 1 => 2 | ||
``` | ||
|
||
**Tip:** Check out the [Advanced](#advanced) section to see what else is possible. | ||
|
||
:::tip[Did you know?] | ||
|
||
- Sparse arrays don't have their holes visited. | ||
- Circular references are skipped. | ||
|
||
::: | ||
|
||
## Types | ||
|
||
### TraverseVisitor | ||
|
||
The `TraverseVisitor` type represents the function passed to `traverse` as its 2nd argument. If you ever need to declare a visitor separate from a `traverse` call, you can do so by declaring a function with this type signature. | ||
|
||
```ts | ||
import { TraverseVisitor } from 'radashi' | ||
|
||
const visitor: TraverseVisitor = (value, key, parent, context) => { | ||
// ... | ||
} | ||
``` | ||
|
||
### TraverseContext | ||
|
||
Every visit includes a context object typed with `TraverseContext`, which contains the following properties: | ||
|
||
- `key`: The current key being visited. | ||
- `parent`: The parent object of the current value. | ||
- `parents`: An array of objects (from parent to child) that the current value is contained by. | ||
- `path`: An array describing the key path to the current value from the root. | ||
- `skip`: A function used for skipping traversal of an object. If no object is provided, the current value is skipped. See [Skipping objects](#skipping-objects) for more details. | ||
- `skipped`: A set of objects that have been skipped. | ||
- `value`: The current value being visited. | ||
|
||
:::danger | ||
|
||
The `path` and `parents` arrays are mutated by the `traverse` function. If you need to use them after the current visit, you should make a copy. | ||
|
||
::: | ||
|
||
### TraverseOptions | ||
|
||
You may set these options for `traverse` using an object as its 3rd argument. | ||
|
||
- `ownKeys`: A function that returns the own enumerable property names of an object. | ||
- `rootNeedsVisit`: A boolean indicating whether the root object should be visited. | ||
|
||
See the [Options](#options) section for more details. | ||
|
||
## Options | ||
|
||
### Traversing all properties | ||
|
||
By default, non-enumerable properties and symbol properties are skipped. You can pass in a custom `ownKeys` implementation to control which object properties are visited. | ||
|
||
This example shows how `Reflect.ownKeys` can be used to include non-enumerable properties and symbol properties. Note that symbol properties are always traversed last when using `Reflect.ownKeys`. | ||
|
||
```ts | ||
import * as _ from 'radashi' | ||
|
||
const symbol = Symbol('b') | ||
const root = { [symbol]: 1 } | ||
Object.defineProperty(root, 'a', { value: 2, enumerable: false }) | ||
|
||
_.traverse( | ||
root, | ||
(value, key) => { | ||
console.log(key, '=>', value) | ||
}, | ||
{ ownKeys: Reflect.ownKeys }, | ||
) | ||
// Logs the following: | ||
// a => 2 | ||
// Symbol(b) => 1 | ||
``` | ||
|
||
### Visiting the root object | ||
|
||
By default, your `visitor` callback will never receive the object passed into `traverse`. To override this behavior, set the `rootNeedsVisit` option to true. | ||
|
||
When the root object is visited, the `key` will be `null`. | ||
|
||
```ts | ||
import * as _ from 'radashi' | ||
|
||
const root = { a: 1 } | ||
|
||
_.traverse( | ||
root, | ||
(value, key) => { | ||
console.log(key, '=>', value) | ||
}, | ||
{ rootNeedsVisit: true }, | ||
) | ||
// Logs the following: | ||
// null => { a: 1 } | ||
// a => 1 | ||
``` | ||
|
||
## Advanced | ||
|
||
### Traversing other objects | ||
|
||
If traversing plain objects and arrays isn't enough, try calling `traverse` from within another `traverse` callback like follows. This takes advantage of the fact that the root object is always traversed. | ||
|
||
```ts | ||
import * as _ from 'radashi' | ||
|
||
// Note how we're using a named visitor function so it can reference itself. | ||
_.traverse(root, function visitor(value, key, parent, context, options) { | ||
if (value instanceof MyClass) { | ||
return _.traverse(value, visitor, options, context) | ||
} | ||
// TODO: Handle other values as needed. | ||
}) | ||
``` | ||
|
||
If you didn't set any options, the `options` argument can be null: | ||
|
||
```ts | ||
return _.traverse(root, visitor, null, context) | ||
``` | ||
|
||
### Skipping objects | ||
|
||
Using the `TraverseContext::skip` method, you can prevent an object from being traversed. By calling `skip()` with no arguments, the current value won't be traversed. | ||
|
||
```ts | ||
import * as _ from 'radashi' | ||
|
||
const root = { | ||
a: { b: 1 }, | ||
c: { d: 2 }, | ||
} | ||
|
||
_.traverse(root, (value, key, parent, context) => { | ||
console.log(key, '=>', value) | ||
|
||
// Skip traversal of the 'a' object. | ||
if (key === 'a') { | ||
context.skip() | ||
} | ||
}) | ||
// Logs the following: | ||
// a => { b: 1 } | ||
// c => { d: 2 } | ||
// d => 2 | ||
``` | ||
|
||
You can pass any object to `skip()` to skip traversal of that object. | ||
|
||
```ts | ||
import * as _ from 'radashi' | ||
|
||
const root = { | ||
a: { | ||
b: { | ||
c: 1, | ||
}, | ||
}, | ||
} | ||
|
||
_.traverse(root, (value, key, parent, context) => { | ||
console.log(key, '=>', value) | ||
|
||
// Visit the properties of the current object, but skip any objects nested within. | ||
Object.values(value).forEach(nestedValue => { | ||
if (_.isObject(nestedValue)) { | ||
context.skip(nestedValue) | ||
} | ||
}) | ||
}) | ||
// Logs the following: | ||
// a => { b: { c: 1 } } | ||
// b => { c: 1 } | ||
``` | ||
|
||
### Exiting early | ||
|
||
If your `visitor` callback returns false, `traverse` will exit early and also return false. This is useful if you found what you wanted, so you don't need to traverse the rest of the objects. | ||
|
||
```ts | ||
let found = null | ||
_.traverse(root, value => { | ||
if (isWhatImLookingFor(value)) { | ||
found = value | ||
return false | ||
} | ||
}) | ||
``` | ||
|
||
### Leave callbacks | ||
|
||
If your `visitor` callback returns a function, it will be called once `traverse` has visited every visitable property/element within the current object. This is known as a “leave callback”. | ||
|
||
Your leave callback can return false to exit traversal early. | ||
|
||
```ts | ||
_.traverse({ arr: ['a', 'b'] }, (value, key) => { | ||
if (isArray(value)) { | ||
console.log('start of array') | ||
return () => { | ||
console.log('end of array') | ||
return false | ||
} | ||
} else { | ||
console.log(key, '=>', value) | ||
} | ||
}) | ||
// Logs the following: | ||
// start of array | ||
// 0 => 'a' | ||
// 1 => 'b' | ||
// end of array | ||
``` |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.