estraverse
Advanced tools
Comparing version 1.6.0 to 1.7.0
@@ -47,2 +47,4 @@ /* | ||
VisitorKeys, | ||
objectCreate, | ||
objectKeys, | ||
BREAK, | ||
@@ -129,2 +131,26 @@ SKIP, | ||
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) { | ||
objectKeys(from).forEach(function (key) { | ||
to[key] = from[key]; | ||
}); | ||
return to; | ||
} | ||
Syntax = { | ||
@@ -143,4 +169,4 @@ AssignmentExpression: 'AssignmentExpression', | ||
ClassExpression: 'ClassExpression', | ||
/* CAUTION: It's deferred to ES7. */ ComprehensionBlock: 'ComprehensionBlock', | ||
/* CAUTION: It's deferred to ES7. */ ComprehensionExpression: 'ComprehensionExpression', | ||
ComprehensionBlock: 'ComprehensionBlock', // CAUTION: It's deferred to ES7. | ||
ComprehensionExpression: 'ComprehensionExpression', // CAUTION: It's deferred to ES7. | ||
ConditionalExpression: 'ConditionalExpression', | ||
@@ -161,3 +187,3 @@ ContinueStatement: 'ContinueStatement', | ||
FunctionExpression: 'FunctionExpression', | ||
/* CAUTION: It's deferred to ES7. */ GeneratorExpression: 'GeneratorExpression', | ||
GeneratorExpression: 'GeneratorExpression', // CAUTION: It's deferred to ES7. | ||
Identifier: 'Identifier', | ||
@@ -213,4 +239,4 @@ IfStatement: 'IfStatement', | ||
ClassExpression: ['id', 'body', 'superClass'], | ||
/* CAUTION: It's deferred to ES7. */ ComprehensionBlock: ['left', 'right'], | ||
/* CAUTION: It's deferred to ES7. */ ComprehensionExpression: ['blocks', 'filter', 'body'], | ||
ComprehensionBlock: ['left', 'right'], // CAUTION: It's deferred to ES7. | ||
ComprehensionExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7. | ||
ConditionalExpression: ['test', 'consequent', 'alternate'], | ||
@@ -231,3 +257,3 @@ ContinueStatement: ['label'], | ||
FunctionExpression: ['id', 'params', 'defaults', 'rest', 'body'], | ||
/* CAUTION: It's deferred to ES7. */ GeneratorExpression: ['blocks', 'filter', 'body'], | ||
GeneratorExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7. | ||
Identifier: [], | ||
@@ -295,3 +321,3 @@ IfStatement: ['test', 'consequent', 'alternate'], | ||
} else { | ||
this.parent.replace(null); | ||
this.replace(null); | ||
return false; | ||
@@ -407,4 +433,20 @@ } | ||
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) { | ||
@@ -467,3 +509,10 @@ var worklist, | ||
nodeType = element.wrap || node.type; | ||
candidates = VisitorKeys[nodeType]; | ||
candidates = this.__keys[nodeType]; | ||
if (!candidates) { | ||
if (this.__fallback) { | ||
candidates = objectKeys(node); | ||
} else { | ||
throw new Error('Unknown node type ' + nodeType + '.'); | ||
} | ||
} | ||
@@ -478,19 +527,20 @@ current = candidates.length; | ||
if (!isArray(candidate)) { | ||
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)); | ||
continue; | ||
} | ||
current2 = candidate.length; | ||
while ((current2 -= 1) >= 0) { | ||
if (!candidate[current2]) { | ||
continue; | ||
} | ||
if ((nodeType === Syntax.ObjectExpression || nodeType === Syntax.ObjectPattern) && 'properties' === candidates[current]) { | ||
element = new Element(candidate[current2], [key, current2], 'Property', null); | ||
} else { | ||
element = new Element(candidate[current2], [key, current2], null, null); | ||
} | ||
worklist.push(element); | ||
} | ||
} | ||
@@ -503,9 +553,13 @@ } | ||
function removeElem() { | ||
var i, nextElem; | ||
var i, | ||
nextElem, | ||
parent; | ||
if (element.ref.remove()) { | ||
parent = element.ref.parent; | ||
// if removed from array, then shift following items' keys | ||
for (i = 1; i < worklist.length; i++) { | ||
nextElem = worklist[i]; | ||
if (nextElem.ref.parent !== element.ref.parent) { | ||
if (nextElem === sentinel || nextElem.ref.parent !== parent) { | ||
break; | ||
@@ -606,3 +660,10 @@ } | ||
nodeType = element.wrap || node.type; | ||
candidates = VisitorKeys[nodeType]; | ||
candidates = this.__keys[nodeType]; | ||
if (!candidates) { | ||
if (this.__fallback) { | ||
candidates = objectKeys(node); | ||
} else { | ||
throw new Error('Unknown node type ' + nodeType + '.'); | ||
} | ||
} | ||
@@ -617,19 +678,20 @@ current = candidates.length; | ||
if (!isArray(candidate)) { | ||
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))); | ||
continue; | ||
} | ||
current2 = candidate.length; | ||
while ((current2 -= 1) >= 0) { | ||
if (!candidate[current2]) { | ||
continue; | ||
} | ||
if (nodeType === Syntax.ObjectExpression && 'properties' === candidates[current]) { | ||
element = new Element(candidate[current2], [key, current2], 'Property', new Reference(candidate, current2)); | ||
} else { | ||
element = new Element(candidate[current2], [key, current2], null, new Reference(candidate, current2)); | ||
} | ||
worklist.push(element); | ||
} | ||
} | ||
@@ -636,0 +698,0 @@ } |
@@ -6,3 +6,3 @@ { | ||
"main": "estraverse.js", | ||
"version": "1.6.0", | ||
"version": "1.7.0", | ||
"engines": { | ||
@@ -23,6 +23,6 @@ "node": ">=0.10.0" | ||
"devDependencies": { | ||
"mocha": "~1.12.0", | ||
"chai": "~1.7.2", | ||
"jshint": "2.1.5", | ||
"coffee-script": "~1.6.3", | ||
"mocha": "^1.21.5", | ||
"chai": "^1.9.2", | ||
"jshint": "^2.5.6", | ||
"coffee-script": "^1.8.0", | ||
"xyz": "^0.4.0" | ||
@@ -39,3 +39,3 @@ }, | ||
"lint": "jshint estraverse.js", | ||
"unit-test": "mocha --compilers coffee:coffee-script", | ||
"unit-test": "mocha --compilers coffee:coffee-script/register", | ||
"release-major": "xyz --increment major --tag X.Y.Z", | ||
@@ -42,0 +42,0 @@ "release-minor": "xyz --increment minor --tag X.Y.Z", |
@@ -50,2 +50,52 @@ ### Estraverse [![Build Status](https://secure.travis-ci.org/Constellation/estraverse.png)](http://travis-ci.org/Constellation/estraverse) | ||
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 exising 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 | ||
@@ -52,0 +102,0 @@ |
33731
711
125