pax_global_header00006660000000000000000000000064137232375460014526gustar00rootroot0000000000000052 comment=8ceb63797813d9ac69572a671b95cf58ffdf35b6 esrecurse-4.3.0/000077500000000000000000000000001372323754600135325ustar00rootroot00000000000000esrecurse-4.3.0/.babelrc000066400000000000000000000000361372323754600151240ustar00rootroot00000000000000{ "presets": ["es2015"] } esrecurse-4.3.0/.gitignore000066400000000000000000000002141372323754600155170ustar00rootroot00000000000000# Emacs *~ \#*\# # Node modules node_modules/ # Cover .coverage_data/ cover_html/ coverage/ npm-debug.log .vimrc.local package-lock.json esrecurse-4.3.0/.npmignore000066400000000000000000000002571372323754600155350ustar00rootroot00000000000000npm-debug.log .DS_Store .vimrc.local t.js .travis.yml .npmignore /tmp/ /.git/ /node_modules/ /tools/ /test/ /build/ /cover_html/ /coverage/ /.coverage_data/ package-lock.json esrecurse-4.3.0/.travis.yml000066400000000000000000000001001372323754600156320ustar00rootroot00000000000000sudo: false language: node_js node_js: - "6" - "8" - "10" esrecurse-4.3.0/README.md000066400000000000000000000117561372323754600150230ustar00rootroot00000000000000### Esrecurse [![Build Status](https://travis-ci.org/estools/esrecurse.svg?branch=master)](https://travis-ci.org/estools/esrecurse) Esrecurse ([esrecurse](https://github.com/estools/esrecurse)) is [ECMAScript](https://www.ecma-international.org/publications/standards/Ecma-262.htm) recursive traversing functionality. ### Example Usage The following code will output all variables declared at the root of a file. ```javascript esrecurse.visit(ast, { XXXStatement: function (node) { this.visit(node.left); // do something... this.visit(node.right); } }); ``` We can use `Visitor` instance. ```javascript var visitor = new esrecurse.Visitor({ XXXStatement: function (node) { this.visit(node.left); // do something... this.visit(node.right); } }); visitor.visit(ast); ``` We can inherit `Visitor` instance easily. ```javascript class Derived extends esrecurse.Visitor { constructor() { super(null); } XXXStatement(node) { } } ``` ```javascript function DerivedVisitor() { esrecurse.Visitor.call(/* this for constructor */ this /* visitor object automatically becomes this. */); } util.inherits(DerivedVisitor, esrecurse.Visitor); DerivedVisitor.prototype.XXXStatement = function (node) { this.visit(node.left); // do something... this.visit(node.right); }; ``` And you can invoke default visiting operation inside custom visit operation. ```javascript function DerivedVisitor() { esrecurse.Visitor.call(/* this for constructor */ this /* visitor object automatically becomes this. */); } util.inherits(DerivedVisitor, esrecurse.Visitor); DerivedVisitor.prototype.XXXStatement = function (node) { // do something... this.visitChildren(node); }; ``` The `childVisitorKeys` option does customize the behaviour of `this.visitChildren(node)`. We can use user-defined node types. ```javascript // This tree contains a user-defined `TestExpression` node. var tree = { type: 'TestExpression', // This 'argument' is the property containing the other **node**. argument: { type: 'Literal', value: 20 }, // This 'extended' is the property not containing the other **node**. extended: true }; esrecurse.visit( ast, { Literal: function (node) { // do something... } }, { // Extending the existing traversing rules. childVisitorKeys: { // TargetNodeName: [ 'keys', 'containing', 'the', 'other', '**node**' ] TestExpression: ['argument'] } } ); ``` We can use the `fallback` option as well. If the `fallback` option is `"iteration"`, `esrecurse` would visit all enumerable properties of unknown nodes. Please note circular references cause the stack overflow. AST might have circular references in additional properties for some purpose (e.g. `node.parent`). ```javascript esrecurse.visit( ast, { Literal: function (node) { // do something... } }, { fallback: 'iteration' } ); ``` If the `fallback` option is a function, `esrecurse` calls this function to determine the enumerable properties of unknown nodes. Please note circular references cause the stack overflow. AST might have circular references in additional properties for some purpose (e.g. `node.parent`). ```javascript esrecurse.visit( ast, { Literal: function (node) { // do something... } }, { fallback: function (node) { return Object.keys(node).filter(function(key) { return key !== 'argument' }); } } ); ``` ### License Copyright (C) 2014 [Yusuke Suzuki](https://github.com/Constellation) (twitter: [@Constellation](https://twitter.com/Constellation)) and other contributors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. esrecurse-4.3.0/esrecurse.js000066400000000000000000000102061372323754600160670ustar00rootroot00000000000000/* Copyright (C) 2014 Yusuke Suzuki Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ (function () { 'use strict'; var estraverse = require('estraverse'); function isNode(node) { if (node == null) { return false; } return typeof node === 'object' && typeof node.type === 'string'; } function isProperty(nodeType, key) { return (nodeType === estraverse.Syntax.ObjectExpression || nodeType === estraverse.Syntax.ObjectPattern) && key === 'properties'; } function Visitor(visitor, options) { options = options || {}; this.__visitor = visitor || this; this.__childVisitorKeys = options.childVisitorKeys ? Object.assign({}, estraverse.VisitorKeys, options.childVisitorKeys) : estraverse.VisitorKeys; if (options.fallback === 'iteration') { this.__fallback = Object.keys; } else if (typeof options.fallback === 'function') { this.__fallback = options.fallback; } } /* Default method for visiting children. * When you need to call default visiting operation inside custom visiting * operation, you can use it with `this.visitChildren(node)`. */ Visitor.prototype.visitChildren = function (node) { var type, children, i, iz, j, jz, child; if (node == null) { return; } type = node.type || estraverse.Syntax.Property; children = this.__childVisitorKeys[type]; if (!children) { if (this.__fallback) { children = this.__fallback(node); } else { throw new Error('Unknown node type ' + type + '.'); } } for (i = 0, iz = children.length; i < iz; ++i) { child = node[children[i]]; if (child) { if (Array.isArray(child)) { for (j = 0, jz = child.length; j < jz; ++j) { if (child[j]) { if (isNode(child[j]) || isProperty(type, children[i])) { this.visit(child[j]); } } } } else if (isNode(child)) { this.visit(child); } } } }; /* Dispatching node. */ Visitor.prototype.visit = function (node) { var type; if (node == null) { return; } type = node.type || estraverse.Syntax.Property; if (this.__visitor[type]) { this.__visitor[type].call(this, node); return; } this.visitChildren(node); }; exports.version = require('./package.json').version; exports.Visitor = Visitor; exports.visit = function (node, visitor, options) { var v = new Visitor(visitor, options); v.visit(node); }; }()); /* vim: set sw=4 ts=4 et tw=80 : */ esrecurse-4.3.0/gulpfile.babel.js000066400000000000000000000056701372323754600167530ustar00rootroot00000000000000// Copyright (C) 2014 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import gulp from 'gulp'; import mocha from 'gulp-mocha'; import eslint from 'gulp-eslint'; import minimist from 'minimist'; import git from 'gulp-git'; import bump from 'gulp-bump'; import filter from 'gulp-filter'; import tagVersion from 'gulp-tag-version'; import 'babel-register'; const SOURCE = [ '*.js' ]; let ESLINT_OPTION = { parser: 'babel-eslint', parserOptions: { 'sourceType': 'module' }, rules: { 'quotes': 0, 'eqeqeq': 0, 'no-use-before-define': 0, 'no-shadow': 0, 'no-new': 0, 'no-underscore-dangle': 0, 'no-multi-spaces': 0, 'no-native-reassign': 0, 'no-loop-func': 0 }, env: { 'node': true } }; gulp.task('test', function() { let options = minimist(process.argv.slice(2), { string: 'test', default: { test: 'test/*.js' } } ); return gulp.src(options.test).pipe(mocha({reporter: 'spec'})); }); gulp.task('lint', () => gulp.src(SOURCE) .pipe(eslint(ESLINT_OPTION)) .pipe(eslint.formatEach('stylish', process.stderr)) .pipe(eslint.failOnError()) ); let inc = importance => gulp.src(['./package.json']) .pipe(bump({type: importance})) .pipe(gulp.dest('./')) .pipe(git.commit('Bumps package version')) .pipe(filter('package.json')) .pipe(tagVersion({ prefix: '' })) ; gulp.task('travis', [ 'lint', 'test' ]); gulp.task('default', [ 'travis' ]); gulp.task('patch', [ ], () => inc('patch')); gulp.task('minor', [ ], () => inc('minor')); gulp.task('major', [ ], () => inc('major')); esrecurse-4.3.0/package.json000077500000000000000000000022151372323754600160230ustar00rootroot00000000000000{ "name": "esrecurse", "description": "ECMAScript AST recursive visitor", "homepage": "https://github.com/estools/esrecurse", "main": "esrecurse.js", "version": "4.3.0", "engines": { "node": ">=4.0" }, "maintainers": [ { "name": "Yusuke Suzuki", "email": "utatane.tea@gmail.com", "web": "https://github.com/Constellation" } ], "repository": { "type": "git", "url": "https://github.com/estools/esrecurse.git" }, "dependencies": { "estraverse": "^5.2.0" }, "devDependencies": { "babel-cli": "^6.24.1", "babel-eslint": "^7.2.3", "babel-preset-es2015": "^6.24.1", "babel-register": "^6.24.1", "chai": "^4.0.2", "esprima": "^4.0.0", "gulp": "^3.9.0", "gulp-bump": "^2.7.0", "gulp-eslint": "^4.0.0", "gulp-filter": "^5.0.0", "gulp-git": "^2.4.1", "gulp-mocha": "^4.3.1", "gulp-tag-version": "^1.2.1", "jsdoc": "^3.3.0-alpha10", "minimist": "^1.1.0" }, "license": "BSD-2-Clause", "scripts": { "test": "gulp travis", "unit-test": "gulp test", "lint": "gulp lint" }, "babel": { "presets": [ "es2015" ] } } esrecurse-4.3.0/test/000077500000000000000000000000001372323754600145115ustar00rootroot00000000000000esrecurse-4.3.0/test/traverse.js000066400000000000000000000226101372323754600167030ustar00rootroot00000000000000// Copyright (C) 2013 Yusuke Suzuki // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. var expect = require('chai').expect; var esrecurse = require('..'); describe('object expression', () => it('properties', function() { let tree = { type: 'ObjectExpression', properties: [{ type: 'Property', key: { type: 'Identifier', name: 'a' }, value: { type: 'Identifier', name: 'b' } }] }; let log = []; esrecurse.visit(tree, { Identifier(node) { return log.push(node.name); } } ); return expect(log).to.deep.equal(['a', 'b']); }) ); describe('chain expression', () => it('expressions', function() { let tree = { type: 'ChainExpression', expression: [{ type: 'MemberExpression', object: { type: 'Identifier', name: 'a' }, property: { type: 'Identifier', name: 'b' }, computed: false, optional: true }] }; let log = []; esrecurse.visit(tree, { Identifier(node) { return log.push(node.name); } } ); return expect(log).to.deep.equal(['a', 'b']); }) ); describe('non listed keys throw an error', () => it('traverse', function() { let tree = { type: 'TestStatement', id: { type: 'Identifier', name: 'decl' }, params: [{ type: 'Identifier', name: 'a' }], defaults: [{ type: 'Literal', value: 20 }], rest: { type: 'Identifier', name: 'rest' }, body: { type: 'BlockStatement', body: [] } }; return expect(function() { let log = []; return esrecurse.visit( tree, { Literal(node) { return log.push(node.value); } } ); }).to.throw('Unknown node type TestStatement.'); }) ); describe('no listed keys fallback if "fallback" option was given', () => it('traverse', function() { let tree = { type: 'TestStatement', id: { type: 'Identifier', name: 'decl' }, params: [{ type: 'Identifier', name: 'a' }], defaults: [{ type: 'Literal', value: 20 }], rest: { type: 'Identifier', name: 'rest' }, body: { type: 'BlockStatement', body: [] } }; let log = []; esrecurse.visit( tree, { Literal(node) { return log.push(node.value); } }, { fallback: 'iteration' } ); return expect(log).to.deep.equal([ 20 ]); }) ); describe('no listed keys fallback if "fallback" option is a function', () => it('traverse', function() { let tree = { type: 'TestStatement', id: { type: 'Identifier', name: 'decl' }, params: [{ type: 'Identifier', name: 'a' }], defaults: [{ type: 'Literal', value: 20 }], rest: { type: 'Identifier', name: 'rest' }, body: { type: 'BlockStatement', body: [] } }; let result = 0; esrecurse.visit( tree, { Identifier() { return result++; } }, { fallback(node) { return Object.keys(node).filter(key => key !== 'id'); } } ); return expect(result).to.equal(2); }) ); describe('inherit Visitor', function() { it('log names', function() { let tree = { type: 'TestStatement', id: { type: 'Identifier', name: 'decl' }, params: [{ type: 'Identifier', name: 'a' }], defaults: [{ type: 'Literal', value: 20 }], rest: { type: 'Identifier', name: 'rest' }, body: { type: 'BlockStatement', body: [] } }; class Derived extends esrecurse.Visitor { constructor() { super(null, {fallback: 'iteration'}); this.log = []; } Identifier(node) { return this.log.push(node.name); } } let visitor = new Derived; visitor.visit(tree); return expect(visitor.log).to.deep.equal([ 'decl', 'a', 'rest' ]); }); return it('customize behavior', function() { let tree = { type: 'TestStatement', id: { type: 'Identifier', name: 'decl' }, params: [{ type: 'Identifier', name: 'a' }], defaults: [{ type: 'Literal', value: 20 }], rest: { type: 'Identifier', name: 'rest' }, body: { type: 'BlockStatement', body: [{ type: 'Identifier', value: 'XXX' }] } }; class Derived extends esrecurse.Visitor { constructor() { super(null, {fallback: 'iteration'}); this.log = []; } BlockStatement(node) {} Identifier(node) { return this.log.push(node.name); } } let visitor = new Derived; visitor.visit(tree); return expect(visitor.log).to.deep.equal([ 'decl', 'a', 'rest' ]); }); }); describe('bidirectional relationship at non visitor keys.', function() { it('ExpressionStatement <-> Identifier', function() { let tree = { type: 'ExpressionStatement', expression: { type: 'Identifier', name: 'foo' } }; tree.expression.parent = tree; let log = []; esrecurse.visit(tree, { Identifier(node) { return log.push(node.name); } } ); return expect(log).to.deep.equal(['foo']); }); return it('ExpressionStatement <-> UnknownNode with the childVisitorKeys option', function() { let tree = { type: 'ExpressionStatement', expression: { type: 'UnknownNode', argument: { type: 'Identifier', name: 'foo' } } }; tree.expression.parent = tree; tree.expression.argument.parent = tree.expression; let log = []; esrecurse.visit( tree, { Identifier(node) { return log.push(node.name); } }, { childVisitorKeys: { UnknownNode: ['argument'] } } ); return expect(log).to.deep.equal(['foo']); }); });