mirror of https://github.com/lukechilds/node.git
Browse Source
Update ESLint to 4.1.0. This fixes a bug that previously prevented us from using the new and stricter indentation checking. Refs: https://github.com/eslint/eslint/issues/8721 Backport-PR-URL: https://github.com/nodejs/node/pull/14830 PR-URL: https://github.com/nodejs/node/pull/13895 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Roman Reiss <me@silverwind.io> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com>v6.x
Rich Trott
8 years ago
committed by
Myles Borins
216 changed files with 10484 additions and 8298 deletions
@ -0,0 +1,68 @@ |
|||
/** |
|||
* @fileoverview Defines a schema for configs. |
|||
* @author Sylvan Mably |
|||
*/ |
|||
|
|||
"use strict"; |
|||
|
|||
const baseConfigProperties = { |
|||
env: { type: "object" }, |
|||
globals: { type: "object" }, |
|||
parser: { type: ["string", "null"] }, |
|||
parserOptions: { type: "object" }, |
|||
plugins: { type: "array" }, |
|||
rules: { type: "object" }, |
|||
settings: { type: "object" } |
|||
}; |
|||
|
|||
const overrideProperties = Object.assign( |
|||
{}, |
|||
baseConfigProperties, |
|||
{ |
|||
files: { |
|||
oneOf: [ |
|||
{ type: "string" }, |
|||
{ |
|||
type: "array", |
|||
items: { type: "string" }, |
|||
minItems: 1 |
|||
} |
|||
] |
|||
}, |
|||
excludedFiles: { |
|||
oneOf: [ |
|||
{ type: "string" }, |
|||
{ |
|||
type: "array", |
|||
items: { type: "string" } |
|||
} |
|||
] |
|||
} |
|||
} |
|||
); |
|||
|
|||
const topLevelConfigProperties = Object.assign( |
|||
{}, |
|||
baseConfigProperties, |
|||
{ |
|||
extends: { type: ["string", "array"] }, |
|||
root: { type: "boolean" }, |
|||
overrides: { |
|||
type: "array", |
|||
items: { |
|||
type: "object", |
|||
properties: overrideProperties, |
|||
required: ["files"], |
|||
additionalProperties: false |
|||
} |
|||
} |
|||
} |
|||
); |
|||
|
|||
const configSchema = { |
|||
type: "object", |
|||
properties: topLevelConfigProperties, |
|||
additionalProperties: false |
|||
}; |
|||
|
|||
module.exports = configSchema; |
@ -1,15 +0,0 @@ |
|||
{ |
|||
"type": "object", |
|||
"properties": { |
|||
"root": { "type": "boolean" }, |
|||
"globals": { "type": ["object"] }, |
|||
"parser": { "type": ["string", "null"] }, |
|||
"env": { "type": "object" }, |
|||
"plugins": { "type": ["array"] }, |
|||
"settings": { "type": "object" }, |
|||
"extends": { "type": ["string", "array"] }, |
|||
"rules": { "type": "object" }, |
|||
"parserOptions": { "type": "object" } |
|||
}, |
|||
"additionalProperties": false |
|||
} |
@ -0,0 +1,130 @@ |
|||
/** |
|||
* @fileoverview Responsible for caching config files |
|||
* @author Sylvan Mably |
|||
*/ |
|||
|
|||
"use strict"; |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// Helpers
|
|||
//------------------------------------------------------------------------------
|
|||
|
|||
/** |
|||
* Get a string hash for a config vector |
|||
* @param {Array<Object>} vector config vector to hash |
|||
* @returns {string} hash of the vector values |
|||
* @private |
|||
*/ |
|||
function hash(vector) { |
|||
return JSON.stringify(vector); |
|||
} |
|||
|
|||
//------------------------------------------------------------------------------
|
|||
// API
|
|||
//------------------------------------------------------------------------------
|
|||
|
|||
/** |
|||
* Configuration caching class (not exported) |
|||
*/ |
|||
class ConfigCache { |
|||
|
|||
constructor() { |
|||
this.filePathCache = new Map(); |
|||
this.localHierarchyCache = new Map(); |
|||
this.mergedVectorCache = new Map(); |
|||
this.mergedCache = new Map(); |
|||
} |
|||
|
|||
/** |
|||
* Gets a config object from the cache for the specified config file path. |
|||
* @param {string} configFilePath the absolute path to the config file |
|||
* @returns {Object|null} config object, if found in the cache, otherwise null |
|||
* @private |
|||
*/ |
|||
getConfig(configFilePath) { |
|||
return this.filePathCache.get(configFilePath); |
|||
} |
|||
|
|||
/** |
|||
* Sets a config object in the cache for the specified config file path. |
|||
* @param {string} configFilePath the absolute path to the config file |
|||
* @param {Object} config the config object to add to the cache |
|||
* @returns {void} |
|||
* @private |
|||
*/ |
|||
setConfig(configFilePath, config) { |
|||
this.filePathCache.set(configFilePath, config); |
|||
} |
|||
|
|||
/** |
|||
* Gets a list of hierarchy-local config objects that apply to the specified directory. |
|||
* @param {string} directory the path to the directory |
|||
* @returns {Object[]|null} a list of config objects, if found in the cache, otherwise null |
|||
* @private |
|||
*/ |
|||
getHierarchyLocalConfigs(directory) { |
|||
return this.localHierarchyCache.get(directory); |
|||
} |
|||
|
|||
/** |
|||
* For each of the supplied parent directories, sets the list of config objects for that directory to the |
|||
* appropriate subset of the supplied parent config objects. |
|||
* @param {string[]} parentDirectories a list of parent directories to add to the config cache |
|||
* @param {Object[]} parentConfigs a list of config objects that apply to the lowest directory in parentDirectories |
|||
* @returns {void} |
|||
* @private |
|||
*/ |
|||
setHierarchyLocalConfigs(parentDirectories, parentConfigs) { |
|||
parentDirectories.forEach((localConfigDirectory, i) => { |
|||
const directoryParentConfigs = parentConfigs.slice(0, parentConfigs.length - i); |
|||
|
|||
this.localHierarchyCache.set(localConfigDirectory, directoryParentConfigs); |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Gets a merged config object corresponding to the supplied vector. |
|||
* @param {Array<Object>} vector the vector to find a merged config for |
|||
* @returns {Object|null} a merged config object, if found in the cache, otherwise null |
|||
* @private |
|||
*/ |
|||
getMergedVectorConfig(vector) { |
|||
return this.mergedVectorCache.get(hash(vector)); |
|||
} |
|||
|
|||
/** |
|||
* Sets a merged config object in the cache for the supplied vector. |
|||
* @param {Array<Object>} vector the vector to save a merged config for |
|||
* @param {Object} config the merged config object to add to the cache |
|||
* @returns {void} |
|||
* @private |
|||
*/ |
|||
setMergedVectorConfig(vector, config) { |
|||
this.mergedVectorCache.set(hash(vector), config); |
|||
} |
|||
|
|||
/** |
|||
* Gets a merged config object corresponding to the supplied vector, including configuration options from outside |
|||
* the vector. |
|||
* @param {Array<Object>} vector the vector to find a merged config for |
|||
* @returns {Object|null} a merged config object, if found in the cache, otherwise null |
|||
* @private |
|||
*/ |
|||
getMergedConfig(vector) { |
|||
return this.mergedCache.get(hash(vector)); |
|||
} |
|||
|
|||
/** |
|||
* Sets a merged config object in the cache for the supplied vector, including configuration options from outside |
|||
* the vector. |
|||
* @param {Array<Object>} vector the vector to save a merged config for |
|||
* @param {Object} config the merged config object to add to the cache |
|||
* @returns {void} |
|||
* @private |
|||
*/ |
|||
setMergedConfig(vector, config) { |
|||
this.mergedCache.set(hash(vector), config); |
|||
} |
|||
} |
|||
|
|||
module.exports = ConfigCache; |
@ -1,102 +1,46 @@ |
|||
{ |
|||
"_args": [ |
|||
[ |
|||
{ |
|||
"raw": "babel-code-frame@^6.22.0", |
|||
"scope": null, |
|||
"escapedName": "babel-code-frame", |
|||
"name": "babel-code-frame", |
|||
"rawSpec": "^6.22.0", |
|||
"spec": ">=6.22.0 <7.0.0", |
|||
"type": "range" |
|||
}, |
|||
"/Users/trott/io.js/tools/node_modules/eslint" |
|||
] |
|||
], |
|||
"_from": "babel-code-frame@>=6.22.0 <7.0.0", |
|||
"_from": "babel-code-frame@^6.22.0", |
|||
"_id": "babel-code-frame@6.22.0", |
|||
"_inCache": true, |
|||
"_location": "/babel-code-frame", |
|||
"_nodeVersion": "6.9.0", |
|||
"_npmOperationalInternal": { |
|||
"host": "packages-12-west.internal.npmjs.com", |
|||
"tmp": "tmp/babel-code-frame-6.22.0.tgz_1484872404755_0.3806710622739047" |
|||
}, |
|||
"_npmUser": { |
|||
"name": "hzoo", |
|||
"email": "hi@henryzoo.com" |
|||
}, |
|||
"_npmVersion": "3.10.10", |
|||
"_inBundle": false, |
|||
"_integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=", |
|||
"_location": "/eslint/babel-code-frame", |
|||
"_phantomChildren": {}, |
|||
"_requested": { |
|||
"type": "range", |
|||
"registry": true, |
|||
"raw": "babel-code-frame@^6.22.0", |
|||
"scope": null, |
|||
"escapedName": "babel-code-frame", |
|||
"name": "babel-code-frame", |
|||
"escapedName": "babel-code-frame", |
|||
"rawSpec": "^6.22.0", |
|||
"spec": ">=6.22.0 <7.0.0", |
|||
"type": "range" |
|||
"saveSpec": null, |
|||
"fetchSpec": "^6.22.0" |
|||
}, |
|||
"_requiredBy": [ |
|||
"/eslint" |
|||
], |
|||
"_resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", |
|||
"_shasum": "027620bee567a88c32561574e7fd0801d33118e4", |
|||
"_shrinkwrap": null, |
|||
"_spec": "babel-code-frame@^6.22.0", |
|||
"_where": "/Users/trott/io.js/tools/node_modules/eslint", |
|||
"_where": "/Users/trott/io.js/tools/eslint-tmp/node_modules/eslint", |
|||
"author": { |
|||
"name": "Sebastian McKenzie", |
|||
"email": "sebmck@gmail.com" |
|||
}, |
|||
"bundleDependencies": false, |
|||
"dependencies": { |
|||
"chalk": "^1.1.0", |
|||
"esutils": "^2.0.2", |
|||
"js-tokens": "^3.0.0" |
|||
}, |
|||
"deprecated": false, |
|||
"description": "Generate errors that contain a code frame that point to source locations.", |
|||
"devDependencies": {}, |
|||
"directories": {}, |
|||
"dist": { |
|||
"shasum": "027620bee567a88c32561574e7fd0801d33118e4", |
|||
"tarball": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz" |
|||
}, |
|||
"homepage": "https://babeljs.io/", |
|||
"license": "MIT", |
|||
"main": "lib/index.js", |
|||
"maintainers": [ |
|||
{ |
|||
"name": "amasad", |
|||
"email": "amjad.masad@gmail.com" |
|||
}, |
|||
{ |
|||
"name": "hzoo", |
|||
"email": "hi@henryzoo.com" |
|||
}, |
|||
{ |
|||
"name": "jmm", |
|||
"email": "npm-public@jessemccarthy.net" |
|||
}, |
|||
{ |
|||
"name": "loganfsmyth", |
|||
"email": "loganfsmyth@gmail.com" |
|||
}, |
|||
{ |
|||
"name": "sebmck", |
|||
"email": "sebmck@gmail.com" |
|||
}, |
|||
{ |
|||
"name": "thejameskyle", |
|||
"email": "me@thejameskyle.com" |
|||
} |
|||
], |
|||
"name": "babel-code-frame", |
|||
"optionalDependencies": {}, |
|||
"readme": "ERROR: No README data found!", |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "https://github.com/babel/babel/tree/master/packages/babel-code-frame" |
|||
}, |
|||
"scripts": {}, |
|||
"version": "6.22.0" |
|||
} |
|||
|
@ -0,0 +1,101 @@ |
|||
{ |
|||
"_from": "ccount@^1.0.0", |
|||
"_id": "ccount@1.0.1", |
|||
"_inBundle": false, |
|||
"_integrity": "sha1-ZlaHlFFowhjsd/9hpBVa4AInqWw=", |
|||
"_location": "/ccount", |
|||
"_phantomChildren": {}, |
|||
"_requested": { |
|||
"type": "range", |
|||
"registry": true, |
|||
"raw": "ccount@^1.0.0", |
|||
"name": "ccount", |
|||
"escapedName": "ccount", |
|||
"rawSpec": "^1.0.0", |
|||
"saveSpec": null, |
|||
"fetchSpec": "^1.0.0" |
|||
}, |
|||
"_requiredBy": [ |
|||
"/remark-stringify" |
|||
], |
|||
"_resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.1.tgz", |
|||
"_shasum": "665687945168c218ec77ff61a4155ae00227a96c", |
|||
"_spec": "ccount@^1.0.0", |
|||
"_where": "/Users/trott/io.js/tools/eslint-tmp/node_modules/eslint/node_modules/remark-stringify", |
|||
"author": { |
|||
"name": "Titus Wormer", |
|||
"email": "tituswormer@gmail.com", |
|||
"url": "http://wooorm.com" |
|||
}, |
|||
"bugs": { |
|||
"url": "https://github.com/wooorm/ccount/issues" |
|||
}, |
|||
"bundleDependencies": false, |
|||
"contributors": [ |
|||
{ |
|||
"name": "Titus Wormer", |
|||
"email": "tituswormer@gmail.com", |
|||
"url": "http://wooorm.com" |
|||
} |
|||
], |
|||
"dependencies": {}, |
|||
"deprecated": false, |
|||
"description": "Count characters", |
|||
"devDependencies": { |
|||
"browserify": "^13.0.1", |
|||
"esmangle": "^1.0.1", |
|||
"nyc": "^7.0.0", |
|||
"remark-cli": "^1.0.0", |
|||
"remark-comment-config": "^4.0.0", |
|||
"remark-github": "^5.0.0", |
|||
"remark-lint": "^4.0.0", |
|||
"remark-validate-links": "^4.0.0", |
|||
"tape": "^4.0.0", |
|||
"xo": "^0.16.0" |
|||
}, |
|||
"files": [ |
|||
"index.js" |
|||
], |
|||
"homepage": "https://github.com/wooorm/ccount#readme", |
|||
"keywords": [ |
|||
"character", |
|||
"count", |
|||
"char" |
|||
], |
|||
"license": "MIT", |
|||
"name": "ccount", |
|||
"remarkConfig": { |
|||
"output": true, |
|||
"plugins": [ |
|||
"comment-config", |
|||
"github", |
|||
"lint", |
|||
"validate-links" |
|||
], |
|||
"settings": { |
|||
"bullet": "*" |
|||
} |
|||
}, |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "git+https://github.com/wooorm/ccount.git" |
|||
}, |
|||
"scripts": { |
|||
"build": "npm run build-md && npm run build-bundle && npm run build-mangle", |
|||
"build-bundle": "browserify index.js --bare -s ccount > ccount.js", |
|||
"build-mangle": "esmangle ccount.js > ccount.min.js", |
|||
"build-md": "remark . --quiet --frail", |
|||
"lint": "xo", |
|||
"test": "npm run build && npm run lint && npm run test-coverage", |
|||
"test-api": "node test", |
|||
"test-coverage": "nyc --reporter lcov tape test.js" |
|||
}, |
|||
"version": "1.0.1", |
|||
"xo": { |
|||
"space": true, |
|||
"ignores": [ |
|||
"ccount.js", |
|||
"ccount.min.js" |
|||
] |
|||
} |
|||
} |
@ -0,0 +1,98 @@ |
|||
{ |
|||
"_from": "character-entities-html4@^1.0.0", |
|||
"_id": "character-entities-html4@1.1.0", |
|||
"_inBundle": false, |
|||
"_integrity": "sha1-GrCFUdPOH6HfCNAPucod77FHoGw=", |
|||
"_location": "/character-entities-html4", |
|||
"_phantomChildren": {}, |
|||
"_requested": { |
|||
"type": "range", |
|||
"registry": true, |
|||
"raw": "character-entities-html4@^1.0.0", |
|||
"name": "character-entities-html4", |
|||
"escapedName": "character-entities-html4", |
|||
"rawSpec": "^1.0.0", |
|||
"saveSpec": null, |
|||
"fetchSpec": "^1.0.0" |
|||
}, |
|||
"_requiredBy": [ |
|||
"/stringify-entities" |
|||
], |
|||
"_resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.0.tgz", |
|||
"_shasum": "1ab08551d3ce1fa1df08d00fb9ca1defb147a06c", |
|||
"_spec": "character-entities-html4@^1.0.0", |
|||
"_where": "/Users/trott/io.js/tools/eslint-tmp/node_modules/eslint/node_modules/stringify-entities", |
|||
"author": { |
|||
"name": "Titus Wormer", |
|||
"email": "tituswormer@gmail.com", |
|||
"url": "http://wooorm.com" |
|||
}, |
|||
"bugs": { |
|||
"url": "https://github.com/wooorm/character-entities-html4/issues" |
|||
}, |
|||
"bundleDependencies": false, |
|||
"contributors": [ |
|||
{ |
|||
"name": "Titus Wormer", |
|||
"email": "tituswormer@gmail.com", |
|||
"url": "http://wooorm.com" |
|||
} |
|||
], |
|||
"dependencies": {}, |
|||
"deprecated": false, |
|||
"description": "HTML4 character entity information", |
|||
"devDependencies": { |
|||
"bail": "^1.0.1", |
|||
"browserify": "^13.0.1", |
|||
"concat-stream": "^1.5.2", |
|||
"esmangle": "^1.0.1", |
|||
"nyc": "^8.0.0", |
|||
"remark-cli": "^2.0.0", |
|||
"remark-preset-wooorm": "^1.0.0", |
|||
"tape": "^4.0.0", |
|||
"xo": "^0.17.0" |
|||
}, |
|||
"files": [ |
|||
"index.json" |
|||
], |
|||
"homepage": "https://github.com/wooorm/character-entities-html4#readme", |
|||
"keywords": [ |
|||
"html", |
|||
"html4", |
|||
"entity", |
|||
"entities", |
|||
"character", |
|||
"reference", |
|||
"name", |
|||
"replacement" |
|||
], |
|||
"license": "MIT", |
|||
"main": "index.json", |
|||
"name": "character-entities-html4", |
|||
"remarkConfig": { |
|||
"output": true, |
|||
"presets": "wooorm" |
|||
}, |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "git+https://github.com/wooorm/character-entities-html4.git" |
|||
}, |
|||
"scripts": { |
|||
"build": "npm run build-md && npm run build-generate && npm run build-bundle && npm run build-mangle", |
|||
"build-bundle": "browserify index.json --bare -s characterEntitiesHTML4 > character-entities-html4.js", |
|||
"build-generate": "node build", |
|||
"build-mangle": "esmangle character-entities-html4.js > character-entities-html4.min.js", |
|||
"build-md": "remark . --quiet --frail", |
|||
"lint": "xo", |
|||
"test": "npm run build && npm run lint && npm run test-coverage", |
|||
"test-api": "node test", |
|||
"test-coverage": "nyc --reporter lcov tape test.js" |
|||
}, |
|||
"version": "1.1.0", |
|||
"xo": { |
|||
"space": true, |
|||
"ignores": [ |
|||
"character-entities-html4.js" |
|||
] |
|||
} |
|||
} |
@ -0,0 +1,3 @@ |
|||
{ |
|||
"presets": ["es2015"] |
|||
} |
@ -0,0 +1,170 @@ |
|||
### 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 behavoir 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 <COPYRIGHT HOLDER> 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. |
@ -1,19 +0,0 @@ |
|||
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 <COPYRIGHT HOLDER> 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. |
@ -1,124 +0,0 @@ |
|||
### Estraverse [![Build Status](https://secure.travis-ci.org/estools/estraverse.png)](http://travis-ci.org/estools/estraverse) |
|||
|
|||
Estraverse ([estraverse](http://github.com/estools/estraverse)) is |
|||
[ECMAScript](http://www.ecma-international.org/publications/standards/Ecma-262.htm) |
|||
traversal functions from [esmangle project](http://github.com/estools/esmangle). |
|||
|
|||
### Documentation |
|||
|
|||
You can find usage docs at [wiki page](https://github.com/estools/estraverse/wiki/Usage). |
|||
|
|||
### Example Usage |
|||
|
|||
The following code will output all variables declared at the root of a file. |
|||
|
|||
```javascript |
|||
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') |
|||
console.log(node.id.name); |
|||
} |
|||
}); |
|||
``` |
|||
|
|||
We can use `this.skip`, `this.remove` and `this.break` functions instead of using Skip, Remove and Break. |
|||
|
|||
```javascript |
|||
estraverse.traverse(ast, { |
|||
enter: function (node) { |
|||
this.break(); |
|||
} |
|||
}); |
|||
``` |
|||
|
|||
And estraverse provides `estraverse.replace` function. When returning node from `enter`/`leave`, current node is replaced with it. |
|||
|
|||
```javascript |
|||
result = estraverse.replace(tree, { |
|||
enter: function (node) { |
|||
// Replace it with replaced. |
|||
if (node.type === 'Literal') |
|||
return replaced; |
|||
} |
|||
}); |
|||
``` |
|||
|
|||
By passing `visitor.keys` mapping, we can extend estraverse traversing functionality. |
|||
|
|||
```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 |
|||
}; |
|||
estraverse.traverse(tree, { |
|||
enter: function (node) { }, |
|||
|
|||
// Extending the existing traversing rules. |
|||
keys: { |
|||
// TargetNodeName: [ 'keys', 'containing', 'the', 'other', '**node**' ] |
|||
TestExpression: ['argument'] |
|||
} |
|||
}); |
|||
``` |
|||
|
|||
By passing `visitor.fallback` option, we can control the behavior when encountering unknown nodes. |
|||
```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 |
|||
}; |
|||
estraverse.traverse(tree, { |
|||
enter: function (node) { }, |
|||
|
|||
// Iterating the child **nodes** of unknown nodes. |
|||
fallback: 'iteration' |
|||
}); |
|||
``` |
|||
|
|||
### License |
|||
|
|||
Copyright (C) 2012-2013 [Yusuke Suzuki](http://github.com/Constellation) |
|||
(twitter: [@Constellation](http://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 <COPYRIGHT HOLDER> 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. |
@ -1,843 +0,0 @@ |
|||
/* |
|||
Copyright (C) 2012-2013 Yusuke Suzuki <utatane.tea@gmail.com> |
|||
Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com> |
|||
|
|||
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 <COPYRIGHT HOLDER> 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. |
|||
*/ |
|||
/*jslint vars:false, bitwise:true*/ |
|||
/*jshint indent:4*/ |
|||
/*global exports:true*/ |
|||
(function clone(exports) { |
|||
'use strict'; |
|||
|
|||
var Syntax, |
|||
isArray, |
|||
VisitorOption, |
|||
VisitorKeys, |
|||
objectCreate, |
|||
objectKeys, |
|||
BREAK, |
|||
SKIP, |
|||
REMOVE; |
|||
|
|||
function ignoreJSHintError() { } |
|||
|
|||
isArray = Array.isArray; |
|||
if (!isArray) { |
|||
isArray = function isArray(array) { |
|||
return Object.prototype.toString.call(array) === '[object Array]'; |
|||
}; |
|||
} |
|||
|
|||
function deepCopy(obj) { |
|||
var ret = {}, key, val; |
|||
for (key in obj) { |
|||
if (obj.hasOwnProperty(key)) { |
|||
val = obj[key]; |
|||
if (typeof val === 'object' && val !== null) { |
|||
ret[key] = deepCopy(val); |
|||
} else { |
|||
ret[key] = val; |
|||
} |
|||
} |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
function shallowCopy(obj) { |
|||
var ret = {}, key; |
|||
for (key in obj) { |
|||
if (obj.hasOwnProperty(key)) { |
|||
ret[key] = obj[key]; |
|||
} |
|||
} |
|||
return ret; |
|||
} |
|||
ignoreJSHintError(shallowCopy); |
|||
|
|||
// based on LLVM libc++ upper_bound / lower_bound
|
|||
// MIT License
|
|||
|
|||
function upperBound(array, func) { |
|||
var diff, len, i, current; |
|||
|
|||
len = array.length; |
|||
i = 0; |
|||
|
|||
while (len) { |
|||
diff = len >>> 1; |
|||
current = i + diff; |
|||
if (func(array[current])) { |
|||
len = diff; |
|||
} else { |
|||
i = current + 1; |
|||
len -= diff + 1; |
|||
} |
|||
} |
|||
return i; |
|||
} |
|||
|
|||
function lowerBound(array, func) { |
|||
var diff, len, i, current; |
|||
|
|||
len = array.length; |
|||
i = 0; |
|||
|
|||
while (len) { |
|||
diff = len >>> 1; |
|||
current = i + diff; |
|||
if (func(array[current])) { |
|||
i = current + 1; |
|||
len -= diff + 1; |
|||
} else { |
|||
len = diff; |
|||
} |
|||
} |
|||
return i; |
|||
} |
|||
ignoreJSHintError(lowerBound); |
|||
|
|||
objectCreate = Object.create || (function () { |
|||
function F() { } |
|||
|
|||
return function (o) { |
|||
F.prototype = o; |
|||
return new F(); |
|||
}; |
|||
})(); |
|||
|
|||
objectKeys = Object.keys || function (o) { |
|||
var keys = [], key; |
|||
for (key in o) { |
|||
keys.push(key); |
|||
} |
|||
return keys; |
|||
}; |
|||
|
|||
function extend(to, from) { |
|||
var keys = objectKeys(from), key, i, len; |
|||
for (i = 0, len = keys.length; i < len; i += 1) { |
|||
key = keys[i]; |
|||
to[key] = from[key]; |
|||
} |
|||
return to; |
|||
} |
|||
|
|||
Syntax = { |
|||
AssignmentExpression: 'AssignmentExpression', |
|||
AssignmentPattern: 'AssignmentPattern', |
|||
ArrayExpression: 'ArrayExpression', |
|||
ArrayPattern: 'ArrayPattern', |
|||
ArrowFunctionExpression: 'ArrowFunctionExpression', |
|||
AwaitExpression: 'AwaitExpression', // CAUTION: It's deferred to ES7.
|
|||
BlockStatement: 'BlockStatement', |
|||
BinaryExpression: 'BinaryExpression', |
|||
BreakStatement: 'BreakStatement', |
|||
CallExpression: 'CallExpression', |
|||
CatchClause: 'CatchClause', |
|||
ClassBody: 'ClassBody', |
|||
ClassDeclaration: 'ClassDeclaration', |
|||
ClassExpression: 'ClassExpression', |
|||
ComprehensionBlock: 'ComprehensionBlock', // CAUTION: It's deferred to ES7.
|
|||
ComprehensionExpression: 'ComprehensionExpression', // CAUTION: It's deferred to ES7.
|
|||
ConditionalExpression: 'ConditionalExpression', |
|||
ContinueStatement: 'ContinueStatement', |
|||
DebuggerStatement: 'DebuggerStatement', |
|||
DirectiveStatement: 'DirectiveStatement', |
|||
DoWhileStatement: 'DoWhileStatement', |
|||
EmptyStatement: 'EmptyStatement', |
|||
ExportAllDeclaration: 'ExportAllDeclaration', |
|||
ExportDefaultDeclaration: 'ExportDefaultDeclaration', |
|||
ExportNamedDeclaration: 'ExportNamedDeclaration', |
|||
ExportSpecifier: 'ExportSpecifier', |
|||
ExpressionStatement: 'ExpressionStatement', |
|||
ForStatement: 'ForStatement', |
|||
ForInStatement: 'ForInStatement', |
|||
ForOfStatement: 'ForOfStatement', |
|||
FunctionDeclaration: 'FunctionDeclaration', |
|||
FunctionExpression: 'FunctionExpression', |
|||
GeneratorExpression: 'GeneratorExpression', // CAUTION: It's deferred to ES7.
|
|||
Identifier: 'Identifier', |
|||
IfStatement: 'IfStatement', |
|||
ImportDeclaration: 'ImportDeclaration', |
|||
ImportDefaultSpecifier: 'ImportDefaultSpecifier', |
|||
ImportNamespaceSpecifier: 'ImportNamespaceSpecifier', |
|||
ImportSpecifier: 'ImportSpecifier', |
|||
Literal: 'Literal', |
|||
LabeledStatement: 'LabeledStatement', |
|||
LogicalExpression: 'LogicalExpression', |
|||
MemberExpression: 'MemberExpression', |
|||
MetaProperty: 'MetaProperty', |
|||
MethodDefinition: 'MethodDefinition', |
|||
ModuleSpecifier: 'ModuleSpecifier', |
|||
NewExpression: 'NewExpression', |
|||
ObjectExpression: 'ObjectExpression', |
|||
ObjectPattern: 'ObjectPattern', |
|||
Program: 'Program', |
|||
Property: 'Property', |
|||
RestElement: 'RestElement', |
|||
ReturnStatement: 'ReturnStatement', |
|||
SequenceExpression: 'SequenceExpression', |
|||
SpreadElement: 'SpreadElement', |
|||
Super: 'Super', |
|||
SwitchStatement: 'SwitchStatement', |
|||
SwitchCase: 'SwitchCase', |
|||
TaggedTemplateExpression: 'TaggedTemplateExpression', |
|||
TemplateElement: 'TemplateElement', |
|||
TemplateLiteral: 'TemplateLiteral', |
|||
ThisExpression: 'ThisExpression', |
|||
ThrowStatement: 'ThrowStatement', |
|||
TryStatement: 'TryStatement', |
|||
UnaryExpression: 'UnaryExpression', |
|||
UpdateExpression: 'UpdateExpression', |
|||
VariableDeclaration: 'VariableDeclaration', |
|||
VariableDeclarator: 'VariableDeclarator', |
|||
WhileStatement: 'WhileStatement', |
|||
WithStatement: 'WithStatement', |
|||
YieldExpression: 'YieldExpression' |
|||
}; |
|||
|
|||
VisitorKeys = { |
|||
AssignmentExpression: ['left', 'right'], |
|||
AssignmentPattern: ['left', 'right'], |
|||
ArrayExpression: ['elements'], |
|||
ArrayPattern: ['elements'], |
|||
ArrowFunctionExpression: ['params', 'body'], |
|||
AwaitExpression: ['argument'], // CAUTION: It's deferred to ES7.
|
|||
BlockStatement: ['body'], |
|||
BinaryExpression: ['left', 'right'], |
|||
BreakStatement: ['label'], |
|||
CallExpression: ['callee', 'arguments'], |
|||
CatchClause: ['param', 'body'], |
|||
ClassBody: ['body'], |
|||
ClassDeclaration: ['id', 'superClass', 'body'], |
|||
ClassExpression: ['id', 'superClass', 'body'], |
|||
ComprehensionBlock: ['left', 'right'], // CAUTION: It's deferred to ES7.
|
|||
ComprehensionExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7.
|
|||
ConditionalExpression: ['test', 'consequent', 'alternate'], |
|||
ContinueStatement: ['label'], |
|||
DebuggerStatement: [], |
|||
DirectiveStatement: [], |
|||
DoWhileStatement: ['body', 'test'], |
|||
EmptyStatement: [], |
|||
ExportAllDeclaration: ['source'], |
|||
ExportDefaultDeclaration: ['declaration'], |
|||
ExportNamedDeclaration: ['declaration', 'specifiers', 'source'], |
|||
ExportSpecifier: ['exported', 'local'], |
|||
ExpressionStatement: ['expression'], |
|||
ForStatement: ['init', 'test', 'update', 'body'], |
|||
ForInStatement: ['left', 'right', 'body'], |
|||
ForOfStatement: ['left', 'right', 'body'], |
|||
FunctionDeclaration: ['id', 'params', 'body'], |
|||
FunctionExpression: ['id', 'params', 'body'], |
|||
GeneratorExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7.
|
|||
Identifier: [], |
|||
IfStatement: ['test', 'consequent', 'alternate'], |
|||
ImportDeclaration: ['specifiers', 'source'], |
|||
ImportDefaultSpecifier: ['local'], |
|||
ImportNamespaceSpecifier: ['local'], |
|||
ImportSpecifier: ['imported', 'local'], |
|||
Literal: [], |
|||
LabeledStatement: ['label', 'body'], |
|||
LogicalExpression: ['left', 'right'], |
|||
MemberExpression: ['object', 'property'], |
|||
MetaProperty: ['meta', 'property'], |
|||
MethodDefinition: ['key', 'value'], |
|||
ModuleSpecifier: [], |
|||
NewExpression: ['callee', 'arguments'], |
|||
ObjectExpression: ['properties'], |
|||
ObjectPattern: ['properties'], |
|||
Program: ['body'], |
|||
Property: ['key', 'value'], |
|||
RestElement: [ 'argument' ], |
|||
ReturnStatement: ['argument'], |
|||
SequenceExpression: ['expressions'], |
|||
SpreadElement: ['argument'], |
|||
Super: [], |
|||
SwitchStatement: ['discriminant', 'cases'], |
|||
SwitchCase: ['test', 'consequent'], |
|||
TaggedTemplateExpression: ['tag', 'quasi'], |
|||
TemplateElement: [], |
|||
TemplateLiteral: ['quasis', 'expressions'], |
|||
ThisExpression: [], |
|||
ThrowStatement: ['argument'], |
|||
TryStatement: ['block', 'handler', 'finalizer'], |
|||
UnaryExpression: ['argument'], |
|||
UpdateExpression: ['argument'], |
|||
VariableDeclaration: ['declarations'], |
|||
VariableDeclarator: ['id', 'init'], |
|||
WhileStatement: ['test', 'body'], |
|||
WithStatement: ['object', 'body'], |
|||
YieldExpression: ['argument'] |
|||
}; |
|||
|
|||
// unique id
|
|||
BREAK = {}; |
|||
SKIP = {}; |
|||
REMOVE = {}; |
|||
|
|||
VisitorOption = { |
|||
Break: BREAK, |
|||
Skip: SKIP, |
|||
Remove: REMOVE |
|||
}; |
|||
|
|||
function Reference(parent, key) { |
|||
this.parent = parent; |
|||
this.key = key; |
|||
} |
|||
|
|||
Reference.prototype.replace = function replace(node) { |
|||
this.parent[this.key] = node; |
|||
}; |
|||
|
|||
Reference.prototype.remove = function remove() { |
|||
if (isArray(this.parent)) { |
|||
this.parent.splice(this.key, 1); |
|||
return true; |
|||
} else { |
|||
this.replace(null); |
|||
return false; |
|||
} |
|||
}; |
|||
|
|||
function Element(node, path, wrap, ref) { |
|||
this.node = node; |
|||
this.path = path; |
|||
this.wrap = wrap; |
|||
this.ref = ref; |
|||
} |
|||
|
|||
function Controller() { } |
|||
|
|||
// API:
|
|||
// return property path array from root to current node
|
|||
Controller.prototype.path = function path() { |
|||
var i, iz, j, jz, result, element; |
|||
|
|||
function addToPath(result, path) { |
|||
if (isArray(path)) { |
|||
for (j = 0, jz = path.length; j < jz; ++j) { |
|||
result.push(path[j]); |
|||
} |
|||
} else { |
|||
result.push(path); |
|||
} |
|||
} |
|||
|
|||
// root node
|
|||
if (!this.__current.path) { |
|||
return null; |
|||
} |
|||
|
|||
// first node is sentinel, second node is root element
|
|||
result = []; |
|||
for (i = 2, iz = this.__leavelist.length; i < iz; ++i) { |
|||
element = this.__leavelist[i]; |
|||
addToPath(result, element.path); |
|||
} |
|||
addToPath(result, this.__current.path); |
|||
return result; |
|||
}; |
|||
|
|||
// API:
|
|||
// return type of current node
|
|||
Controller.prototype.type = function () { |
|||
var node = this.current(); |
|||
return node.type || this.__current.wrap; |
|||
}; |
|||
|
|||
// API:
|
|||
// return array of parent elements
|
|||
Controller.prototype.parents = function parents() { |
|||
var i, iz, result; |
|||
|
|||
// first node is sentinel
|
|||
result = []; |
|||
for (i = 1, iz = this.__leavelist.length; i < iz; ++i) { |
|||
result.push(this.__leavelist[i].node); |
|||
} |
|||
|
|||
return result; |
|||
}; |
|||
|
|||
// API:
|
|||
// return current node
|
|||
Controller.prototype.current = function current() { |
|||
return this.__current.node; |
|||
}; |
|||
|
|||
Controller.prototype.__execute = function __execute(callback, element) { |
|||
var previous, result; |
|||
|
|||
result = undefined; |
|||
|
|||
previous = this.__current; |
|||
this.__current = element; |
|||
this.__state = null; |
|||
if (callback) { |
|||
result = callback.call(this, element.node, this.__leavelist[this.__leavelist.length - 1].node); |
|||
} |
|||
this.__current = previous; |
|||
|
|||
return result; |
|||
}; |
|||
|
|||
// API:
|
|||
// notify control skip / break
|
|||
Controller.prototype.notify = function notify(flag) { |
|||
this.__state = flag; |
|||
}; |
|||
|
|||
// API:
|
|||
// skip child nodes of current node
|
|||
Controller.prototype.skip = function () { |
|||
this.notify(SKIP); |
|||
}; |
|||
|
|||
// API:
|
|||
// break traversals
|
|||
Controller.prototype['break'] = function () { |
|||
this.notify(BREAK); |
|||
}; |
|||
|
|||
// API:
|
|||
// remove node
|
|||
Controller.prototype.remove = function () { |
|||
this.notify(REMOVE); |
|||
}; |
|||
|
|||
Controller.prototype.__initialize = function(root, visitor) { |
|||
this.visitor = visitor; |
|||
this.root = root; |
|||
this.__worklist = []; |
|||
this.__leavelist = []; |
|||
this.__current = null; |
|||
this.__state = null; |
|||
this.__fallback = visitor.fallback === 'iteration'; |
|||
this.__keys = VisitorKeys; |
|||
if (visitor.keys) { |
|||
this.__keys = extend(objectCreate(this.__keys), visitor.keys); |
|||
} |
|||
}; |
|||
|
|||
function isNode(node) { |
|||
if (node == null) { |
|||
return false; |
|||
} |
|||
return typeof node === 'object' && typeof node.type === 'string'; |
|||
} |
|||
|
|||
function isProperty(nodeType, key) { |
|||
return (nodeType === Syntax.ObjectExpression || nodeType === Syntax.ObjectPattern) && 'properties' === key; |
|||
} |
|||
|
|||
Controller.prototype.traverse = function traverse(root, visitor) { |
|||
var worklist, |
|||
leavelist, |
|||
element, |
|||
node, |
|||
nodeType, |
|||
ret, |
|||
key, |
|||
current, |
|||
current2, |
|||
candidates, |
|||
candidate, |
|||
sentinel; |
|||
|
|||
this.__initialize(root, visitor); |
|||
|
|||
sentinel = {}; |
|||
|
|||
// reference
|
|||
worklist = this.__worklist; |
|||
leavelist = this.__leavelist; |
|||
|
|||
// initialize
|
|||
worklist.push(new Element(root, null, null, null)); |
|||
leavelist.push(new Element(null, null, null, null)); |
|||
|
|||
while (worklist.length) { |
|||
element = worklist.pop(); |
|||
|
|||
if (element === sentinel) { |
|||
element = leavelist.pop(); |
|||
|
|||
ret = this.__execute(visitor.leave, element); |
|||
|
|||
if (this.__state === BREAK || ret === BREAK) { |
|||
return; |
|||
} |
|||
continue; |
|||
} |
|||
|
|||
if (element.node) { |
|||
|
|||
ret = this.__execute(visitor.enter, element); |
|||
|
|||
if (this.__state === BREAK || ret === BREAK) { |
|||
return; |
|||
} |
|||
|
|||
worklist.push(sentinel); |
|||
leavelist.push(element); |
|||
|
|||
if (this.__state === SKIP || ret === SKIP) { |
|||
continue; |
|||
} |
|||
|
|||
node = element.node; |
|||
nodeType = node.type || element.wrap; |
|||
candidates = this.__keys[nodeType]; |
|||
if (!candidates) { |
|||
if (this.__fallback) { |
|||
candidates = objectKeys(node); |
|||
} else { |
|||
throw new Error('Unknown node type ' + nodeType + '.'); |
|||
} |
|||
} |
|||
|
|||
current = candidates.length; |
|||
while ((current -= 1) >= 0) { |
|||
key = candidates[current]; |
|||
candidate = node[key]; |
|||
if (!candidate) { |
|||
continue; |
|||
} |
|||
|
|||
if (isArray(candidate)) { |
|||
current2 = candidate.length; |
|||
while ((current2 -= 1) >= 0) { |
|||
if (!candidate[current2]) { |
|||
continue; |
|||
} |
|||
if (isProperty(nodeType, candidates[current])) { |
|||
element = new Element(candidate[current2], [key, current2], 'Property', null); |
|||
} else if (isNode(candidate[current2])) { |
|||
element = new Element(candidate[current2], [key, current2], null, null); |
|||
} else { |
|||
continue; |
|||
} |
|||
worklist.push(element); |
|||
} |
|||
} else if (isNode(candidate)) { |
|||
worklist.push(new Element(candidate, key, null, null)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
Controller.prototype.replace = function replace(root, visitor) { |
|||
function removeElem(element) { |
|||
var i, |
|||
key, |
|||
nextElem, |
|||
parent; |
|||
|
|||
if (element.ref.remove()) { |
|||
// When the reference is an element of an array.
|
|||
key = element.ref.key; |
|||
parent = element.ref.parent; |
|||
|
|||
// If removed from array, then decrease following items' keys.
|
|||
i = worklist.length; |
|||
while (i--) { |
|||
nextElem = worklist[i]; |
|||
if (nextElem.ref && nextElem.ref.parent === parent) { |
|||
if (nextElem.ref.key < key) { |
|||
break; |
|||
} |
|||
--nextElem.ref.key; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
var worklist, |
|||
leavelist, |
|||
node, |
|||
nodeType, |
|||
target, |
|||
element, |
|||
current, |
|||
current2, |
|||
candidates, |
|||
candidate, |
|||
sentinel, |
|||
outer, |
|||
key; |
|||
|
|||
this.__initialize(root, visitor); |
|||
|
|||
sentinel = {}; |
|||
|
|||
// reference
|
|||
worklist = this.__worklist; |
|||
leavelist = this.__leavelist; |
|||
|
|||
// initialize
|
|||
outer = { |
|||
root: root |
|||
}; |
|||
element = new Element(root, null, null, new Reference(outer, 'root')); |
|||
worklist.push(element); |
|||
leavelist.push(element); |
|||
|
|||
while (worklist.length) { |
|||
element = worklist.pop(); |
|||
|
|||
if (element === sentinel) { |
|||
element = leavelist.pop(); |
|||
|
|||
target = this.__execute(visitor.leave, element); |
|||
|
|||
// node may be replaced with null,
|
|||
// so distinguish between undefined and null in this place
|
|||
if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) { |
|||
// replace
|
|||
element.ref.replace(target); |
|||
} |
|||
|
|||
if (this.__state === REMOVE || target === REMOVE) { |
|||
removeElem(element); |
|||
} |
|||
|
|||
if (this.__state === BREAK || target === BREAK) { |
|||
return outer.root; |
|||
} |
|||
continue; |
|||
} |
|||
|
|||
target = this.__execute(visitor.enter, element); |
|||
|
|||
// node may be replaced with null,
|
|||
// so distinguish between undefined and null in this place
|
|||
if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) { |
|||
// replace
|
|||
element.ref.replace(target); |
|||
element.node = target; |
|||
} |
|||
|
|||
if (this.__state === REMOVE || target === REMOVE) { |
|||
removeElem(element); |
|||
element.node = null; |
|||
} |
|||
|
|||
if (this.__state === BREAK || target === BREAK) { |
|||
return outer.root; |
|||
} |
|||
|
|||
// node may be null
|
|||
node = element.node; |
|||
if (!node) { |
|||
continue; |
|||
} |
|||
|
|||
worklist.push(sentinel); |
|||
leavelist.push(element); |
|||
|
|||
if (this.__state === SKIP || target === SKIP) { |
|||
continue; |
|||
} |
|||
|
|||
nodeType = node.type || element.wrap; |
|||
candidates = this.__keys[nodeType]; |
|||
if (!candidates) { |
|||
if (this.__fallback) { |
|||
candidates = objectKeys(node); |
|||
} else { |
|||
throw new Error('Unknown node type ' + nodeType + '.'); |
|||
} |
|||
} |
|||
|
|||
current = candidates.length; |
|||
while ((current -= 1) >= 0) { |
|||
key = candidates[current]; |
|||
candidate = node[key]; |
|||
if (!candidate) { |
|||
continue; |
|||
} |
|||
|
|||
if (isArray(candidate)) { |
|||
current2 = candidate.length; |
|||
while ((current2 -= 1) >= 0) { |
|||
if (!candidate[current2]) { |
|||
continue; |
|||
} |
|||
if (isProperty(nodeType, candidates[current])) { |
|||
element = new Element(candidate[current2], [key, current2], 'Property', new Reference(candidate, current2)); |
|||
} else if (isNode(candidate[current2])) { |
|||
element = new Element(candidate[current2], [key, current2], null, new Reference(candidate, current2)); |
|||
} else { |
|||
continue; |
|||
} |
|||
worklist.push(element); |
|||
} |
|||
} else if (isNode(candidate)) { |
|||
worklist.push(new Element(candidate, key, null, new Reference(node, key))); |
|||
} |
|||
} |
|||
} |
|||
|
|||
return outer.root; |
|||
}; |
|||
|
|||
function traverse(root, visitor) { |
|||
var controller = new Controller(); |
|||
return controller.traverse(root, visitor); |
|||
} |
|||
|
|||
function replace(root, visitor) { |
|||
var controller = new Controller(); |
|||
return controller.replace(root, visitor); |
|||
} |
|||
|
|||
function extendCommentRange(comment, tokens) { |
|||
var target; |
|||
|
|||
target = upperBound(tokens, function search(token) { |
|||
return token.range[0] > comment.range[0]; |
|||
}); |
|||
|
|||
comment.extendedRange = [comment.range[0], comment.range[1]]; |
|||
|
|||
if (target !== tokens.length) { |
|||
comment.extendedRange[1] = tokens[target].range[0]; |
|||
} |
|||
|
|||
target -= 1; |
|||
if (target >= 0) { |
|||
comment.extendedRange[0] = tokens[target].range[1]; |
|||
} |
|||
|
|||
return comment; |
|||
} |
|||
|
|||
function attachComments(tree, providedComments, tokens) { |
|||
// At first, we should calculate extended comment ranges.
|
|||
var comments = [], comment, len, i, cursor; |
|||
|
|||
if (!tree.range) { |
|||
throw new Error('attachComments needs range information'); |
|||
} |
|||
|
|||
// tokens array is empty, we attach comments to tree as 'leadingComments'
|
|||
if (!tokens.length) { |
|||
if (providedComments.length) { |
|||
for (i = 0, len = providedComments.length; i < len; i += 1) { |
|||
comment = deepCopy(providedComments[i]); |
|||
comment.extendedRange = [0, tree.range[0]]; |
|||
comments.push(comment); |
|||
} |
|||
tree.leadingComments = comments; |
|||
} |
|||
return tree; |
|||
} |
|||
|
|||
for (i = 0, len = providedComments.length; i < len; i += 1) { |
|||
comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens)); |
|||
} |
|||
|
|||
// This is based on John Freeman's implementation.
|
|||
cursor = 0; |
|||
traverse(tree, { |
|||
enter: function (node) { |
|||
var comment; |
|||
|
|||
while (cursor < comments.length) { |
|||
comment = comments[cursor]; |
|||
if (comment.extendedRange[1] > node.range[0]) { |
|||
break; |
|||
} |
|||
|
|||
if (comment.extendedRange[1] === node.range[0]) { |
|||
if (!node.leadingComments) { |
|||
node.leadingComments = []; |
|||
} |
|||
node.leadingComments.push(comment); |
|||
comments.splice(cursor, 1); |
|||
} else { |
|||
cursor += 1; |
|||
} |
|||
} |
|||
|
|||
// already out of owned node
|
|||
if (cursor === comments.length) { |
|||
return VisitorOption.Break; |
|||
} |
|||
|
|||
if (comments[cursor].extendedRange[0] > node.range[1]) { |
|||
return VisitorOption.Skip; |
|||
} |
|||
} |
|||
}); |
|||
|
|||
cursor = 0; |
|||
traverse(tree, { |
|||
leave: function (node) { |
|||
var comment; |
|||
|
|||
while (cursor < comments.length) { |
|||
comment = comments[cursor]; |
|||
if (node.range[1] < comment.extendedRange[0]) { |
|||
break; |
|||
} |
|||
|
|||
if (node.range[1] === comment.extendedRange[0]) { |
|||
if (!node.trailingComments) { |
|||
node.trailingComments = []; |
|||
} |
|||
node.trailingComments.push(comment); |
|||
comments.splice(cursor, 1); |
|||
} else { |
|||
cursor += 1; |
|||
} |
|||
} |
|||
|
|||
// already out of owned node
|
|||
if (cursor === comments.length) { |
|||
return VisitorOption.Break; |
|||
} |
|||
|
|||
if (comments[cursor].extendedRange[0] > node.range[1]) { |
|||
return VisitorOption.Skip; |
|||
} |
|||
} |
|||
}); |
|||
|
|||
return tree; |
|||
} |
|||
|
|||
exports.version = require('./package.json').version; |
|||
exports.Syntax = Syntax; |
|||
exports.traverse = traverse; |
|||
exports.replace = replace; |
|||
exports.attachComments = attachComments; |
|||
exports.VisitorKeys = VisitorKeys; |
|||
exports.VisitorOption = VisitorOption; |
|||
exports.Controller = Controller; |
|||
exports.cloneEnvironment = function () { return clone({}); }; |
|||
|
|||
return exports; |
|||
}(exports)); |
|||
/* vim: set sw=4 ts=4 et tw=80 : */ |
@ -1,100 +0,0 @@ |
|||
{ |
|||
"_args": [ |
|||
[ |
|||
{ |
|||
"raw": "estraverse@~4.1.0", |
|||
"scope": null, |
|||
"escapedName": "estraverse", |
|||
"name": "estraverse", |
|||
"rawSpec": "~4.1.0", |
|||
"spec": ">=4.1.0 <4.2.0", |
|||
"type": "range" |
|||
}, |
|||
"/Users/trott/io.js/tools/node_modules/esrecurse" |
|||
] |
|||
], |
|||
"_from": "estraverse@>=4.1.0 <4.2.0", |
|||
"_id": "estraverse@4.1.1", |
|||
"_inCache": true, |
|||
"_location": "/esrecurse/estraverse", |
|||
"_nodeVersion": "4.1.1", |
|||
"_npmUser": { |
|||
"name": "constellation", |
|||
"email": "utatane.tea@gmail.com" |
|||
}, |
|||
"_npmVersion": "2.14.4", |
|||
"_phantomChildren": {}, |
|||
"_requested": { |
|||
"raw": "estraverse@~4.1.0", |
|||
"scope": null, |
|||
"escapedName": "estraverse", |
|||
"name": "estraverse", |
|||
"rawSpec": "~4.1.0", |
|||
"spec": ">=4.1.0 <4.2.0", |
|||
"type": "range" |
|||
}, |
|||
"_requiredBy": [ |
|||
"/esrecurse" |
|||
], |
|||
"_resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz", |
|||
"_shasum": "f6caca728933a850ef90661d0e17982ba47111a2", |
|||
"_shrinkwrap": null, |
|||
"_spec": "estraverse@~4.1.0", |
|||
"_where": "/Users/trott/io.js/tools/node_modules/esrecurse", |
|||
"bugs": { |
|||
"url": "https://github.com/estools/estraverse/issues" |
|||
}, |
|||
"dependencies": {}, |
|||
"description": "ECMAScript JS AST traversal functions", |
|||
"devDependencies": { |
|||
"chai": "^2.1.1", |
|||
"coffee-script": "^1.8.0", |
|||
"espree": "^1.11.0", |
|||
"gulp": "^3.8.10", |
|||
"gulp-bump": "^0.2.2", |
|||
"gulp-filter": "^2.0.0", |
|||
"gulp-git": "^1.0.1", |
|||
"gulp-tag-version": "^1.2.1", |
|||
"jshint": "^2.5.6", |
|||
"mocha": "^2.1.0" |
|||
}, |
|||
"directories": {}, |
|||
"dist": { |
|||
"shasum": "f6caca728933a850ef90661d0e17982ba47111a2", |
|||
"tarball": "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz" |
|||
}, |
|||
"engines": { |
|||
"node": ">=0.10.0" |
|||
}, |
|||
"gitHead": "bbcccbfe98296585e4311c8755e1d00dcd581e3c", |
|||
"homepage": "https://github.com/estools/estraverse", |
|||
"license": "BSD-2-Clause", |
|||
"main": "estraverse.js", |
|||
"maintainers": [ |
|||
{ |
|||
"name": "constellation", |
|||
"email": "utatane.tea@gmail.com" |
|||
}, |
|||
{ |
|||
"name": "michaelficarra", |
|||
"email": "npm@michael.ficarra.me" |
|||
}, |
|||
{ |
|||
"name": "nzakas", |
|||
"email": "nicholas@nczconsulting.com" |
|||
} |
|||
], |
|||
"name": "estraverse", |
|||
"optionalDependencies": {}, |
|||
"readme": "ERROR: No README data found!", |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "git+ssh://git@github.com/estools/estraverse.git" |
|||
}, |
|||
"scripts": { |
|||
"lint": "jshint estraverse.js", |
|||
"test": "npm run-script lint && npm run-script unit-test", |
|||
"unit-test": "mocha --compilers coffee:coffee-script/register" |
|||
}, |
|||
"version": "4.1.1" |
|||
} |
File diff suppressed because it is too large
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue