ast-types
Advanced tools
Comparing version 0.2.0 to 0.2.2
@@ -173,3 +173,6 @@ var types = require("./types"); | ||
.field("kind", or("var", "let", "const")) | ||
.field("declarations", [def("VariableDeclarator")]); | ||
.field("declarations", [or( | ||
def("VariableDeclarator"), | ||
def("Identifier") // TODO Esprima deviation. | ||
)]); | ||
@@ -182,2 +185,3 @@ def("VariableDeclarator") | ||
// TODO Are all Expressions really Patterns? | ||
def("Expression").bases("Node", "Pattern"); | ||
@@ -219,3 +223,5 @@ | ||
.field("argument", def("Expression")) | ||
.field("prefix", isBoolean); | ||
// TODO Esprima doesn't bother with this field, presumably because | ||
// it's always true for unary operators. | ||
.field("prefix", isBoolean, defaults.true); | ||
@@ -227,2 +233,3 @@ var BinaryOperator = or( | ||
"+", "-", "*", "/", "%", | ||
"&", // TODO Missing from the Parser API. | ||
"|", "^", "in", | ||
@@ -327,3 +334,3 @@ "instanceof", ".."); | ||
.field("param", def("Pattern")) | ||
.field("guard", or(def("Expression"), null)) | ||
.field("guard", or(def("Expression"), null), defaults.null) | ||
.field("body", def("BlockStatement")); | ||
@@ -330,0 +337,0 @@ |
113
lib/types.js
@@ -6,2 +6,5 @@ var assert = require("assert"); | ||
var each = Ap.forEach; | ||
var objToStr = Object.prototype.toString; | ||
var funObjStr = objToStr.call(function(){}); | ||
var strObjStr = objToStr.call(""); | ||
@@ -15,13 +18,23 @@ // A type is an object with a .check method that takes a value and returns | ||
// The isFunction or isString types need to be defined before they can | ||
// be used. We can get away with checking only isFunction because we | ||
// happen to know that isString is defined before isFunction. | ||
if (isFunction instanceof Type) { | ||
assert.ok(isFunction.check(name) || isString.check(name), name); | ||
assert.ok(isFunction.check(check), check); | ||
} | ||
// Unfortunately we can't elegantly reuse isFunction and isString, | ||
// here, because this code is executed while defining those types. | ||
assert.strictEqual(objToStr.call(check), funObjStr, | ||
check + " is not a function"); | ||
// The `name` parameter can be either a function or a string. | ||
var nameObjStr = objToStr.call(name); | ||
assert.ok(nameObjStr === funObjStr || | ||
nameObjStr === strObjStr, | ||
name + " is neither a function nor a string"); | ||
Object.defineProperties(self, { | ||
name: { value: name }, | ||
check: { value: check } | ||
check: { | ||
value: function(value, deep) { | ||
var result = check.call(self, value, deep); | ||
if (!result && objToStr.call(deep) === funObjStr) | ||
deep(self, value); | ||
return result; | ||
} | ||
} | ||
}); | ||
@@ -48,3 +61,2 @@ } | ||
var objToStr = Object.prototype.toString; | ||
var builtInTypes = {}; | ||
@@ -256,7 +268,37 @@ Object.defineProperty(exports, "builtInTypes", { | ||
assert.strictEqual(this.finalized, true); | ||
return Object.keys(allFields).every(function(name) { | ||
var type = allFields[name].type; | ||
return value.hasOwnProperty(name) | ||
&& type.check(value[name], deep); | ||
}); | ||
function checkFieldByName(name) { | ||
var field = allFields[name]; | ||
var type = field.type; | ||
// If the value has a property with this name, check the type of | ||
// the child value. | ||
if (value.hasOwnProperty(name)) | ||
return type.check(value[name], deep); | ||
// If there is no default function for this field, treat the | ||
// missing property as a type error. | ||
if (!field.defaultFn) | ||
return false; | ||
// If there is a default function for this field, and we are not | ||
// checking deeply, just assume that the default function would | ||
// return something that matches field.type. | ||
if (!deep) | ||
return true; | ||
// If we are checking deeply, go ahead and deeply check the | ||
// result returned by the default function. | ||
var child = field.defaultFn.call(value); | ||
var result = type.check(child, deep); | ||
if (result) { | ||
// If the default function returned something suitable, go | ||
// ahead and fill it in to promote general good hygiene. | ||
value[name] = child; | ||
} | ||
return result; | ||
} | ||
return isObject.check(value) | ||
&& Object.keys(allFields).every(checkFieldByName); | ||
}; | ||
@@ -269,13 +311,36 @@ | ||
// A Def type can only match an object value. | ||
if (!isObject.check(value)) | ||
return false; | ||
var vDef = Def.fromValue(value); | ||
// If we couldn't determine the Def associated with the given value, | ||
// it was probably just missing a "type" field, so be optimistic and | ||
// let this.checkAllFields make the final decision. | ||
if (!vDef) | ||
return this.checkAllFields(value, deep); | ||
// If checking deeply and vDef === this, then we only need to call | ||
// checkAllFields once. Calling checkAllFields is too strict when deep | ||
// is false, because then we only care about this.isSupertypeOf(vDef). | ||
if (deep && vDef === this) | ||
return this.checkAllFields(value, deep); | ||
// In most cases we rely exclusively on isSupertypeOf to make O(1) | ||
// subtyping determinations. This suffices in most situations outside | ||
// of unit tests, since interface conformance is checked whenever new | ||
// instances are created using builder functions. The exception is | ||
// when deep is true; then, we recursively check all fields. | ||
var vDef = Def.fromValue(value); | ||
return !!vDef // Coerce to boolean. | ||
&& this.isSupertypeOf(vDef) | ||
&& (!deep || (vDef.checkAllFields(value, true) && | ||
(this === vDef || // Shallow-check strict supertype fields. | ||
this.checkAllFields(value, false)))) | ||
// instances are created using builder functions. | ||
if (!this.isSupertypeOf(vDef)) | ||
return false; | ||
// The exception is when deep is true; then, we recursively check all | ||
// fields. | ||
if (!deep) | ||
return true; | ||
// Use the more specific Def (vDef) to perform the deep check, but | ||
// shallow-check fields defined by the less specific Def (this). | ||
return vDef.checkAllFields(value, deep) | ||
&& this.checkAllFields(value, false); | ||
}; | ||
@@ -345,3 +410,5 @@ | ||
? args[i] | ||
: field.defaultFn.apply(built, args); | ||
// Expose the partially-built object to the default | ||
// function as its `this` object. | ||
: field.defaultFn.call(built); | ||
@@ -348,0 +415,0 @@ assert.ok( |
@@ -19,3 +19,3 @@ var types = require("./types"); | ||
.field("name", isString) | ||
.field("namspace", or(isString, null)); | ||
.field("namespace", or(isString, null), defaults.null); | ||
@@ -37,12 +37,15 @@ def("XJSExpression") | ||
)], defaults.emptyArray) | ||
// Little-known fact: default functions have access to the same | ||
// arguments as the builder function. | ||
.field("name", def("XJSIdentifier"), function(openingElement) { | ||
return openingElement.name; | ||
.field("name", def("XJSIdentifier"), function() { | ||
// Little-known fact: the `this` object inside a default function | ||
// is none other than the partially-built object itself, and any | ||
// fields initialized directly from builder function arguments | ||
// (like openingElement, closingElement, and children) are | ||
// guaranteed to be available. | ||
return this.openingElement.name; | ||
}) | ||
.field("selfClosing", isBoolean, function(openingElement) { | ||
return openingElement.selfClosing; | ||
.field("selfClosing", isBoolean, function() { | ||
return this.openingElement.selfClosing; | ||
}) | ||
.field("attributes", [def("XJSAttribute")], function(openingElement) { | ||
return openingElement.attributes; | ||
.field("attributes", [def("XJSAttribute")], function() { | ||
return this.openingElement.attributes; | ||
}); | ||
@@ -49,0 +52,0 @@ |
{ | ||
"author": "Ben Newman <bn@cs.stanford.edu>", | ||
"name": "ast-types", | ||
"description": "Efficient, modular, Esprima-compatible implementation of the abstract syntax tree (AST) type hierarchy pioneered by the Mozilla SpiderMonkey Parser API", | ||
"description": "Esprima-compatible implementation of the Mozilla JS Parser API", | ||
"keywords": [ | ||
@@ -21,3 +21,3 @@ "ast", | ||
], | ||
"version": "0.2.0", | ||
"version": "0.2.2", | ||
"homepage": "http://github.com/benjamn/ast-types", | ||
@@ -24,0 +24,0 @@ "repository": { |
var types = require("../lib/types"); | ||
var n = types.namedTypes; | ||
var b = types.builders; | ||
var path = require("path"); | ||
var fs = require("fs"); | ||
var parse = require("esprima").parse; | ||
@@ -30,2 +33,16 @@ require("../lib/core"); | ||
exports.testIsSupertypeOf = function(t, assert) { | ||
var def = types.Type.def; | ||
assert.ok(def("Node").isSupertypeOf(def("Node"))); | ||
assert.ok(def("Node").isSupertypeOf(def("Expression"))); | ||
assert.ok(!def("Expression").isSupertypeOf(def("Node"))); | ||
assert.ok(!def("Expression").isSupertypeOf( | ||
def("DebuggerStatement"))); | ||
// TODO Make this test case more exhaustive. | ||
t.finish(); | ||
}; | ||
exports.testShallowAndDeepChecks = function(t, assert) { | ||
@@ -51,3 +68,3 @@ var index = b.identifier("foo"); | ||
// This makes decl cease to conform to n.VariableDeclaration. | ||
decl.declarations.push(b.identifier("bar")); | ||
decl.declarations.push(b.literal("bar")); | ||
@@ -90,1 +107,24 @@ assert.ok(n.Node.check(decl)); | ||
}; | ||
function validateProgram(file) { | ||
file = path.join(__dirname, "..", file); | ||
exports["test " + file] = function(t, assert) { | ||
fs.readFile(file, "utf8", function(err, code) { | ||
if (err) throw err; | ||
assert.ok(n.Program.check(parse(code), true)); | ||
assert.ok(n.Program.check(parse(code, { loc: true }), true)); | ||
t.finish(); | ||
}); | ||
}; | ||
} | ||
validateProgram("main.js"); | ||
validateProgram("lib/shared.js"); | ||
validateProgram("lib/core.js"); | ||
validateProgram("lib/types.js"); | ||
validateProgram("test/run.js"); | ||
validateProgram("test/data/backbone.js"); | ||
validateProgram("test/data/jquery-1.9.1.js"); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
372340
13
10512
1
1