{"id":12305,"library":"unist-util-visit-parents","title":"Unist Utility for Ancestral Node Traversal","description":"unist-util-visit-parents is a robust utility within the unist (Universal Syntax Tree) ecosystem designed for deeply traversing ASTs (Abstract Syntax Trees) while providing a full lineage of parent nodes for each visited node. This functionality is crucial for transformations or analyses that require contextual information about a node's position within the tree. The current stable version is 6.0.2, with active development evidenced by frequent minor and major releases, particularly focusing on TypeScript type improvements and ESM compatibility. It differentiates itself from `unist-util-visit` by offering an array of parent nodes, making it indispensable for scenarios where ancestral context is necessary, such as scope analysis or complex rewrite operations. The library is ESM-only and requires Node.js 16 or higher, adhering to modern JavaScript module standards.","status":"active","version":"6.0.2","language":"javascript","source_language":"en","source_url":"https://github.com/syntax-tree/unist-util-visit-parents","tags":["javascript","unist","unist-util","util","utility","tree","ast","visit","traverse","typescript"],"install":[{"cmd":"npm install unist-util-visit-parents","lang":"bash","label":"npm"},{"cmd":"yarn add unist-util-visit-parents","lang":"bash","label":"yarn"},{"cmd":"pnpm add unist-util-visit-parents","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The package is ESM-only since v6.0.0 and must be imported using ES modules syntax. CommonJS `require` will result in an `ERR_REQUIRE_ESM` error.","wrong":"const visitParents = require('unist-util-visit-parents').visitParents","symbol":"visitParents","correct":"import { visitParents } from 'unist-util-visit-parents'"},{"note":"`CONTINUE`, `EXIT`, and `SKIP` are named exports representing specific actions for visitor functions. `Action` is a TypeScript type, not a runtime value.","wrong":"import { Action } from 'unist-util-visit-parents'","symbol":"CONTINUE","correct":"import { CONTINUE } from 'unist-util-visit-parents'"},{"note":"When importing types like `Visitor`, `Action`, or `Test`, use `import type` to clearly distinguish them from runtime values and avoid bundling issues.","wrong":"import { Visitor } from 'unist-util-visit-parents'","symbol":"Visitor","correct":"import type { Visitor } from 'unist-util-visit-parents'"}],"quickstart":{"code":"import { visitParents, SKIP } from 'unist-util-visit-parents';\nimport { fromMarkdown } from 'mdast-util-from-markdown';\nimport type { Root, Paragraph, Strong, PhrasingContent } from 'mdast';\n\nconst markdownInput = 'This is a *test* with **strong** emphasis and `code` blocks.';\nconst tree: Root = fromMarkdown(markdownInput);\n\nconsole.log('Original Tree:');\nconsole.log(JSON.stringify(tree, null, 2));\n\n// Example 1: Log all nodes and their direct parent types\nvisitParents(tree, (node, ancestors) => {\n  const parentTypes = ancestors.length > 0 ? ancestors.map(p => p.type).join(' > ') : 'Root';\n  console.log(`- Node Type: ${node.type}, Parents: ${parentTypes}`);\n});\n\n// Example 2: Skip children of 'strong' nodes and modify content\nvisitParents<Strong>(tree, 'strong', (node, ancestors) => {\n  console.log(`\\nVisiting strong node: ${node.value || ''}`);\n  if (node.children && node.children.length > 0 && node.children[0].type === 'text') {\n    node.children[0].value = (node.children[0].value || '') + ' (MODIFIED)';\n    console.log(`  Modified strong text. Skipping its children for further traversal.`);\n  }\n  return SKIP; // Do not traverse children of this 'strong' node\n});\n\nconsole.log('\\nModified Tree (strong nodes updated and their children skipped):');\nconsole.log(JSON.stringify(tree, null, 2));\n\n// Example 3: Find a specific node type and its ancestors, then exit\nlet foundCode = false;\nvisitParents<PhrasingContent>(tree, 'inlineCode', (node, ancestors) => {\n  console.log(`\\nFound inlineCode: ${node.value}`);\n  console.log('  Ancestors:', ancestors.map(a => a.type));\n  foundCode = true;\n  return true; // Use true (CONTINUE) or EXIT to stop, depending on requirement\n});\n\nif (!foundCode) {\n  console.log('\\nNo inlineCode nodes found.');\n}","lang":"typescript","description":"Demonstrates how to use `visitParents` to traverse a Markdown AST, log node types with ancestral paths, modify nodes, and control traversal flow using `SKIP`."},"warnings":[{"fix":"Migrate your project to use ES modules (`import`/`export`) or ensure your build tools correctly transpile if targeting older environments. Update your Node.js runtime to version 16 or newer. Do not use `require()` for this package.","message":"Version 6.0.0 changed the package to be ESM-only, removing CommonJS support. It also updated the required Node.js version to 16 or higher.","severity":"breaking","affected_versions":">=6.0.0"},{"fix":"Ensure your tooling supports `exports` maps. Always import symbols directly from the main package entrypoint (`unist-util-visit-parents`) rather than relying on private or deep paths.","message":"With version 6.0.0, the package now uses an `exports` map in `package.json`. This may affect how the package is resolved in older bundlers or Node.js environments that do not fully support `exports` maps, or if you were relying on undocumented deep imports.","severity":"breaking","affected_versions":">=6.0.0"},{"fix":"Update your TypeScript imports to use types directly from the main `unist-util-visit-parents` export. TypeScript's inference capabilities have also improved, often making explicit type imports less necessary for visitor arguments.","message":"Version 6.0.0 removed the `complex-types.d.ts` file, consolidating types into the main export. TypeScript projects relying on this specific file for type imports will break.","severity":"breaking","affected_versions":">=6.0.0"},{"fix":"Review your `visitor` function signatures. TypeScript should now correctly infer types, but you might need to adjust explicit type annotations to align with the new base typing logic. Consider using type parameters with `visitParents<SpecificNodeType>(...)` for better type inference.","message":"Version 5.0.0 introduced a breaking change to TypeScript types, specifically how the `visitor` function's arguments are typed, basing them on the `tree` type. This might cause type errors in existing TypeScript projects.","severity":"breaking","affected_versions":">=5.0.0 <6.0.0"},{"fix":"Carefully consider the implications of traversal order for your specific task. Preorder is generally suitable for most transformations; `reverse` is for specific cases where children need to be processed before their parents, but still in a depth-first manner.","message":"The `reverse` option (the fourth argument to `visitParents`) changes the traversal order from preorder (NLR) to reverse preorder (NRL). Using this incorrectly can lead to unexpected processing order for nodes.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Structure your visitors to handle multiple conditions within a single traversal loop. For example: `visitParents(tree, (node, parents) => { if (is(node, 'paragraph')) { ... } if (is(node, 'strong')) { ... } })`","message":"This utility is a high-level abstraction for AST traversal. For optimal performance in complex scenarios, avoid walking the tree multiple times. Instead, perform a single walk and use `unist-util-is` inside your visitor function to test for different node types and apply multiple operations.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Change `const { visitParents } = require('unist-util-visit-parents');` to `import { visitParents } from 'unist-util-visit-parents';` and ensure your environment supports ES modules (e.g., Node.js 16+ or a bundler).","cause":"Attempting to `require()` an ESM-only package like `unist-util-visit-parents`.","error":"ERR_REQUIRE_ESM"},{"fix":"Ensure you are running Node.js 16 or newer. If using a bundler (e.g., Webpack, Rollup), update it to a version that fully supports ESM and `exports` maps. Verify your `tsconfig.json` (if applicable) is configured for a modern module system (e.g., `\"module\": \"Node16\"` or `\"ES2022\"`).","cause":"This error often occurs in older Node.js versions or build environments when an ESM-only package (like `unist-util-visit-parents@6`) is incorrectly treated as a CommonJS module, particularly when there's an `exports` map involved.","error":"TypeError: Cannot read properties of undefined (reading 'exports')"},{"fix":"Confirm your import statement is `import { visitParents } from 'unist-util-visit-parents';`. If you're in a CommonJS context, you cannot use this package directly; you must transition to ESM or use an older version if available (though not recommended).","cause":"This usually indicates that the import failed to correctly resolve `visitParents`. This can happen if you're using CommonJS `require()` or if there's a mismatch between how the module is exported and imported (e.g., trying to import a default export when only named exports exist).","error":"TypeError: visitParents is not a function"},{"fix":"Ensure you are using a compatible version of `@types/unist` for your unist package. For specific node types, use type parameters with `visitParents<SpecificNodeType>(tree, 'type', visitor)` or `is()` from `unist-util-is` for more robust type checking within the visitor. Update `@types/unist` if needed, as `unist-util-visit-parents` v6.0.0 updated its dependency.","cause":"TypeScript error related to the `test` argument of `visitParents` or the `visitor` function's node types not matching the expected `Node` interface or a more specific unist node type.","error":"Argument of type '...' is not assignable to parameter of type 'Test'."}],"ecosystem":"npm"}