Socket
Socket
Sign inDemoInstall

ast-types

Package Overview
Dependencies
Maintainers
1
Versions
172
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ast-types - npm Package Compare versions

Comparing version 0.3.38 to 0.4.0

lib/path-visitor.js

10

lib/node-path.js

@@ -21,2 +21,3 @@ var assert = require("assert");

Object.defineProperty(this, "node", {
configurable: true, // Enable deletion.
value: this._computeNode()

@@ -32,2 +33,3 @@ });

Object.defineProperty(this, "parent", {
configurable: true, // Enable deletion.
value: this._computeParent()

@@ -43,2 +45,3 @@ });

Object.defineProperty(this, "scope", {
configurable: true, // Enable deletion.
value: this._computeScope()

@@ -52,2 +55,9 @@ });

NPp.replace = function() {
delete this.node;
delete this.parent;
delete this.scope;
return Path.prototype.replace.apply(this, arguments);
};
// The value of the first ancestor Path whose value is a Node.

@@ -54,0 +64,0 @@ NPp._computeNode = function() {

108

lib/path.js

@@ -33,3 +33,3 @@ var assert = require("assert");

// child Path object, for both performance and consistency reasons.
this.__childCache = {};
this.__childCache = Object.create(null);
}

@@ -118,43 +118,28 @@

