Giter VIP home page Giter VIP logo

estraverse's People

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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

estraverse's Issues

Add `enter` callback as a second .traverse arg

I suggest making the .traverse method more polymorphic.

is it cool to write:

traverse.traverse(ast, node => isBemjson(node) && bemjsons.push(this.nodeToObject(node)));

insted of:

traverse.traverse(ast, {
    enter: node => isBemjson(node) && bemjsons.push(this.nodeToObject(node))
});

Allow non-standard nodes?

Would you be open to make estraverse to support non-standard nodes?

I'm trying to use estraverse.replace in js2coffee to mangle the JS AST into a CoffeeScript AST. This involves things such as, say, rewriting an undefined to be surrounded by backticks. This means replacing { type: 'Identifier', name: 'undefined' } with a custom CoffeeScript node, such as { type: 'CoffeeEscapedExpression', argument: 'undefined' }.

This makes estraverse choke in these lines:

Controller.prototype.traverse = function traverse() {
...
   candidates = VisitorKeys[nodeType];
   current = candidates.length; /* <--- */

It would be nice to:

  • Allow estraverse to have its VisitorKeys list customizable, and/or
  • Make estraverse ignore nodes it doesn't know about.

What do you think?

`attachComments` doesn't attach comments found in function signature

Code:

var x = function (/* signature comment */) {
    return 'foo' + 'bar';
};
/* raz */
x(function (other) { return other });

Handling:

var ast = esprima.parse(code, { comment: true, range: true, tokens: true });
console.log(ast.comments.length); // 2, both comments are referenced
ast = escodegen.attachComments(ast, ast.comments, ast.tokens);
console.log(escodegen.generate(ast, { comment: true });

Result:

var x = function (foo) {
    return 'foo' + 'raz'
};
/* raz */
x(function (other) {
    return other
})

We miss comment in function signature

Is estraverse.Controller API?

I use estraverse.traverse in oj to iterate over the esprima AST. I'd like to use estraverse.Controller directly, so I can use Controller#path and Controller#parents.

In estraverse.js, these methods are commented as API. However, no documentation or usage information exists in the README or wiki.

Just to make sure: Controller is intended to be API, right?

estraverse.attachComments attaches root comment to wrong node

Consider the following snippet:

/**
 * 
 */
function f1(o1, o2, o3) {
    return; 
};

If you call estraverse.attachComments on the AST for it, the block comment is attached to the 'Program' node and not the 'FunctionDeclaration' node as you would expect.

I'm assuming this is due to the fact that the 'Program' and 'FunctionDeclaration' start range is the same.

Block statement traversal inside variable declaration issue

I saw this issue working inside eslint and it did not emit event for BlockStatement for the following code:

Code:

var a = function() {
        a++;
        b++;
        c++;
    },
    b;

I listen for 2 nodes VariableDeclaration and BlockStatement.
My function gets called for VariableDeclaration but never get called for BlockStatement.
I expect that to happen.

Is this an known issue or my expectations are wrong.

UPDATE

If I stop listening for VariableDeclaration then its works fine and the function gets called for BlockStatement.

remove doesn't work for `expression` properties

Hi,

It seems like using this.remove on an expression which is itself set as expression property of it's parent throws an error "Cannot read property 'type' of undefined". In this case, the parent should be removed with the child.

estraverse::map

Hey,
what about map method based on traverse method?

now i have to write in none FP style:

const retrieveBemEntities = (fileContent) => {
    var bemjsons = [];
    return new Promise(function(res, err) {
        const ast = parse.parse(fileContent);
        traverse.traverse(ast, {
            enter: node => isObject(node) && isBemjson(node) && bemjsons.push(nodeToObject(node)),
            onEnd: () => res(bemjsons)
        });
    })
}

'll be cool write like this:

/**
 * @returns {Promise<BEMJSON[]>}
 */
const retrieveBemEntities = (fileContent) =>
    traverse.map(parse.parse(fileContent),
        node => isObject(node) && isBemjson(node) && nodeToObject(node));

How to make an accompanying sourcemap for transform?

I posted a question on SO, but then thought I might also ask here.

Does estraverse support making a source map? Something like estraverse.replace(ast, transform, sourceMap) would be awesome. Maybe in the returned AST object the root node can have a sourceMap property? Or something along the lines of being able to supply a source map for the original AST in order to get the resulting source map. If no sourcemap is provided, then it would just return a sourcemap as if this is the first transform on the given code.

Would something like that be doable? What are the limitations? For example, I know the AST doesn't contain info about semi colons or the number and ordering of whitespace characters, so it may be difficult to map that.

Is there any existing recommended way to handle source maps with esprima+estraverse?

Why don't just fix the AST standard?

I don't understand the whole concept of estraverse. I mean it's like creating a SAX parser which iterates over the DOM. If I understand well, all of this is because the AST nodes do not have an uniform interface, like DOM nodes have e.g. childNodes, setAttribute, appendChild, etc.. Why don't you just fix the standard instead of creating such workarounds because of its errors?

What happens with node returned from replace()?

When we replace a node, do we expect the whole sub-tree of that node to be replaced?

I think that is the case, just wondering. Haven't tried it yet.

Another possibility could be that a returned node with a matching type is replaced in-place.

Large JS files not fully traversed

I'm trying to traverse the AST of a JS file with 32482 LOC. I can see that lines after line 27860 has not been traversed. I can see the FunctionExpression node at that line has been entered but not left. Is this a known limitation in estraverse? Is there a way around this? Here is the file I'm trying to analyze.

Support traverse of comments

Esprima can include source code comments in its AST. For example, when parsing this code with the comment:true flag:

function f(){
    /*hello*/
    //world
}

Esprima returns this AST:

{
    "type": "Program",
    "body": [ /* omitted to save space */ ],
    "comments": [
        {
            "type": "Block",
            "value": "hello"
        },
        {
            "type": "Line",
            "value": "world"
        },
    ]
}

It would be helpful for estraverse to visit the comment nodes. Currently it does not.

(I believe comments are an Esprima extension to the Spidermonkey API, so this may be non-standard. But it would be really useful for downstream projects. For example, I'm currently trying to write a linting rule for ESLint that deals with comments, and fixing this issue is a prerequisite.)

Node not removed

Consider the following example:

var escodegen = require('escodegen');
var esprima = require('esprima');
var estraverse = require('estraverse');

var code = 'function foo() { debug("bar"); debug("baz"); }';
var ast = esprima.parse(code);

estraverse.replace(ast, {
  enter: function enter(node) {
    if (
        'ExpressionStatement' === node.type
      && 'CallExpression' === node.expression.type
      && 'debug' === node.expression.callee.name
    ) {
      return this.remove();
    }
  }
});

code = escodegen.generate(ast, {
  format: {
    indent: { style: '  ' }
  }
});

console.log(code);

This returns:

function foo() {
  debug('baz');
}

but the expected result is:

function foo() {
}

Am i doing something wrong?
The versions of the modules used:

├─┬ [email protected]
│ ├── [email protected]
│ └─┬ [email protected]
│   └── [email protected]
├── [email protected]
└── [email protected]

/cc @RReverser

Accessing parent of parent node, that's grand parent node

Thanks for the wonderful work.

Is it possible to access the parent of parent node?

If the current node is 1 in the image below, is it possible to access node 5 ?

example:

 ast = estraverse.replace(ast, {
            leave: function(node, parent, grand) {
                       console.log(grand);
              }
  }

Pls. can anyone help?
tree

estraverse ignores decorator in AST

We have the below sample code:

function dec() {
}

export default class Foo {
    @dec
    bar() {}
}

After parsed with babel-eslint, it contains a MethodDefinition node at body[1].declaration.body.body[0], it has a decorators property, however estraverse.traverse just ignore this property

Is it possible that estraverse support the edge ECMAScript feature to visit Decorator node?

Strange conditional logic in traverse() inner loop

The use of candidates[current] instead of key is confusing, but candidates[current].type seems nonsensical (it will always be undefined, unless I'm mistaken):

if (nodeType === Syntax.ObjectExpression &&
    'properties' === candidates[current] && // Why not 'properties' === key?
    null == candidates[current].type) { // Do you mean node.type or candidate.type?
    element = new Element(candidate[current2], [key, current2], 'Property', null);
}

As seen here: https://github.com/Constellation/estraverse/blob/e8c74ab23dde58153fd2ff4d9c02f45877162963/estraverse.js#L340

estraverse::nodeToObject

What about nodeToObject method?
now I have to use workaroud with patched escodegen and json.parse:

const nodeToObject = node => JSON.parse(codegen.generate(node, {format: {realjson: true}}));

usage

traverse.traverse(ast, {
    enter: node => isBemjson(node) && bemjsons.push(this.nodeToObject(node))
});

Option to ignore properties in fallback="iteration" mode

Right now, the option for fallback: "iteration" works great so long as all properties containing arrays/objects are intended to be traversed. However, there are some cases where extra information has been added into the AST (such as a parent property) where traversing according to regular rules isn't desirable.

I'd like to add an option that works only when fallback: "iteration" is set that allows us to ignore specific properties by name. So something like:

controller.traverse(tree, {
    enter: function() {},
    exit: function() {},
    fallback: "iteration",
    ignoreKeys: [ "parent" ]
});

So ignoreKeys would be an array of keys that should never be traversed regardless of where they appear in the tree.

Document what Skip and Break does

Does skip stop recursion down its children? does break only stop the traversal of the current node's siblings, or will it halt the entire operation entirely? These behaviors aren't documented and aren't immediately apparent.

backward traversal

First, thank you for very elegant, concise, and useful tool. I use both tools: estraverse and recently shift-traverse for my projects.

One thing that I am missing is backward AST traversal. IMHO It will be useful for the static code analysis algorithms like lazy SSA construction or definition search.

What do you think?

Add onEnd handler or then promise

I use estraverse look for a specific node and I return the promise.
I cannot throw reject on traverse complete without workarounds.

function retrieveBemEntity (fileContent, offset) {
  return new Promise(function (res, err) {
    var ast = parse.parseExpressionAt(fileContent.substr(offset));
    traverse.traverse(ast, {enter: function (node) {
      var bemEntity = _onNode(node);
      if (bemEntity) res(bemEntity), this.break();
    }});
    setTimeout(()=>err('not found'), 100); // todo add traverse.traverse on end handler
  });
}

Removing nodes in estraverse.replace

Is needed from time to time (for example, to eliminate debugger statements in AST), but the only option for now is replacing them with EmptyStatement which is not exactly the same as generates extra line with ;.

I do understand that removing nodes is not always correct (i.e., not an option for parts of expressions), but this responsibility should be on developer's shoulders.

Unknown node types

From time to time, there are new node types that are not yet supported by estraverse. Currently, estraverse just throws error on such nodes, what makes it less flexible compared to other AST traversal libraries (while I do understand reasoning behind strict set of properties).

But what if, instead of throwing, we would allow iterating over all sub-properties of unknown nodes? This would allow to use estraverse on new node types without waiting for new versions.

defaults and rest members of Function nodes not traversed

interface Function <: Node {
    id: Identifier | null;
    params: [ Pattern ];
    defaults: [ Expression ];
    rest: Identifier | null;
    body: BlockStatement | Expression;
    generator: boolean;
    expression: boolean;
}

As you can see, id, params, defaults, rest, and body may have values that are Nodes, but we currently only traverse these members:

  • ArrowFunctionExpression: ['params', 'body']
  • FunctionDeclaration: ['id', 'params', 'body']
  • FunctionExpression: ['id', 'params', 'body']

Add support to replace a node on enter, but skip traversal of child nodes

Hi there,
it seems that the most recent version of estraverse has a more simplified interface compared to older versions. The enter callback of the visitor does not include the third 'cb' argument, previously used to skip traversal.
With the new method of returning the SKIP or BREAK value, there is no way to replace a node in the enter stage, while skipping the traversal of the children, which is a feature we're currently using in our project.

Are there any plans to add support for this (again)?

replace(): replace with 2 nodes?

Would it be possible to replace a node with multiple statements? I understand this can't work on all places (only in bodys), but it'd be useful for some cases.

estraverse.replace(tree, {
  enter: function (node, parent) {
    if (/* something */) {
      return [
        { type: 'FunctionDeclaration', body: /* ... */ },
        { type: 'FunctionDeclaration', body: /* ... */ } ];
    }
  }
});

An example use case would be to to change a ForStatement (for (x;y;z){a}) into a WhileStatement (x; while (y) { z; a; }), which will be useful for js2coffee.

4.1.0 -> 4.1.1 update breaks eslint

I'm not completely sure if the problem is with estraverse or eslint, but the fact is that eslint works just fine for us over estraverse 4.1.0, bur over estraverse 4.1.1 it does that:

> [email protected] lint /home/gitlab-runner/builds/be2d88b2/0/stc-b2b/browser-app
> eslint ./src ./index.js ./tests


/home/gitlab-runner/builds/be2d88b2/0/stc-b2b/browser-app/node_modules/estraverse/estraverse.js:411
                current = candidates.length;
                                    ^
TypeError: Cannot read property 'length' of undefined
    at Controller.traverse (/home/gitlab-runner/builds/be2d88b2/0/stc-b2b/browser-app/node_modules/estraverse/estraverse.js:411:37)
    at EventEmitter.module.exports.api.verify (/home/gitlab-runner/builds/be2d88b2/0/stc-b2b/browser-app/node_modules/eslint/lib/eslint.js:779:24)
    at processText (/home/gitlab-runner/builds/be2d88b2/0/stc-b2b/browser-app/node_modules/eslint/lib/cli-engine.js:221:27)
    at processFile (/home/gitlab-runner/builds/be2d88b2/0/stc-b2b/browser-app/node_modules/eslint/lib/cli-engine.js:258:18)
    at executeOnFile (/home/gitlab-runner/builds/be2d88b2/0/stc-b2b/browser-app/node_modules/eslint/lib/cli-engine.js:604:23)
    at Array.forEach (native)
    at /home/gitlab-runner/builds/be2d88b2/0/stc-b2b/browser-app/node_modules/eslint/lib/cli-engine.js:630:49
    at Array.forEach (native)
    at CLIEngine.executeOnFiles (/home/gitlab-runner/builds/be2d88b2/0/stc-b2b/browser-app/node_modules/eslint/lib/cli-engine.js:626:18)
    at Object.cli.execute (/home/gitlab-runner/builds/be2d88b2/0/stc-b2b/browser-app/node_modules/eslint/lib/cli.js:159:95)

List of operator symbols with English names

I'd like to add a pubic property, estraverse.Operators
I find this useful for debugging and using the english names for valid element classnames.

estraverse.Operators = {
    '=': 'equal-assign',
    '+=': 'plus-assign',
    '-=': 'minus-assign',
    '*=': 'times-assign',
    '/=': 'divide-assign',
    '%=': 'modulus-assign',
    '<<=': 'left-shift-assign',
    '>>=': 'right-shift-assign',
    '>>>=': 'zero-right-shift-assign',
    '&=': 'and-assign',
    '^=': 'xor-assign',
    '|=': 'or-assign',

    '==': 'equal',
    '!=': 'not-equal',
    '===': 'strict-equal',
    '!==': 'strict-not-equal',
    '>': 'greater-than',
    '>=': 'greater-than-or-equal',
    '<': 'less-than',
    '<=': 'less-than-or-equal',

    '%': 'modulus',
    '++': 'increment',
    '--': 'decrement',
    '-': 'negate',

    '&': 'bitwise-and',
    '|': 'bitwise-or',
    '~': 'bitwise-not',
    '^': 'xor',
    '<<': 'left-shift',
    '>>': 'right-shift',
    '>>>': 'zero-right-shift',

    '&&': 'logical-and',
    '||': 'logical-or',
    '!': 'logical-not',

    '?': 'trinary-consequent',
    ':': 'trinary-alternate'
}

npmjs package page doesn't show readme

At https://www.npmjs.com/package/estraverse, it says there is no readme:

screen shot 2017-03-28 at 3 38 00 pm

This is because the published package does not include README.md:

$ tar tvf $(npm pack estraverse)
-rw-rw-rw-  0 0      0        1016 Mar 10  2016 package/package.json
-rw-rw-rw-  0 0      0       27642 Mar 10  2016 package/estraverse.js
-rw-rw-rw-  0 0      0        2790 Mar  7  2016 package/gulpfile.js
-rw-rw-rw-  0 0      0        1231 Mar  7  2016 package/LICENSE.BSD
-rw-rw-rw-  0 0      0         242 Mar  7  2016 package/.jshintrc
-rw-rw-rw-  0 0      0          29 Mar  7  2016 package/.babelrc
$

According to https://github.com/npm/registry/issues/120#issuecomment-276157329, old versions of npm didn't include README.md. If you upgrade your npm version, and publish a patch release of this module, the readme should appear on npmjs.com.


(issue markdown adapted from domenic/opener#24)

ExportSpecifier visitor keys not in same order as source / token list

VisitorKeys = {
...
ExportSpecifier: ['exported', 'local'],

The keys should be in the reverse order because the 'local' identifier node will come before the 'exported' node. For example:
var a; export { a as b };
'local' is 'a'
'exported' is 'b'

This is the opposite for ImportSpecifier so its keys are correct.

exports is undefined?

Hi

I tried to use estraverse as external javascript library for a website that I develop. Whenever I call estraverse (estraverse.traverse), it gaves me an error: 'exports' is undefined. Can someone help with this?

Here are my code:

<script type="text/javascript" src="plugins/esprima.js"></script> <script type="text/javascript" src="plugins/estraverse.js"></script>

var ast;
ast = esprima.parse('var answer = 42;var answer2 = 45;function f(){var answer3;}');
ast = JSON.stringify(ast);

var test;
estraverse.traverse(ast, {
enter: function (node, parent) {
if (node.type == 'FunctionExpression' || node.type == 'FunctionDeclaration')
return estraverse.VisitorOption.Skip;
},
leave: function (node, parent) {
if (node.type == 'VariableDeclarator')
test += node.id.name;
}
});

How can I get preceding/leading comments for a node when traversing?

I am trying to get all the comments that are preceding/before the current node while traversing. I notice the comment here: #9 (comment), but I am not exactly sure how to do it.

If I first parse my source code using esprima, I will get the AST, where comments are separate from the tree, inside ast.comments.

Then, when I traverse the tree using estraverse, how and when should I attachComments so that I can access them in leadingComments?

I tried something like this:

var ast = esprima.parse(...);
estraverse.traverse(ast, {
  cursor: 0,
  enter: function (node) {
    node = estraverse.attachComments( node, ast.comments, [] );
    console.log('NODE', node)
  }
});

But it doesn't work - it simply adds all comments to the leadingComments property of a node.

Traverse down to new nodes in .replace()

When using estraverse.replace(), and I want to make new nodes, what's the best way to traverse down those new nodes?

For instance:

estraverse.replace(tree, {
  enter: function (node, parent) {
    if (/* something */) {
      var newStatement = { type: 'FunctionDeclaration', body: /* ... */ };
      parent.body.push(newStatement);
     // ...recurse into newStatement
    }
  }
});

...currently, I'm just invoking estraverse.replace(newroot, { ... }) again with the same enter/exits, but I was wondering if there would be strange side effects to this of if there would be better ways.

README.md typo

Second Example in the README.md: Shouldn't it be "return this.break();" instead of only "this.break();" in order for the traversal to end at the first node?

release 1.9.1 not tagged

escodegen references version ^1.9.1 as a dependency but there is no release for this even though the latest HEAD is tagged "version 1.9.2 starts". Could this be release be tagged?

Source version does not match tag version

While updating Eclipse Orion to use version 1.5.0 of Estraverse I noticed that the exported version is '1.3.3-dev' for the1.5 tag in the repo. Is this intentional? It does not cause any issues for us, just wondering why the source version and the tagged version differ.

Release 4.1.1

c074451 fixes a very fatal bug in ESLint where parsing basic stuff like export default would crash. It would be so awesome is this change is released soon 👍

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.