Giter VIP home page Giter VIP logo

unist-util-visit's Introduction

unist-util-visit

Build Coverage Downloads Size Sponsors Backers Chat

unist utility to walk the tree.

Contents

What is this?

This is a very important utility for working with unist as it lets you walk the tree.

When should I use this?

You can use this utility when you want to walk the tree. You can use unist-util-visit-parents if you care about the entire stack of parents.

Install

This package is ESM only. In Node.js (version 16+), install with npm:

npm install unist-util-visit

In Deno with esm.sh:

import {CONTINUE, EXIT, SKIP, visit} from 'https://esm.sh/unist-util-visit@5'

In browsers with esm.sh:

<script type="module">
  import {CONTINUE, EXIT, SKIP, visit} from 'https://esm.sh/unist-util-visit@5?bundle'
</script>

Use

import {fromMarkdown} from 'mdast-util-from-markdown'
import {visit} from 'unist-util-visit'

const tree = fromMarkdown('Some *emphasis*, **strong**, and `code`.')

visit(tree, 'text', function (node, index, parent) {
  console.log([node.value, parent ? parent.type : index])
})

Yields:

[ 'Some ', 'paragraph' ]
[ 'emphasis', 'emphasis' ]
[ ', ', 'paragraph' ]
[ 'strong', 'strong' ]
[ ', and ', 'paragraph' ]
[ '.', 'paragraph' ]

API

This package exports the identifiers CONTINUE, EXIT, SKIP, and visit. There is no default export.

visit(tree[, test], visitor[, reverse])

This function works exactly the same as unist-util-visit-parents, but Visitor has a different signature.

CONTINUE

Continue traversing as normal (true).

EXIT

Stop traversing immediately (false).

SKIP

Do not traverse this node’s children ('skip').

Action

Union of the action types (TypeScript type). See Action in unist-util-visit-parents.

ActionTuple

List with an action and an index (TypeScript type). See ActionTuple in unist-util-visit-parents.

BuildVisitor

Build a typed Visitor function from a tree and a test (TypeScript type). See BuildVisitor in unist-util-visit-parents.

Index

Move to the sibling at index next (TypeScript type). See Index in unist-util-visit-parents.

Test

unist-util-is compatible test (TypeScript type).

Visitor

Handle a node (matching test, if given) (TypeScript type).

Visitors are free to transform node. They can also transform parent.

Replacing node itself, if SKIP is not returned, still causes its descendants to be walked (which is a bug).

When adding or removing previous siblings of node (or next siblings, in case of reverse), the Visitor should return a new Index to specify the sibling to traverse after node is traversed. Adding or removing next siblings of node (or previous siblings, in case of reverse) is handled as expected without needing to return a new Index.

Removing the children property of parent still results in them being traversed.

Parameters
  • node (Node) — found node
  • index (number or undefined) — index of node in parent
  • parent (Node or undefined) — parent of node
Returns

What to do next.

An Index is treated as a tuple of [CONTINUE, Index]. An Action is treated as a tuple of [Action].

Passing a tuple back only makes sense if the Action is SKIP. When the Action is EXIT, that action can be returned. When the Action is CONTINUE, Index can be returned.

VisitorResult

Any value that can be returned from a visitor (TypeScript type). See VisitorResult in unist-util-visit-parents.

Types

This package is fully typed with TypeScript. It exports the additional types Action, ActionTuple, BuildVisitor, Index, Test, Visitor, and VisitorResult.

Compatibility

Projects maintained by the unified collective are compatible with maintained versions of Node.js.

When we cut a new major release, we drop support for unmaintained versions of Node. This means we try to keep the current release line, unist-util-visit@^5, compatible with Node.js 16.

Related

Contribute

See contributing.md in syntax-tree/.github for ways to get started. See support.md for ways to get help.

This project has a code of conduct. By interacting with this repository, organization, or community you agree to abide by its terms.

License

MIT © Titus Wormer

unist-util-visit's People

Contributors

alecmev avatar benatkin avatar christianmurphy avatar coderaiser avatar eush77 avatar gibson042 avatar greenkeeperio-bot avatar guiltydolphin avatar jangxyz avatar jlevy avatar murderlon avatar teinett avatar wooorm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

unist-util-visit's Issues

Can transformations be immutable?

Is it possible to modify nodes in an immutable way? eg,

// Redact all text nodes
node = visit(node, (child) => {
  if (child.type === 'text') {
    return { ...child, value: '[redacted]' }
  }
})

Causes tsc to stall indefinitely

Initial checklist

Affected packages and versions

4.1.0

Link to runnable example

No response

Steps to reproduce

clone https://github.com/cjroebuck/next-build-stalled

npm i
npx tsc

typescript version 4.5.2

(typescript version 4.4.3 does build ok)

Expected behavior

build shouldn't stall

Actual behavior

build stalls indefinitely

In order to get the build to pass, comment out this line

I suspect it's an issue with the unist-util-visit types?

Runtime

Node v16

Package manager

npm v7

OS

macOS

Build and bundle tools

Next.js

Is the API synchronous?

Is it safe to assume this is synchronous and will remain so? Might be helpful to add this in readme somewhere. 😄

e.g.

  var defs = []
  visit(ast, function (node, index, parent) {
    if (node.type === 'definition') {
      defs.push(node)
    }
  })
  console.log(defs)

NPM readme example still uses require()

Initial checklist

  • I read the support docs
  • I read the contributing guide
  • I agree to follow the code of conduct
  • I searched issues and couldn’t find anything (or linked relevant results below)

The example in the readme on main uses import, so it seems like just a new publish is needed.

Type doesn't work when using array of tests

Initial checklist

Affected packages and versions

[email protected]

Link to runnable example

https://codesandbox.io/s/react-markdown-debug-forked-sqvof

Steps to reproduce

  1. Open the codesandbox link
  2. Inspect the TypeScript error at line 25

Expected behavior

The visit method should be able to narrow the type of directiveVisitor and not throw an error.

Actual behavior

The visit method's type is not able narrow the type of directiveVisitor because it can't read the test ['textDirective', 'leafDirective', 'containerDirective']

Runtime

Node v14

Package manager

yarn v1

OS

macOS

Build and bundle tools

Next.js

Special character parsing

Hey, @wooorm 👋

I'm working on Gatsby plugin for extending code block functionality and it's using the below syntax:

```js:title=index.js&copy=true
console.log('Some code goes here...')
```

The problem I'm facing is that &copy gets encoded to ©. Is there any way to avoid it?

Note on mutation

This is a doc suggestion + a more general question.

It may be worth putting in the docs some thoughts on what the contract is wrt mutating the tree. In particular, modifying individual nodes is fine, but unist-util-visit assumes the visitor does not mutate the number of children of the parent.

This is a bit of a pitfall, as it's not uncommon to want to traverse and mutate adjacent children. For example, see https://github.com/jackycute/remark-html-emoji-image/blob/master/index.js#L66-L69 — but it appears that approach is buggy, since unist-util-visit visits children sequentially by index.

More generally, I'd be interested to know what approach is best to handle the fully mutating use case. https://github.com/syntax-tree/unist-util-map and https://github.com/eush77/unist-util-filter are listed but cover different use cases. One easy option (but may not be the best) is to make a visit-dynamic variant, something like:

'use strict';

module.exports = visit;

/**
 * A mutating version of https://github.com/syntax-tree/unist-util-visit
 *
 * Traverse a Unist tree, while also allowing addition/deletion of children.
 * Visitor should return number of nodes added/deleted (positive for addition, negative for removal,
 * 0 if only visited), or false to terminate. To avoid confusion, we don't support reverse traversal.
 */
function visit(tree, type, visitor) {
  if (typeof type === 'function') {
    visitor = type;
    type = null;
  }

  one(tree);

  /* Visit a single node. */
  function one(node, index, parent) {
    let result;

    index = index || (parent ? 0 : null);

    if (!type || node.type === type) {
      result = visitor(node, index, parent || null);
    }

    if (node.children && result !== false) {
      all(node);
    }

    return result;
  }

  /* Visit children in `parent`, possibly adding or removing children. */
  function all(parent) {
    let child;
    let index = 0;
    while (index < parent.children.length) {
      child = parent.children[index];

      let delta = 0;
      if (child) {
        delta = one(child, index, parent);
        if (delta === false) {  // Abort.
          return;
        }
      }

      index += 1 + (delta || 0);
    }
  }
}

Cannot find module 'unist-util-is/lib/index.js' or its corresponding type declarations

Initial checklist

Affected packages and versions

[email protected]

Link to runnable example

No response

Steps to reproduce

After upgrading from 4.1.1 to 4.1.2 I receive the errors below:

[email protected] build:esm
tsc

node_modules/unist-util-visit/lib/index.d.ts:32:24 - error TS2307: Cannot find module 'unist-util-is/lib/index.js' or its corresponding type declarations.

32 Check extends import('unist-util-is/lib/index.js').Test
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

node_modules/unist-util-visit/lib/index.d.ts:115:24 - error TS2307: Cannot find module 'unist-util-is/lib/index.js' or its corresponding type declarations.

115 Check extends import('unist-util-is/lib/index.js').Test
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

node_modules/unist-util-visit/lib/index.d.ts:132:24 - error TS2307: Cannot find module 'unist-util-is/lib/index.js' or its corresponding type declarations.

132 Check extends import('unist-util-is/lib/index.js').Test = string

Expected behavior

No type declaration errors.

Actual behavior

Receive type declaration errors.

Affected runtime and version

[email protected]

Affected package manager and version

[email protected]

Affected OS and version

macos

Build and bundle tools

No response

[Types]: type of parent should be Parent

Hi, currently the type for Visitor is

  type Visitor<V extends Node> = (
    node: V,
    index: number,
    parent: Node
  ) => void | Action | Index | ActionTuple

I think the parent parameter should be of type Parent, as the type Node does not have a children property.

Standalone documentation

Subject of the feature

I think it would be easier to get started with this if the README contained the docs about common things like returning an action instead of referring to unist-util-visit-parents.

Problem

It took me a little while to figure out that, like unist-util-visit-parents, this accepts returning an action (such as visit.SKIP).

Alternatives

Removing the details of how to call the function and just linking to unist-util-visit-parents might work.

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module

Initial checklist

  • I read the support docs
  • I read the contributing guide
  • I agree to follow the code of conduct
  • I searched issues and couldn’t find anything (or linked relevant results below)

Affected packages and versions: latest

Steps to reproduce

Install in Node 10 environment (I haven't tested on other node versions). Receive the following error:

Link to code example: https://github.com/googleapis/release-please/pull/870/checks?check_run_id=2390814891

Expected behavior

Library compiles.

I believe the goal is perhaps a dual-mode module (that would work for ESM and CJS?). This might just take some fiddling with extensions and export maps.

Here's what we landed on for yargs:

https://github.com/yargs/yargs/blob/master/package.json#L5

It's ugly but works on most Node versions.

Actual behavior

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/runner/work/release-please/release-please/node_modules/unist-util-visit/index.js
require() of ES modules is not supported.
require() of /home/runner/work/release-please/release-please/node_modules/unist-util-visit/index.js from /home/runner/work/release-please/release-please/build/src/util/to-conventional-changelog-format.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /home/runner/work/release-please/release-please/node_modules/unist-util-visit/package.json.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.