Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

jsstana

Package Overview
Dependencies
Maintainers
1
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jsstana - npm Package Compare versions

Comparing version 0.0.10 to 0.0.11

test/assign.js

288

lib/jsstana.js

@@ -13,7 +13,6 @@ /**

var contents = // ...
var syntax = esprima.parse(syntax);
var syntax = esprima.parse(contents);
jsstana.traverse(syntax, function (node) {
jsstana.traverse(syntax, function (node) {
var m = jsstana.match("(call alert ?argument)", node);
var m = jsstana.match("(call alert ?argument)", node);
if (m) {

@@ -113,2 +112,3 @@ console.log("alert called with argument", m.argument);

// http://ecma-international.org/ecma-262/5.1/#sec-7.7
var validBinaryOperators = [

@@ -131,3 +131,70 @@ "+", "-", "*", "/", "%",

var validAssignmentOperators = [
"=",
"+=", "-=", "*=", "/=", "%=",
"<<=", ">>=", ">>>=",
"&=", "|=", "^=",
];
var builtInMatchers = {
"not": notMatcher,
"or": orMatcher,
"and": andMatcher,
"var": varMatcher,
"ident": identMatcher,
"return": returnMatcher,
"call": _.partial(callMatcher, true),
"new": _.partial(callMatcher, false),
"expr": expressionMatcher,
"binary": binaryMatcher,
"unary": unaryMatcher,
"update": _.partial(updateMatcher, undefined),
"prefix": _.partial(updateMatcher, true),
"postfix": _.partial(updateMatcher, false),
"assign": assignMatcher,
"member": _.partial(memberMatcher, undefined),
"property": _.partial(memberMatcher, false),
"subscript": _.partial(memberMatcher, true),
"lookup": lookupMatcher,
"throw": throwMatcher,
"ternary": ternaryMatcher,
"literal": _.partial(literalMatcher, "any"),
"string": _.partial(literalMatcher, "string"),
"number": _.partial(literalMatcher, "number"),
"bool": _.partial(literalMatcher, "bool"),
"regexp": _.partial(literalMatcher, "regexp"),
"null": _.partial(literalBuiltinMatcher, "null"),
"true": _.partial(literalBuiltinMatcher, "true"),
"false": _.partial(literalBuiltinMatcher, "false"),
"infinity": _.partial(literalBuiltinMatcher, "infinity"),
"nan": _.partial(literalBuiltinMatcher, "nan"),
"undefined": _.partial(literalBuiltinMatcher, "undefined"),
"null-node": nullNodeMatcher,
};
var unaryOperators = _.difference(validUnaryOperators, validBinaryOperators);
// "TODO: , == SequenceExpression"
_.each(validBinaryOperators, function (binop) {
builtInMatchers[binop] = _.partial(binaryMatcher, binop);
});
_.each(unaryOperators, function (unop) {
builtInMatchers[unop] = _.partial(unaryMatcher, unop);
});
_.each(validAssignmentOperators, function (assignOp) {
builtInMatchers[assignOp] = _.partial(assignMatcher, assignOp);
});
function matcher(sexpr) {
/* jshint validthis:true */
var that = this instanceof JsstanaContext ? this : new JsstanaContext();
var args = _.toArray(arguments).slice(1);
if (args.length !== 0) {
that = new JsstanaContext(that);
that.positionalMatchers = args;
}
if (_.isString(sexpr)) {

@@ -138,3 +205,3 @@ if (sexpr.indexOf(".") !== -1) {

});
return matcher(sexpr);
return that.matcher(sexpr);
} else if (sexpr === "?") {

@@ -151,2 +218,7 @@ return function () {

};
} else if (sexpr.match(/^\$\d+$/)) {
sexpr = parseInt(sexpr.substr(1), 10);
assert(sexpr < that.positionalMatchers.length,
"there is only " + that.positionalMatchers.length + " positional matchers, required " + sexpr);
return that.positionalMatchers[sexpr];
} else if (sexpr === "true") {

@@ -182,52 +254,6 @@ return function (node) {

var matchers = {
"not": notMatcher,
"or": orMatcher,
"and": andMatcher,
"var": varMatcher,
"ident": identMatcher,
"return": returnMatcher,
"call": callMatcher.bind(undefined, true),
"new": callMatcher.bind(undefined, false),
"expr": expressionMatcher,
"binary": binaryMatcher,
"unary": unaryMatcher,
"update": updateMatcher.bind(undefined, undefined),
"prefix": updateMatcher.bind(undefined, true),
"postfix": updateMatcher.bind(undefined, false),
"member": memberMatcher.bind(undefined, undefined),
"property": memberMatcher.bind(undefined, false),
"subscript": memberMatcher.bind(undefined, true),
"lookup": lookupMatcher,
"throw": throwMatcher,
"ternary": ternaryMatcher,
"literal": literalMatcher.bind(undefined, "any"),
"string": literalMatcher.bind(undefined, "string"),
"number": literalMatcher.bind(undefined, "number"),
"bool": literalMatcher.bind(undefined, "bool"),
"regexp": literalMatcher.bind(undefined, "regexp"),
"null": literalBuiltinMatcher.bind(undefined, "null"),
"true": literalBuiltinMatcher.bind(undefined, "true"),
"false": literalBuiltinMatcher.bind(undefined, "false"),
"infinity": literalBuiltinMatcher.bind(undefined, "infinity"),
"nan": literalBuiltinMatcher.bind(undefined, "nan"),
"undefined": literalBuiltinMatcher.bind(undefined, "undefined"),
"null-node": nullNodeMatcher,
};
var binaryOperators = validBinaryOperators;
var unaryOperators = _.difference(validUnaryOperators, validBinaryOperators);
// "TODO: , == SequenceExpression"
_.each(binaryOperators, function (binop) {
matchers[binop] = binaryMatcher.bind(undefined, binop);
});
_.each(unaryOperators, function (unop) {
matchers[unop] = unaryMatcher.bind(undefined, unop);
});
if (_.has(matchers, rator)) {
return matchers[rator].apply(undefined, rands);
if (_.has(that.matchers, rator)) {
return that.matchers[rator].apply(that, rands);
} else if (_.has(builtInMatchers, rator)) {
return builtInMatchers[rator].apply(that, rands);
} else {

@@ -259,6 +285,7 @@ throw new Error("unknown node type: " + rator);

function notMatcher(pattern) {
assert("not", 1, arguments);
/* jshint validthis:true */
assertArguments("not", 1, arguments);
pattern = pattern || "?";
var patternMatcher = matcher(pattern);
var patternMatcher = this.matcher(pattern);

@@ -276,4 +303,5 @@ return function (node) {

function orMatcher() {
/* jshint validthis:true */
var args = _.toArray(arguments);
var argsMatchers = args.map(matcher);
var argsMatchers = args.map(matcher, this);

@@ -298,4 +326,5 @@ return function (node) {

function andMatcher() {
/* jshint validthis:true */
var args = _.toArray(arguments);
var argsMatchers = args.map(matcher);
var argsMatchers = args.map(matcher, this);

@@ -336,6 +365,7 @@ return function (node) {

function returnMatcher(value) {
/* jshint validthis:true */
assertArguments("return", 1, arguments);
value = value || "?";
var valueMatcher = matcher(value);
var valueMatcher = this.matcher(value);

@@ -476,2 +506,3 @@ return function (node) {

function varMatcher(id, init) {
/* jshint validthis:true */
assertArguments("var", 2, arguments);

@@ -482,3 +513,3 @@ id = id || "?";

var idMatcher = identifierMatcher(id);
var initMatcher = matcher(init);
var initMatcher = this.matcher(init);

@@ -523,5 +554,6 @@ return function (node) {

function callMatcher(callnew, callee) {
/* jshint validthis:true */
callee = callee || "?";
var calleeMatcher = matcher(callee);
var calleeMatcher = this.matcher(callee);
var args = _.toArray(arguments).slice(2);

@@ -551,3 +583,3 @@ var dotted = false;

var argumentMatchers = args.map(matcher);
var argumentMatchers = args.map(matcher, this);

@@ -582,6 +614,7 @@ return function (node) {

function expressionMatcher(expr) {
/* jshint validthis:true */
assertArguments("expr", 1, arguments);
expr = expr || "?";
var exprMatcher = matcher(expr);
var exprMatcher = this.matcher(expr);

@@ -603,2 +636,3 @@ return function (node) {

function binaryMatcher(operator, lhs, rhs) {
/* jshint validthis:true */
assertArguments("binary", 3, arguments);

@@ -613,4 +647,4 @@

var opMatcher = operatorMatcher(operator, validBinaryOperators);
var lhsMatcher = matcher(lhs);
var rhsMatcher = matcher(rhs);
var lhsMatcher = this.matcher(lhs);
var rhsMatcher = this.matcher(rhs);

@@ -636,2 +670,3 @@ return function (node) {

function unaryMatcher(operator, value) {
/* jshint validthis:true */
assertArguments("unary", 2, arguments, 1);

@@ -642,6 +677,6 @@

assert(_.isString(operator), "binary operator should be string expr");
assert(_.isString(operator), "unary operator should be string expr");
var opMatcher = operatorMatcher(operator, validUnaryOperators);
var valueMatcher = matcher(value);
var valueMatcher = this.matcher(value);

@@ -666,2 +701,3 @@ return function (node) {

function updateMatcher(prefix, operator, value) {
/* jshint validthis:true */
assertArguments("update/postfix/prefix", 2, arguments, 1);

@@ -672,6 +708,6 @@

assert(_.isString(operator), "binary operator should be string expr");
assert(_.isString(operator), "update operator should be string expr");
var opMatcher = operatorMatcher(operator, validUpdateOperators);
var valueMatcher = matcher(value);
var valueMatcher = this.matcher(value);

@@ -690,2 +726,31 @@ return function (node) {

/**
#### (assign op var value)
Matches `AssignmentExpression`.
*/
function assignMatcher(operator, variable, value) {
/* jshint validthis:true */
assertArguments("assign", 3, arguments);
operator = operator || "?";
variable = variable || "?";
value = value || "?";
assert(_.isString(operator), "assignment operator should be string expr");
var opMatcher = operatorMatcher(operator, validAssignmentOperators);
var variableMatcher = this.matcher(variable);
var valueMatcher = this.matcher(value);
return function (node) {
if (node.type !== "AssignmentExpression") { return undefined; }
var opM = opMatcher(node.operator);
var variableM = variableMatcher(node.left);
var valueM = valueMatcher(node.right);
return combineMatches(opM, variableM, valueM);
};
}
/**
#### (member object property)

@@ -699,2 +764,3 @@

function memberMatcher(computed, object, property) {
/* jshint validthis:true */
assertArguments("member/property/subscript", 2, arguments, 1);

@@ -705,3 +771,3 @@ object = object || "?";

var objectMatcher = matcher(object);
var propertyMatcher = matcher(property);
var propertyMatcher = this.matcher(property);

@@ -745,6 +811,7 @@ return function (node) {

function throwMatcher(ex) {
/* jshint validthis:true */
assertArguments("throw", 1, arguments);
ex = ex || "?";
var exMatcher = matcher(ex);
var exMatcher = this.matcher(ex);

@@ -764,2 +831,3 @@ return function (node) {

function ternaryMatcher(test, con, alt) {
/* jshint validthis:true */
assertArguments("ternary", 3, arguments);

@@ -770,5 +838,5 @@ test = test || "?";

var testMatcher = matcher(test);
var consequentMatcher = matcher(con);
var alternateMatcher = matcher(alt);
var testMatcher = this.matcher(test);
var consequentMatcher = this.matcher(con);
var alternateMatcher = this.matcher(alt);

@@ -801,6 +869,8 @@ return function (node) {

function match(pattern, node) {
/* jshint validthis:true */
assert(arguments.length === 1 || arguments.length === 2, "match takes one or two arguments");
var that = this instanceof JsstanaContext ? this : new JsstanaContext();
if (!_.has(matchPatterns, pattern)) {
matchPatterns[pattern] = matcher(sexpr.parse(pattern));
matchPatterns[pattern] = that.matcher(sexpr.parse(pattern));
}

@@ -817,7 +887,65 @@

/**
### createMatcher(pattern, [posMatcher])
Create matcher. With one argument, `matcher(pattern) === match(pattern)`.
With additional arguments, you can add `$0`, `$1`... additional anonymous matchers.
```js
var matcher = jsstana.createMatcher("(expr (= a $0))", function (node) {
return node.type === "ObjectExpression" && node.properties.length === 0 ? {} : undefined;
});
```
*/
function createMatcher() {
/* jshint validthis:true */
var args = _.toArray(arguments);
args[0] = sexpr.parse(args[0]);
return matcher.apply(this, args);
}
/**
### new jsstana()
Create new jsstana context. You can add new operations to this one.
```js
var ctx = new jsstana();
ctx.addMatchers("empty-object", function () {
this.assertArguments("empty-object", 0, arguments);
return function (node) {
return node.type === "ObjectExpression" && node.properties.length === 0 ? {} : undefined;
};
});
ctx.match("(empty-object", node);
```
You may compile submatchers with `this.matcher(sexpr)` and combine their results with `this.combineMatches`.
`this.assertArguments` checks argument (rator) count, to help validate pattern grammar.
*/
function JsstanaContext(context) {
this.matchers = context instanceof JsstanaContext ? context.matchers : {};
this.positionalMatchers = [];
}
// matcher utilities
JsstanaContext.prototype.combineMatches = combineMatches;
JsstanaContext.prototype.assertArguments = assertArguments;
JsstanaContext.prototype.matcher = matcher;
// public api
JsstanaContext.prototype.match = match;
JsstanaContext.prototype.createMatcher = createMatcher;
JsstanaContext.prototype.addMatcher = function (name, f) {
assert(!_.has(this.matchers, name), "matcher names should be unique: " + name);
this.matchers[name] = f;
};
// Exports
exports.traverse = traverse;
exports.parseSExpr = sexpr.parse;
exports.match = match;
JsstanaContext.traverse = traverse;
JsstanaContext.match = match;
JsstanaContext.createMatcher = createMatcher;
module.exports = JsstanaContext;
/**

@@ -836,2 +964,6 @@

- 0.0.11 User-provided patterns
- fixed installing on Windows
- assignment pattern
- anonymous matchers
- 0.0.10 ident pattern

@@ -838,0 +970,0 @@ - 0.0.9 Boolean patterns

@@ -12,5 +12,19 @@ "use string";

function unquote(m) {
return m[1].replace(/\\(.)/g, function (unused, c) {
return c;
});
}
function quote(str) {
return str.replace(/(['\\])/g, function (unused, c) {
return "\\" + c;
});
}
var sexprP = p.alt(
p.seq(lexemeP("("), p.repeat(function () { return sexprP; }), lexemeP(")")).onMatch(function (arr) { return arr[1]; }),
lexemeP(p.regex(/[a-zA-Z\?\.\-\/*+<>=!%,~][a-zA-Z0-9_\?\.\-\/*+<>+!%,~]*/)).onMatch(_.first),
lexemeP(p.regex(/[a-zA-Z\?\.\-\/*+<>=!%,~\$][a-zA-Z0-9_\?\.\-\/*+<>=+!%,~\$]*/)).onMatch(_.first),
lexemeP(p.regex(/"((?:[^"]|\\.)*)"/)).onMatch(unquote),
lexemeP(p.regex(/'((?:[^']|\\.)*)'/)).onMatch(unquote),
lexemeP(p.regex(/[0-9]+/)).onMatch(function (m) { return parseInt(_.first(m), 10); } )

@@ -30,4 +44,27 @@ );

function stringifyString(sexpr) {
if (sexpr === "") {
return "''";
} else if (sexpr.match(/[ '"]/) || sexpr.match(/^\d*$/)) {
return "'" + quote(sexpr) + "'";
} else {
return sexpr;
}
}
function stringify(sexpr) {
if (_.isString(sexpr)) {
return stringifyString(sexpr);
} else if (_.isNumber(sexpr)) {
return ""+sexpr;
} else if (_.isArray(sexpr)) {
return "(" + sexpr.map(stringify).join(" ") + ")";
}
throw new Error("sexpr should be an array, a number or a string");
}
module.exports = {
parse: parse,
};
stringify: stringify,
};
{
"name": "jsstana",
"description": "s-expression match patterns for Mozilla Parser AST",
"version": "0.0.10",
"version": "0.0.11",
"homepage": "https://github.com/phadej/jsstana",

@@ -6,0 +6,0 @@ "author": {

@@ -12,7 +12,6 @@ # jsstana [![Build Status](https://secure.travis-ci.org/phadej/jsstana.png?branch=master)](http://travis-ci.org/phadej/jsstana)

var contents = // ...
var syntax = esprima.parse(syntax);
var syntax = esprima.parse(contents);
jsstana.traverse(syntax, function (node) {
jsstana.traverse(syntax, function (node) {
var m = jsstana.match("(call alert ?argument)", node);
var m = jsstana.match("(call alert ?argument)", node);
if (m) {

@@ -114,2 +113,6 @@ console.log("alert called with argument", m.argument);

#### (assign op var value)
Matches `AssignmentExpression`.
#### (member object property)

@@ -147,2 +150,31 @@

### createMatcher(pattern, [posMatcher])
Create matcher. With one argument, `matcher(pattern) === match(pattern)`.
With additional arguments, you can add `$0`, `$1`... additional anonymous matchers.
```js
var matcher = jsstana.createMatcher("(expr (= a $0))", function (node) {
return node.type === "ObjectExpression" && node.properties.length === 0 ? {} : undefined;
});
```
### new jsstana()
Create new jsstana context. You can add new operations to this one.
```js
var ctx = new jsstana();
ctx.addMatchers("empty-object", function () {
this.assertArguments("empty-object", 0, arguments);
return function (node) {
return node.type === "ObjectExpression" && node.properties.length === 0 ? {} : undefined;
};
});
ctx.match("(empty-object", node);
```
You may compile submatchers with `this.matcher(sexpr)` and combine their results with `this.combineMatches`.
`this.assertArguments` checks argument (rator) count, to help validate pattern grammar.
## Contributing

@@ -159,2 +191,6 @@

- 0.0.11 User-provided patterns
- fixed installing on Windows
- assignment pattern
- anonymous matchers
- 0.0.10 ident pattern

@@ -184,2 +220,1 @@ - 0.0.9 Boolean patterns

Licensed under the BSD3 license.

@@ -61,3 +61,3 @@ /* global describe:true, it:true */

it("takes operands as second and third parameters, non-match", function () {
it("takes operands as second and third parameters", function () {
var syntax = esprima.parse("1 + 2;");

@@ -64,0 +64,0 @@ var node = syntax.body[0];

@@ -21,10 +21,1 @@ /* global describe:true, it:true */

});
describe("parseSExpr()", function () {
it("works", function () {
var actual = jsstana.parseSExpr("(foo bar 1 2 (1 2) 1)");
var expected = ["foo", "bar", 1, 2, [1, 2], 1];
assert.deepEqual(actual, expected);
});
});
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