Pp.replace = function(replacement) {
var count = arguments.length;
assert.ok(
this.parentPath instanceof Path,
"Instead of replacing the root of the tree, create a new tree."
);
var name = this.name;
var results = [];
var parentValue = this.parentPath.value;
var parentCache = this.parentPath.__childCache;
var results = [];
var count = arguments.length;
if (toString.call(parentValue) === arrayToString) {
var i;
var newIndex;
var originalLength = parentValue.length;
var moved = Object.create(null);
if (this.value !== parentCache[name].value) {
if (parentValue[this.name] !== this.value) {
// Something caused our index (name) to become out of date.
for (i = 0; i < parentValue.length; ++i) {
if (parentValue[i] === this.value) {
this.name = name = i;
break;
}
var i = parentValue.indexOf(this.value);
if (i >= 0) {
parentCache[this.name = i] = this;
}
assert.ok(
this.value === parentCache[name].value,
"Cannot replace already replaced node: " + this.value.type
);
}
delete parentCache.length;
delete parentCache[name];
assert.strictEqual(parentValue[this.name], this.value);
assert.strictEqual(this.parentPath.get(this.name), this);
var moved = {};
for (i = name + 1; i < parentValue.length; ++i) {
var child = parentCache[i];
if (child) {
newIndex = i - 1 + count;
moved[newIndex] = child;
Object.defineProperty(child, "name", { value: newIndex });
for (var i = this.name + 1; i < originalLength; ++i) {
if (hasOwn.call(parentCache, i)) {
var childPath = parentCache[i];
var newIndex = i - 1 + count;
moved[newIndex] = childPath;
childPath.name = newIndex;
delete parentCache[i];

@@ -164,27 +149,58 @@ }

var args = slice.call(arguments);
args.unshift(name, 1);
parentValue.splice.apply(parentValue, args);
delete parentCache.length;
var spliceArgs = [this.name, 1];
for (i = 0; i < count; ++i) {
spliceArgs.push(arguments[i]);
}
var splicedOut = parentValue.splice.apply(parentValue, spliceArgs);
assert.strictEqual(splicedOut[0], this.value);
assert.strictEqual(
parentValue.length,
originalLength - 1 + count
);
for (newIndex in moved) {
if (hasOwn.call(moved, newIndex)) {
parentCache[newIndex] = moved[newIndex];
}
parentCache[newIndex] = moved[newIndex];
}
for (i = name; i < name + count; ++i) {
results.push(this.parentPath.get(i));
if (count === 0) {
delete this.value;
delete parentCache[this.name];
this.__childCache = {};
} else {
assert.strictEqual(parentValue[this.name], replacement);
if (this.value !== replacement) {
this.value = replacement;
this.__childCache = {};
}
for (i = 0; i < count; ++i) {
results.push(this.parentPath.get(this.name + i));
}
assert.strictEqual(results[0], this);
}
} else if (count === 1) {
delete parentCache[name];
parentValue[name] = replacement;
results.push(this.parentPath.get(name));
if (this.value !== replacement) {
this.__childCache = {};
}
this.value = parentValue[this.name] = replacement;
results.push(this);
} else if (count === 0) {
delete parentCache[name];
delete parentValue[name];
delete parentValue[this.name];
delete this.value;
this.__childCache = {};
// Leave this path cached as parentCache[this.name], even though
// it no longer has a value defined.
} else {
assert.ok(false, "Could not replace Path.");
assert.ok(false, "Could not replace path");
}

@@ -191,0 +207,0 @@

@@ -1,102 +0,27 @@

var assert = require("assert");
var types = require("./types");
var Node = types.namedTypes.Node;
var isObject = types.builtInTypes.object;
var isArray = types.builtInTypes.array;
var NodePath = require("./node-path");
var funToStr = Function.prototype.toString;
var thisPattern = /\bthis\b/;
var visit = require("./path-visitor").visit;
var warnedAboutDeprecation = false;
// Good for traversals that need to modify the syntax tree or to access
// path/scope information via `this` (a NodePath object). Somewhat slower
// than traverseWithNoPathInfo because of the NodePath bookkeeping.
function traverseWithFullPathInfo(node, callback) {
if (!thisPattern.test(funToStr.call(callback))) {
// If the callback function contains no references to `this`, then
// it will have no way of using any of the NodePath information
// that traverseWithFullPathInfo provides, so we can skip that
// bookkeeping altogether.
return traverseWithNoPathInfo(
node instanceof NodePath ? node.value : node,
callback
if (!warnedAboutDeprecation) {
warnedAboutDeprecation = true;
console.warn(
"\033[33m", // yellow
'DEPRECATED(ast-types): Please use require("ast-types").visit ' +
"instead of .traverse for syntax tree manipulation." +
"\033[0m" // reset
);
}
function traverse(path) {
assert.ok(path instanceof NodePath);
var value = path.value;
if (isArray.check(value)) {
path.each(traverse);
return;
}
if (Node.check(value)) {
if (callback.call(path, value, traverse) === false) {
return;
return visit(node, {
visitNode: function(path) {
if (callback.call(path, path.value) !== false) {
this.traverse(path);
}
} else if (!isObject.check(value)) {
return;
}
types.eachField(value, function(name, child) {
var childPath = path.get(name);
if (childPath.value !== child) {
childPath.replace(child);
}
traverse(childPath);
});
}
if (node instanceof NodePath) {
traverse(node);
return node.value;
}
// Just in case we call this.replace at the root, there needs to be an
// additional parent Path to update.
var rootPath = new NodePath({ root: node });
traverse(rootPath.get("root"));
return rootPath.value.root;
}
// Good for read-only traversals that do not require any NodePath
// information. Faster than traverseWithFullPathInfo because less
// information is exposed. A context parameter is supported because `this`
// no longer has to be a NodePath object.
function traverseWithNoPathInfo(node, callback, context) {
Node.assert(node);
context = context || null;
function traverse(node) {
if (isArray.check(node)) {
node.forEach(traverse);
return;
return false;
}
if (Node.check(node)) {
if (callback.call(context, node, traverse) === false) {
return;
}
} else if (!isObject.check(node)) {
return;
}
types.eachField(node, function(name, child) {
traverse(child);
});
}
traverse(node);
return node;
});
}
// Since we export traverseWithFullPathInfo as module.exports, we need to
// attach traverseWithNoPathInfo to it as a property. In other words, you
// should use require("ast-types").traverse.fast(ast, ...) to invoke the
// quick-and-dirty traverseWithNoPathInfo function.
traverseWithFullPathInfo.fast = traverseWithNoPathInfo;
traverseWithFullPathInfo.fast = traverseWithFullPathInfo;
module.exports = traverseWithFullPathInfo;

@@ -29,2 +29,3 @@ var types = require("./lib/types");

exports.NodePath = require("./lib/node-path");
exports.computeSupertypeLookupTable = types.computeSupertypeLookupTable;
exports.PathVisitor = require("./lib/path-visitor");
exports.visit = exports.PathVisitor.visit;

@@ -21,3 +21,3 @@ {

],
"version": "0.3.38",
"version": "0.4.0",
"homepage": "http://github.com/benjamn/ast-types",

@@ -33,8 +33,5 @@ "repository": {

},
"dependencies": {
"private": "~0.1.2"
},
"devDependencies": {
"esprima": "~1.1.1",
"mocha": "~1.16.2"
"esprima": "~1.2.2",
"mocha": "~1.20.1"
},

@@ -41,0 +38,0 @@ "engines": {

@@ -12,2 +12,3 @@ var assert = require("assert");

var NodePath = require("../lib/node-path");
var PathVisitor = require("../lib/path-visitor");

@@ -53,3 +54,3 @@ describe("basic type checking", function() {

it("should resolve the most precise supertypes", function() {
var table = types.computeSupertypeLookupTable({
var table = require("../lib/types").computeSupertypeLookupTable({
Function: true,

@@ -588,3 +589,3 @@ Declaration: true,

if (n.VariableDeclaration.check(node)) {
var scopeBody = this.scope.path.get("body").get("body");
var scopeBody = this.scope.path.get("body", "body");

@@ -617,4 +618,6 @@ // This is contrived such that we just happen to be replacing

assert.strictEqual(scopeBody.get(0), this);
// Then replace the node, not the one we just added.
this.replace(b.returnStatement(b.identifier("$$")));
this.replace(b.returnStatement(b.identifier("$3")));
}

@@ -626,21 +629,31 @@ });

statements.map(function(node) { return node.type; }),
['VariableDeclaration', 'VariableDeclaration', 'ReturnStatement']
['ReturnStatement', 'VariableDeclaration', 'VariableDeclaration']
);
assert.ok(n.VariableDeclaration.check(statements[0]), "not a variable declaration: " + statements[0].type);
assert.equal(statements[0].declarations[0].id.name, "$2");
assert.ok(n.VariableDeclaration.check(statements[1]), "not a variable declaration: " + statements[1].type);
n.ReturnStatement.assert(statements[0]);
assert.equal(statements[0].argument.name, "$3");
n.VariableDeclaration.assert(statements[1]);
assert.equal(statements[1].declarations[0].id.name, "$$");
assert.ok(n.ReturnStatement.check(statements[2]), "not a return statement: " + statements[2].type);
assert.equal(statements[2].argument.name, "$$");
n.VariableDeclaration.assert(statements[2]);
assert.equal(statements[2].declarations[0].id.name, "a");
});
it("should throw when trying to replace the same node twice", function() {
it("should not throw when replacing the same node twice", function() {
types.traverse(ast, function(node) {
if (n.VariableDeclaration.check(node)) {
this.replace(b.expressionStatement(b.literal(null)));
n.ExpressionStatement.assert(this.value);
n.Literal.assert(this.value.expression);
assert.strictEqual(this.value.expression.value, null);
var self = this;
assert.throws(function() {
self.replace(b.expressionStatement(b.literal('NOPE')));
}, /Cannot replace already replaced node: VariableDeclaration/);
this.replace(b.expressionStatement(b.literal("OK")));
n.ExpressionStatement.assert(this.value);
n.Literal.assert(this.value.expression);
assert.strictEqual(this.value.expression.value, "OK");
if (this.parentPath.get(this.name) !== this) {
assert.ok(false, "Should have reused the same path");
}
}

@@ -823,1 +836,316 @@ });

});
describe("types.visit", function() {
var objProp;
beforeEach(function() {
objProp = b.memberExpression(
b.identifier("object"),
b.identifier("property"),
false
);
});
it("should be identical to PathVisitor.visit", function() {
assert.strictEqual(types.visit, PathVisitor.visit);
});
it("should work with no visitors", function() {
var foo = b.identifier("foo");
assert.strictEqual(types.visit(foo), foo);
});
it("should allow simple tree modifications", function() {
var bar = types.visit(b.identifier("foo"), {
visitIdentifier: function(path) {
assert.ok(path instanceof NodePath);
path.value.name = "bar";
return false;
}
});
n.Identifier.assert(bar);
assert.strictEqual(bar.name, "bar");
});
it("should complain about missing this.traverse", function() {
try {
types.visit(objProp, {
visitIdentifier: function(path) {
// buh?
}
});
assert.ok(false, "should have thrown an exception");
} catch (err) {
assert.strictEqual(
err.message,
"Must either call this.traverse or return false in visitIdentifier"
);
}
});
it("should support this.traverse", function() {
var idNames = [];
types.visit(objProp, {
visitMemberExpression: function(path) {
this.traverse(path, {
visitIdentifier: function(path) {
idNames.push("*" + path.value.name + "*");
return false;
}
});
path.get("object", "name").replace("asdfasdf");
path.get("property", "name").replace("zxcvzxcv");
this.visitor.visit(path.get("property"));
},
visitIdentifier: function(path) {
idNames.push(path.value.name);
return false;
}
});
assert.deepEqual(idNames, ["*object*", "*property*", "zxcvzxcv"]);
idNames.length = 0;
types.visit(objProp, {
visitMemberExpression: function(path) {
path.get("object", "name").replace("asdfasdf");
path.get("property", "name").replace("zxcvzxcv");
this.traverse(path, {
visitIdentifier: function(path) {
idNames.push(path.value.name);
return false;
}
});
}
});
assert.deepEqual(idNames, ["asdfasdf", "zxcvzxcv"]);
});
it("should support this.replace", function() {
var seqExpr = b.sequenceExpression([
b.literal("asdf"),
b.identifier("zxcv"),
b.thisExpression()
]);
types.visit(seqExpr, {
visitIdentifier: function(path) {
assert.strictEqual(path.value.name, "zxcv");
path.replace(
b.identifier("foo"),
b.identifier("bar")
);
return false;
}
});
assert.strictEqual(seqExpr.expressions.length, 4);
var foo = seqExpr.expressions[1];
n.Identifier.assert(foo);
assert.strictEqual(foo.name, "foo");
var bar = seqExpr.expressions[2];
n.Identifier.assert(bar);
assert.strictEqual(bar.name, "bar");
types.visit(seqExpr, {
visitIdentifier: function(path) {
if (path.value.name === "foo") {
path.replace(path.value, path.value);
}
return false;
}
});
assert.strictEqual(seqExpr.expressions.length, 5);
var foo = seqExpr.expressions[1];
n.Identifier.assert(foo);
assert.strictEqual(foo.name, "foo");
var foo = seqExpr.expressions[2];
n.Identifier.assert(foo);
assert.strictEqual(foo.name, "foo");
var bar = seqExpr.expressions[3];
n.Identifier.assert(bar);
assert.strictEqual(bar.name, "bar");
types.visit(seqExpr, {
visitLiteral: function(path) {
path.replace();
return false;
},
visitIdentifier: function(path) {
if (path.value.name === "bar") {
path.replace();
}
return false;
}
});
assert.strictEqual(seqExpr.expressions.length, 3);
var first = seqExpr.expressions[0];
n.Identifier.assert(first);
assert.strictEqual(first.name, "foo");
var second = seqExpr.expressions[1];
assert.strictEqual(second, first);
var third = seqExpr.expressions[2];
n.ThisExpression.assert(third);
});
it("should reuse old VisitorContext objects", function() {
var objectContext;
var propertyContext;
types.visit(objProp, {
visitIdentifier: function(path) {
assert.strictEqual(this.needToCallTraverse, true);
this.traverse(path);
assert.strictEqual(path.name, path.value.name);
if (path.name === "object") {
objectContext = this;
} else if (path.name === "property") {
propertyContext = this;
}
}
});
assert.ok(objectContext);
assert.ok(propertyContext);
assert.strictEqual(objectContext, propertyContext);
});
it("should dispatch to closest visitSupertype method", function() {
var foo = b.identifier("foo");
var bar = b.identifier("bar");
var callExpr = b.callExpression(
b.memberExpression(
b.functionExpression(
b.identifier("add"),
[foo, bar],
b.blockStatement([
b.returnStatement(
b.binaryExpression("+", foo, bar)
)
])
),
b.identifier("bind"),
false
),
[b.thisExpression()]
);
var nodes = [];
var expressions = [];
var identifiers = [];
var statements = [];
var returnStatements = [];
var functions = [];
function makeVisitorMethod(array) {
return function(path) {
array.push(path.value);
this.traverse(path);
};
}
types.visit(callExpr, {
visitNode: makeVisitorMethod(nodes),
visitExpression: makeVisitorMethod(expressions),
visitIdentifier: makeVisitorMethod(identifiers),
visitStatement: makeVisitorMethod(statements),
visitReturnStatement: makeVisitorMethod(returnStatements),
visitFunction: makeVisitorMethod(functions)
});
function check(array) {
var rest = Array.prototype.slice.call(arguments, 1);
assert.strictEqual(array.length, rest.length);
for (var i = 0; i < rest.length; ++i) {
assert.strictEqual(array[i], rest[i]);
}
}
check(nodes);
check(expressions,
callExpr,
callExpr.callee,
callExpr.callee.object.body.body[0].argument,
callExpr.arguments[0]);
check(identifiers,
callExpr.callee.object.id,
foo,
bar,
foo,
bar,
callExpr.callee.property);
check(statements,
callExpr.callee.object.body);
check(returnStatements,
callExpr.callee.object.body.body[0]);
check(functions,
callExpr.callee.object);
});
it("should replace this.currentPath with returned value", function() {
assert.strictEqual(objProp.computed, false);
types.visit(objProp, {
visitIdentifier: function(path) {
if (path.value.name === "property") {
path.parent.get("computed").replace(true);
return b.callExpression(
b.memberExpression(
b.thisExpression(),
b.identifier("toString"),
false
),
[]
);
}
this.traverse(path);
},
visitThisExpression: function(path) {
return b.identifier("self");
}
});
assert.strictEqual(objProp.computed, true);
n.CallExpression.assert(objProp.property);
var callee = objProp.property.callee;
n.MemberExpression.assert(callee);
n.Identifier.assert(callee.object);
assert.strictEqual(callee.object.name, "self");
n.Identifier.assert(callee.property);
assert.strictEqual(callee.property.name, "toString");
assert.deepEqual(objProp.property.arguments, []);
});
});

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc