{"id":13339466,"url":"https://github.com/flex-development/unist-util-visit","last_synced_at":"2026-01-26T01:31:43.608Z","repository":{"id":228284093,"uuid":"773558630","full_name":"flex-development/unist-util-visit","owner":"flex-development","description":"utility to visit nodes","archived":false,"fork":false,"pushed_at":"2025-02-18T08:49:14.000Z","size":2467,"stargazers_count":3,"open_issues_count":14,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-13T11:25:36.400Z","etag":null,"topics":["syntax-tree","unist","unist-util","util","visit","walk"],"latest_commit_sha":null,"homepage":"https://github.com/flex-development/unist-util-visit","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flex-development.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/funding.yml","license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["flex-development"]}},"created_at":"2024-03-18T00:52:18.000Z","updated_at":"2025-07-26T17:29:28.000Z","dependencies_parsed_at":"2024-05-02T09:54:46.816Z","dependency_job_id":"9f2a5751-19a1-4d5b-ba6d-670a476e7704","html_url":"https://github.com/flex-development/unist-util-visit","commit_stats":null,"previous_names":["flex-development/unist-util-visit"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/flex-development/unist-util-visit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flex-development%2Funist-util-visit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flex-development%2Funist-util-visit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flex-development%2Funist-util-visit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flex-development%2Funist-util-visit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flex-development","download_url":"https://codeload.github.com/flex-development/unist-util-visit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flex-development%2Funist-util-visit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28763920,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-26T00:37:26.264Z","status":"ssl_error","status_checked_at":"2026-01-26T00:37:25.959Z","response_time":113,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["syntax-tree","unist","unist-util","util","visit","walk"],"created_at":"2024-07-29T19:20:03.645Z","updated_at":"2026-01-26T01:31:43.592Z","avatar_url":"https://github.com/flex-development.png","language":"TypeScript","readme":"# unist-util-visit\n\n[![github release](https://img.shields.io/github/v/release/flex-development/unist-util-visit.svg?include_prereleases\u0026sort=semver)](https://github.com/flex-development/unist-util-visit/releases/latest)\n[![npm](https://img.shields.io/npm/v/@flex-development/unist-util-visit.svg)](https://npmjs.com/package/@flex-development/unist-util-visit)\n[![codecov](https://codecov.io/gh/flex-development/unist-util-visit/graph/badge.svg?token=xHQmS2Z03w)](https://codecov.io/gh/flex-development/unist-util-visit)\n[![module type: esm](https://img.shields.io/badge/module%20type-esm-brightgreen)](https://github.com/voxpelli/badges-cjs-esm)\n[![license](https://img.shields.io/github/license/flex-development/unist-util-visit.svg)](LICENSE.md)\n[![conventional commits](https://img.shields.io/badge/-conventional%20commits-fe5196?logo=conventional-commits\u0026logoColor=ffffff)](https://conventionalcommits.org/)\n[![typescript](https://img.shields.io/badge/-typescript-3178c6?logo=typescript\u0026logoColor=ffffff)](https://typescriptlang.org/)\n[![vitest](https://img.shields.io/badge/-vitest-6e9f18?style=flat\u0026logo=vitest\u0026logoColor=ffffff)](https://vitest.dev/)\n[![yarn](https://img.shields.io/badge/-yarn-2c8ebb?style=flat\u0026logo=yarn\u0026logoColor=ffffff)](https://yarnpkg.com/)\n\n[unist][unist] utility to walk the tree\n\n## Contents\n\n- [What is this?](#what-is-this)\n- [When should I use this?](#when-should-i-use-this)\n- [Install](#install)\n- [Use](#use)\n- [API](#api)\n  - [`visit(tree[, test], visitor|visitors[, reverse])`](#visittree-test-visitorvisitors-reverse)\n  - [`CONTINUE`](#continue)\n  - [`EXIT`](#exit)\n  - [`SKIP`](#skip)\n  - [`Action`](#action)\n  - [`ActionTuple`](#actiontuple)\n  - [`Index`](#index)\n  - [`Test`](#test)\n  - [`TestFunction\u003c[T][, P]\u003e`](#testfunctiont-p)\n  - [`VisitedAncestor\u003c[Tree][, Check]\u003e`](#visitedancestortree-check)\n  - [`VisitedNode\u003c[Tree][, Check]\u003e`](#visitednodetree-check)\n  - [`VisitedParent\u003c[Tree][, Check]\u003e`](#visitedparenttree-check)\n  - [`Visitor\u003c[Tree][, Check]\u003e`](#visitortree-check)\n  - [`VisitorResult`](#visitorresult)\n  - [`Visitors\u003c[Tree][, Check]\u003e`](#visitorstree-check)\n- [Related](#related)\n- [Contribute](#contribute)\n\n## What is this?\n\nThis package is an essential utility for [unist][unist] that lets you walk the tree.\n\n## When should I use this?\n\nUse this utility when you want to walk the tree with ancestral information, or need to do a [*postorder*][postorder]\nwalk.\n\nYou can use [`unist-util-visit-parents`][unist-util-visit-parents] or [`syntax-tree/unist-util-visit`][unist-util-visit]\nif you only need to do a [*preorder*][preorder] traversal, or don't care about the entire stack of parents.\n\n## Install\n\nThis package is [ESM only][esm].\n\nIn Node.js (version 18+) with [yarn][yarn]:\n\n```sh\nyarn add @flex-development/unist-util-visit\nyarn add -D @types/unist\n```\n\n\u003cblockquote\u003e\n  \u003csmall\u003e\n    See \u003ca href='https://yarnpkg.com/protocol/git'\u003eGit - Protocols | Yarn\u003c/a\u003e\n    \u0026nbsp;for details regarding installing from Git.\n  \u003c/small\u003e\n\u003c/blockquote\u003e\n\nIn Deno with [`esm.sh`][esmsh]:\n\n```ts\nimport { CONTINUE, EXIT, SKIP, visit } from 'https://esm.sh/@flex-development/unist-util-visit'\n```\n\nIn browsers with [`esm.sh`][esmsh]:\n\n```html\n\u003cscript type=\"module\"\u003e\n  import { CONTINUE, EXIT, SKIP, visit } from 'https://esm.sh/@flex-development/unist-util-visit'\n\u003c/script\u003e\n```\n\n## Use\n\n```js\nimport { fromDocs } from '@flex-development/docast-util-from-docs'\nimport { visit } from '@flex-development/unist-util-visit'\nimport { directiveFromMarkdown } from 'mdast-util-directive'\nimport { directive } from 'micromark-extension-directive'\nimport { read } from 'to-vfile'\n\nconst file = await read('examples/docblock.mjs')\n\nconst tree = fromDocs(file, {\n  mdastExtensions: [directiveFromMarkdown()],\n  micromarkExtensions: [directive()]\n})\n\nvisit(tree, (node, index, parent, ancestors) =\u003e {\n  console.log(`\\u001B[1m${node.type}\\u001B[22m`)\n  console.log(`index: ${index}`)\n  console.log(`parent: ${parent?.type}`)\n  console.log(`ancestors: ${JSON.stringify(ancestors.map(anc =\u003e anc.type))}\\n`)\n})\n\n// enter and leave\nvisit(tree, {\n  enter(node, index, parent, ancestors) {/* … */},\n  leave(node, index, parent, ancestors) {/* … */}\n})\n```\n\nYields:\n\n```sh\nroot\nindex: undefined\nparent: undefined\nancestors: []\n\ncomment\nindex: 0\nparent: root\nancestors: []\n\ndescription\nindex: 0\nparent: comment\nancestors: [\"root\"]\n\nparagraph\nindex: 0\nparent: description\nancestors: [\"root\",\"comment\"]\n\ntext\nindex: 0\nparent: paragraph\nancestors: [\"root\",\"comment\",\"description\"]\n\nbreak\nindex: 1\nparent: description\nancestors: [\"root\",\"comment\"]\n\nbreak\nindex: 2\nparent: description\nancestors: [\"root\",\"comment\"]\n\ncontainerDirective\nindex: 3\nparent: description\nancestors: [\"root\",\"comment\"]\n\nparagraph\nindex: 0\nparent: containerDirective\nancestors: [\"root\",\"comment\",\"description\"]\n\ntext\nindex: 0\nparent: paragraph\nancestors: [\"root\",\"comment\",\"description\",\"containerDirective\"]\n\ninlineCode\nindex: 1\nparent: paragraph\nancestors: [\"root\",\"comment\",\"description\",\"containerDirective\"]\n\ntext\nindex: 2\nparent: paragraph\nancestors: [\"root\",\"comment\",\"description\",\"containerDirective\"]\n\ncode\nindex: 1\nparent: containerDirective\nancestors: [\"root\",\"comment\",\"description\"]\n\nblockTag\nindex: 1\nparent: comment\nancestors: [\"root\"]\n\ntypeExpression\nindex: 0\nparent: blockTag\nancestors: [\"root\",\"comment\"]\n```\n\n## API\n\nThis package exports the identifiers [`CONTINUE`](#continue), [`EXIT`](#exit), [`SKIP`](#skip), and\n[`visit`](#visittree-test-visitorvisitors-reverse). There is no default export.\n\n### `visit(tree[, test], visitor|visitors[, reverse])`\n\nVisit nodes, with ancestral information.\n\nThis algorithm performs [*depth-first tree traversal*][dft] in [*preorder*][preorder] (**NLR**) and/or\n[*postorder*][postorder] (**LRN**), or if `reverse` is given, *reverse preorder* (**NRL**) and/or *reverse postorder*\n(**RLN**). Nodes are handled on [*enter*][enter] during *preorder* traversals and on [*exit*][exit] during *postorder*\ntraversals.\n\nYou can choose which nodes visitor functions handle by passing a [`test`](#test). For complex tests, you should test\nyourself in `visitor` or `visitors` instead, as it will be faster and also have improved type information.\n\nWalking the `tree` is an intensive task. Make use of visitor return values whenever possible. Instead of walking the\n`tree` multiple times, walk it once, use [`unist-util-is`][unist-util-is] to check if a node matches, and then perform\ndifferent operations.\n\nYou can change `tree`. See [`Visitor`](#visitortree-check) for more info.\n\n#### Parameters\n\n- `tree` ([`Node`][node]) - [*tree*][tree] to traverse\n- `test` ([`Test`](#test), optional) - [`unist-util-is`][unist-util-is]-compatible test\n- `visitor` ([`Visitor`](#visitortree-check)) - handle a node on *enter*\n- `visitors` ([`Visitors`](#visitorstree-check)) - handle each node on *enter* and/or *exit*\n- `reverse` (`boolean`, optional) - traverse in reverse\n\n#### Return\n\nNothing (`void`).\n\n### `CONTINUE`\n\nContinue traversing as normal (`true`).\n\n```ts\nconst CONTINUE: Continue = true\n```\n\n### `EXIT`\n\nStop traversing immediately (`false`).\n\n```ts\nconst EXIT: Exit = false\n```\n\n### `SKIP`\n\nDo not traverse the [*children*][child] of this node (`'skip'`).\n\n```ts\nconst SKIP: Skip = 'skip'\n```\n\n### `Action`\n\nUnion of action types.\n\n```ts\ntype Action = Continue | Exit | Skip\n```\n\n### `ActionTuple`\n\nList with at most two (`2`) values, the first an [`Action`](#action) and the second an [`Index`](#index).\n\n```ts\ntype ActionTuple = [\n  action?: Action | null | undefined | void,\n  index?: Index | null | undefined\n]\n```\n\n### `Index`\n\nMove to the [*sibling*][sibling] at `index` next (after node itself is completely traversed).\n\nUseful if mutating the `tree`, such as when removing the node the [`Visitor`](#visitortree-check) is currently on, or\nany of its previous *siblings*.\n\nNegative indices (`\u003c 0`) and indices greater than or equal to `parent.children.length` stop traversal of the parent.\n\n```ts\ntype Index = number\n```\n\n### `Test`\n\nCheck for an arbitrary [`Node`][node].\n\nSee [`unist-util-is`][unist-util-is] for more details.\n\n```ts\ntype Test =\n  | (TestFunction | unist.Node | unist.Node['type'])[]\n  | TestFunction\n  | unist.Node\n  | unist.Node['type']\n  | null\n  | undefined\n```\n\n### `TestFunction\u003c[T][, P]\u003e`\n\nCheck if `node` passes a test.\n\n- `T` ([`Node`][node]): node to check\n  - **default**: [`Node`][node]\n- `P` ([`Parent`][parent]): [*parent*][parent] of node `T`\n  - **default**: [`Parent`][parent]\n\n#### Parameters\n\n- `node` (`T`): node to check\n- `index` ([`Index`](#index) | `undefined`): index of `node` in `parent.children`\n- `parent` ([`Parent`][parent] | `undefined`): [*parent*][parent] of `node`\n\n#### Return\n\nTest result (`boolean | undefined | void`).\n\n\u003e 👉 **Note**: For the best type-safety, test functions should return [type predicates][type-predicate] (`node is Type`).\n\n### `VisitedAncestor\u003c[Tree][, Check]\u003e`\n\nCollect [*ancestors*][ancestor] of visited nodes in [`Tree`][tree].\n\n- `Tree` ([`Node`][node]) - [*tree*][tree] to extract ancestors from\n  - **default**: [`Node`][node]\n- `Check` ([`Test`](#test)) - visited node test\n  - **default**: `null | undefined`\n\n```ts\nimport type * as docast from '@flex-development/docast'\nimport type { VisitedAncestor } from '@flex-development/unist-util-visit'\nimport type * as unist from 'unist'\n\ntype Tree = docast.Root\ntype Check = (value: unist.Node) =\u003e value is docast.TypeExpression\n\ntype Visited = VisitedAncestor\u003cTree, Check\u003e // docast.BlockTag | docast.Comment | docast.Root\n```\n\n### `VisitedNode\u003c[Tree][, Check]\u003e`\n\nCollect visited nodes in [`Tree`][tree].\n\n- `Tree` ([`Node`][node]) - [*tree*][tree] to traverse\n  - **default**: [`Node`][node]\n- `Check` ([`Test`](#test)) - visited node test\n  - **default**: `null | undefined`\n\n```ts\nimport type * as docast from '@flex-development/docast'\nimport type { VisitedNode } from '@flex-development/unist-util-visit'\n\ntype Tree = docast.Root\n\ntype Visited = VisitedNode\u003cTree\u003e\n// | docast.Root\n// | docast.Comment\n// | docast.BlockTag\n// | docast.Description\n// | docast.InlineTag\n// | docast.TypeExpression\n// | mdast.Blockquote\n// | mdast.Code\n// | mdast.Definition\n// | mdast.FootnoteDefinition\n// | mdast.Heading\n// | mdast.List\n// | mdast.ListItem\n// | mdast.Paragraph\n// | mdast.PhrasingContent\n// | mdast.Table\n// | mdast.TableCell\n// | mdast.TableRow\n// | mdast.ThematicBreak\n```\n\n### `VisitedParent\u003c[Tree][, Check]\u003e`\n\nCollect [*parents*][parent] of visited nodes in [`Tree`][tree].\n\n- `Tree` ([`Node`][node]) - [*tree*][tree] to extract parents from\n  - **default**: [`Node`][node]\n- `Check` ([`Test`](#test)) - visited node test\n  - **default**: `null | undefined`\n\n```ts\nimport type * as docast from '@flex-development/docast'\nimport type { VisitedNode } from '@flex-development/unist-util-visit'\n\ntype Tree = docast.Root\ntype Check = docast.TypeExpression['type']\n\ntype Visited = VisitedNode\u003cTree, Check\u003e // docast.BlockTag\n```\n\n### `Visitor\u003c[Tree][, Check]\u003e`\n\nHandle a `node`.\n\nVisitors are free to transform `node`. They can also transform `parent`, or the grandparent of `node` (the last of\n`ancestors`).\n\n\u003e 👉 **Note**: Replacing `node` itself, if [`SKIP`](#skip) is not returned, still causes its [*descendants*][descendant]\n\u003e to be walked (which is a bug).\n\nWhen adding or removing previous [*siblings*][sibling] of `node`, the `Visitor` should return a new [`Index`](#index) to\nspecify the *sibling* to traverse after `node` is traversed. Adding or removing next *siblings* of `node` is handled as\nexpected without needing to return a new `Index`.\n\nRemoving the [*children*][child] of an [*ancestor*][ancestor] still results in those *child* nodes being traversed.\n\n- `Tree` ([`Node`][node]) - [*tree*][tree] to traverse\n  - **default**: [`Node`][node]\n- `Check` ([`Test`](#test)) - visited node test\n  - **default**: `null | undefined`\n\n#### Parameters\n\n- `node` ([`VisitedNode\u003cTree, Check\u003e`](#visitednodetree-check)) - found node\n- `index` ([`Index`](#index) | `undefined`) - index of `node` in `parent.children`\n- `parent` ([`VisitedParent\u003cTree, Check\u003e`](#visitedparenttree-check) | `undefined`) - [*parent*][parent] of `node`\n- `ancestors` ([`VisitedAncestor\u003cTree, Check\u003e[]`](#visitedancestortree-check)) - [*ancestors*][ancestor] of `node`, if\n  any, where the last node is the grandparent of `node`\n\n#### Return\n\nWhat to do next ([`VisitorResult`](#visitorresult)).\n\n### `VisitorResult`\n\nUnion of values that can be returned from a [`Visitor`](#visitortree-check).\n\nAn [`Index`](#index) is treated as a tuple of `[CONTINUE, Index]`. An [`Action`](#action) is treated as a tuple of\n`[Action]`.\n\nReturning a tuple only makes sense if the `Action` is [`SKIP`](#skip). When the `Action` is [`EXIT`](#exit), that action\ncan be returned. When the `Action` is [`CONTINUE`](#continue), `Index` can be returned.\n\n```ts\ntype VisitorResult = Action | ActionTuple | Index | null | undefined | void\n```\n\n### `Visitors\u003c[Tree][, Check]\u003e`\n\nHandle nodes when entering ([*preorder*][preorder]) and/or leaving ([*postorder*][postorder]).\n\n- `Tree` ([`Node`][node]) - [*tree*][tree] to traverse\n  - **default**: [`Node`][node]\n- `Check` ([`Test`](#test)) - visited node test\n  - **default**: `null | undefined`\n\n#### Fields\n\n- `enter` ([`Visitor\u003cTree, Check\u003e`](#visitortree-check), optional) - handle nodes when [*entering*][enter] (*preorder*)\n- `leave` ([`Visitor\u003cTree, Check\u003e`](#visitortree-check), optional) - handle nodes when [*exiting*][exit] (*postorder*)\n\n## Related\n\n- [`unist-util-filter`][unist-util-filter] \u0026mdash; create a new tree with all nodes that pass a test\n- [`unist-util-flatmap`][unist-util-flatmap] \u0026mdash; create a new tree by mapping (to an array) with the given function\n- [`unist-util-generated`][unist-util-generated] \u0026mdash; check if a node is generated\n- [`unist-util-is`][unist-util-is] \u0026mdash; check if a node passes a test\n- [`unist-util-map`][unist-util-map] \u0026mdash; create a new tree with all nodes mapped by a given function\n- [`unist-util-remove`][unist-util-remove] \u0026mdash; remove nodes from a tree that pass a test\n- [`unist-util-select`][unist-util-filter] \u0026mdash; select nodes with CSS-like selectors\n- [`unist-util-visit-parents`][unist-util-visit-parents] \u0026mdash; recursively walk over nodes, with a stack of parents\n\n## Contribute\n\nSee [`CONTRIBUTING.md`](CONTRIBUTING.md).\n\nThis project has a [code of conduct](CODE_OF_CONDUCT.md). By interacting with this repository, organization, or\ncommunity you agree to abide by its terms.\n\n[ancestor]: https://github.com/syntax-tree/unist#ancestor\n[child]: https://github.com/syntax-tree/unist#child\n[dft]: https://github.com/syntax-tree/unist#depth-first-traversal\n[descendant]: https://github.com/syntax-tree/unist#descendant\n[enter]: https://github.com/syntax-tree/unist#enter\n[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c\n[esmsh]: https://esm.sh/\n[exit]: https://github.com/syntax-tree/unist#exit\n[node]: https://github.com/syntax-tree/unist#node\n[parent]: https://github.com/syntax-tree/unist#parent-1\n[postorder]: https://github.com/syntax-tree/unist#postorder\n[preorder]: https://github.com/syntax-tree/unist#preorder\n[sibling]: https://github.com/syntax-tree/unist#sibling\n[tree]: https://github.com/syntax-tree/unist#tree\n[type-predicate]: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates\n[unist-util-filter]: https://github.com/syntax-tree/unist-util-filter\n[unist-util-flatmap]: https://github.com/syntax-tree/unist-util-flatmap\n[unist-util-generated]: https://github.com/syntax-tree/unist-util-generated\n[unist-util-is]: https://github.com/syntax-tree/unist-util-is\n[unist-util-map]: https://github.com/syntax-tree/unist-util-map\n[unist-util-remove]: https://github.com/syntax-tree/unist-util-remove\n[unist-util-visit-parents]: https://github.com/syntax-tree/unist-util-visit-parents\n[unist-util-visit]: https://github.com/syntax-tree/unist-util-visit\n[unist]: https://github.com/syntax-tree/unist\n[yarn]: https://yarnpkg.com\n","funding_links":["https://github.com/sponsors/flex-development"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflex-development%2Funist-util-visit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflex-development%2Funist-util-visit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflex-development%2Funist-util-visit/lists"}