Skip to content

Commit

Permalink
Merge b31912c into 1e1da30
Browse files Browse the repository at this point in the history
  • Loading branch information
twada committed Apr 15, 2015
2 parents 1e1da30 + b31912c commit 839bf34
Show file tree
Hide file tree
Showing 13 changed files with 284 additions and 126 deletions.
8 changes: 2 additions & 6 deletions bower.json
Expand Up @@ -32,14 +32,10 @@
"url": "git://github.com/twada/espower.git"
},
"devDependencies": {
"esprima": "~1.2.2",
"escodegen": "1.4.1",
"estraverse": "~1.9.0",
"mocha": "~2.1.0",
"requirejs": "~2.1.15",
"mocha": "~2.2.4",
"requirejs": "~2.1.17",
"assert": "Jxck/assert"
},
"resolutions": {
"esprima": "~1.2.2"
}
}
128 changes: 84 additions & 44 deletions build/espower.js
Expand Up @@ -108,6 +108,10 @@ AssertionVisitor.prototype.enter = function (currentNode, parentNode) {
}
};

AssertionVisitor.prototype.leave = function (currentNode, parentNode) {
// nothing to do now
};

AssertionVisitor.prototype.verifyNotInstrumented = function (currentNode) {
if (currentNode.type !== syntax.CallExpression) {
return;
Expand Down Expand Up @@ -260,6 +264,9 @@ function addToProps (props, createNode, name, value) {
name: name
}),
value: value,
method: false,
shorthand: false,
computed: false,
kind: 'init'
}));
}
Expand Down Expand Up @@ -369,9 +376,9 @@ Instrumentor.prototype.instrument = function (ast) {
enter: function (currentNode, parentNode) {
var controller = this,
path = controller.path(),
currentPath = path ? path[path.length - 1] : null;
currentKey = path ? path[path.length - 1] : null;
if (assertionVisitor) {
if (toBeSkipped(currentNode, parentNode, currentPath)) {
if (toBeSkipped(currentNode, parentNode, currentKey)) {
skipping = true;
return controller.skip();
}
Expand All @@ -391,7 +398,8 @@ Instrumentor.prototype.instrument = function (ast) {
},
leave: function (currentNode, parentNode) {
var path = this.path(),
resultTree = currentNode;
resultTree = currentNode,
currentKey = path ? path[path.length - 1] : null;
if (!assertionVisitor) {
return undefined;
}
Expand All @@ -400,16 +408,14 @@ Instrumentor.prototype.instrument = function (ast) {
return undefined;
}
if (assertionVisitor.isLeavingAssertion(path)) {
assertionVisitor.leave(currentNode, parentNode);
assertionVisitor = null;
return undefined;
}
if (!assertionVisitor.isCapturingArgument()) {
return undefined;
}
if (isCalleeOfParent(currentNode, parentNode)) {
return undefined;
}
if (toBeCaptured(currentNode)) {
if (toBeCaptured(currentNode, parentNode, currentKey)) {
resultTree = assertionVisitor.captureNode(currentNode, path);
}
if (assertionVisitor.isLeavingArgument(path)) {
Expand All @@ -421,11 +427,6 @@ Instrumentor.prototype.instrument = function (ast) {
return result;
};

function isCalleeOfParent(currentNode, parentNode) {
return (parentNode.type === syntax.CallExpression || parentNode.type === syntax.NewExpression) &&
parentNode.callee === currentNode;
}

function verifyAstPrerequisites (ast, options) {
var errorMessage;
if (typeof ast.loc === 'undefined') {
Expand Down Expand Up @@ -467,30 +468,51 @@ module.exports = [
syntax.ArrayExpression,
syntax.ConditionalExpression,
syntax.UpdateExpression,
syntax.TemplateLiteral,
syntax.TaggedTemplateExpression,
syntax.SpreadElement,
syntax.Property
];

},{"estraverse":50}],7:[function(_dereq_,module,exports){
'use strict';

var estraverse = _dereq_('estraverse'),
syntax = estraverse.Syntax;
var estraverse = _dereq_('estraverse');
var syntax = estraverse.Syntax;
var caputuringTargetTypes = [
// syntax.Property,
// syntax.ObjectExpression,
// syntax.ArrayExpression,
// syntax.ConditionalExpression,
syntax.Identifier,
syntax.MemberExpression,
syntax.CallExpression,
syntax.UnaryExpression,
syntax.BinaryExpression,
syntax.LogicalExpression,
syntax.AssignmentExpression,
syntax.NewExpression,
syntax.UpdateExpression,
syntax.TemplateLiteral,
syntax.TaggedTemplateExpression
];

module.exports = function toBeCaptured (currentNode) {
switch(currentNode.type) {
case syntax.Identifier:
case syntax.MemberExpression:
case syntax.CallExpression:
case syntax.UnaryExpression:
case syntax.BinaryExpression:
case syntax.LogicalExpression:
case syntax.AssignmentExpression:
case syntax.UpdateExpression:
case syntax.NewExpression:
return true;
default:
return false;
}
function isCaputuringTargetType (currentNode) {
return caputuringTargetTypes.indexOf(currentNode.type) !== -1;
}

function isCalleeOfParent(parentNode, currentKey) {
return (parentNode.type === syntax.CallExpression || parentNode.type === syntax.NewExpression) && currentKey === 'callee';
}

function isChildOfTaggedTemplateExpression(parentNode) {
return parentNode.type === syntax.TaggedTemplateExpression;
}

module.exports = function toBeCaptured (currentNode, parentNode, currentKey) {
return isCaputuringTargetType(currentNode) &&
!isCalleeOfParent(parentNode, currentKey) &&
!isChildOfTaggedTemplateExpression(parentNode);
};

},{"estraverse":50}],8:[function(_dereq_,module,exports){
Expand All @@ -500,42 +522,60 @@ var estraverse = _dereq_('estraverse'),
syntax = estraverse.Syntax,
supportedNodeTypes = _dereq_('./supported-node-types');

function isLeftHandSideOfAssignment(parentNode, currentPath) {
function isLeftHandSideOfAssignment(parentNode, currentKey) {
// Do not instrument left due to 'Invalid left-hand side in assignment'
return parentNode.type === syntax.AssignmentExpression && currentPath === 'left';
return parentNode.type === syntax.AssignmentExpression && currentKey === 'left';
}

function isChildOfObjectLiteral (parentNode) {
return parentNode.type === syntax.Property && parentNode.kind === 'init';
}

function isObjectLiteralKey (parentNode, currentKey) {
return isChildOfObjectLiteral(parentNode) && currentKey === 'key';
}

function isObjectLiteralValue (parentNode, currentKey) {
return isChildOfObjectLiteral(parentNode) && currentKey === 'value';
}

function isNonComputedObjectLiteralKey(parentNode, currentKey) {
// Do not instrument non-computed Object literal key
return isObjectLiteralKey(parentNode, currentKey) && !parentNode.computed;
}

function isObjectLiteralKey(parentNode, currentPath) {
// Do not instrument Object literal key
return parentNode.type === syntax.Property && parentNode.kind === 'init' && currentPath === 'key';
function isShorthandedValueOfObjectLiteral(parentNode, currentKey) {
// Do not instrument shorthanded Object literal value
return isObjectLiteralValue(parentNode, currentKey) && parentNode.shorthand;
}

function isUpdateExpression(parentNode) {
// Just wrap UpdateExpression, not digging in.
return parentNode.type === syntax.UpdateExpression;
}

function isCallExpressionWithNonComputedMemberExpression(currentNode, parentNode, currentPath) {
function isCallExpressionWithNonComputedMemberExpression(currentNode, parentNode, currentKey) {
// Do not instrument non-computed property of MemberExpression within CallExpression.
return currentNode.type === syntax.Identifier && parentNode.type === syntax.MemberExpression && !parentNode.computed && currentPath === 'property';
return currentNode.type === syntax.Identifier && parentNode.type === syntax.MemberExpression && !parentNode.computed && currentKey === 'property';
}

function isTypeOfOrDeleteUnaryExpression(currentNode, parentNode, currentPath) {
function isTypeOfOrDeleteUnaryExpression(currentNode, parentNode, currentKey) {
// 'typeof Identifier' or 'delete Identifier' is not instrumented
return currentNode.type === syntax.Identifier && parentNode.type === syntax.UnaryExpression && (parentNode.operator === 'typeof' || parentNode.operator === 'delete') && currentPath === 'argument';
return currentNode.type === syntax.Identifier && parentNode.type === syntax.UnaryExpression && (parentNode.operator === 'typeof' || parentNode.operator === 'delete') && currentKey === 'argument';
}

function isSupportedNodeType (node) {
return supportedNodeTypes.indexOf(node.type) !== -1;
}

module.exports = function toBeSkipped (currentNode, parentNode, currentPath) {
module.exports = function toBeSkipped (currentNode, parentNode, currentKey) {
return !isSupportedNodeType(currentNode) ||
isLeftHandSideOfAssignment(parentNode, currentPath) ||
isObjectLiteralKey(parentNode, currentPath) ||
isLeftHandSideOfAssignment(parentNode, currentKey) ||
isNonComputedObjectLiteralKey(parentNode, currentKey) ||
isShorthandedValueOfObjectLiteral(parentNode, currentKey) ||
isUpdateExpression(parentNode) ||
isCallExpressionWithNonComputedMemberExpression(currentNode, parentNode, currentPath) ||
isTypeOfOrDeleteUnaryExpression(currentNode, parentNode, currentPath);
isCallExpressionWithNonComputedMemberExpression(currentNode, parentNode, currentKey) ||
isTypeOfOrDeleteUnaryExpression(currentNode, parentNode, currentKey);
};

},{"./supported-node-types":6,"estraverse":50}],9:[function(_dereq_,module,exports){
Expand Down Expand Up @@ -14542,7 +14582,7 @@ module.exports={
},
"_id": "estraverse@3.1.0",
"_shasum": "15e28a446b8b82bc700ccc8b96c78af4da0d6cba",
"_from": "estraverse@>=3.0.0 <4.0.0",
"_from": "estraverse@>=3.1.0 <4.0.0",
"_npmVersion": "2.0.0-alpha-5",
"_npmUser": {
"name": "constellation",
Expand Down
5 changes: 3 additions & 2 deletions esp.js
@@ -1,9 +1,10 @@
var espower = require('./index'),
esprima = require('esprima'),
acorn = require('acorn'),
escodegen = require('escodegen');

var jsCode = process.argv[2];
var jsAst = esprima.parse(jsCode, {tolerant: true, loc: true, tokens: true});
var parserOptions = {ecmaVersion: 6, locations: true};
var jsAst = acorn.parse(jsCode, parserOptions);
var modifiedAst = espower(jsAst);

console.log(escodegen.generate(modifiedAst));
7 changes: 7 additions & 0 deletions lib/assertion-visitor.js
Expand Up @@ -66,6 +66,10 @@ AssertionVisitor.prototype.enter = function (currentNode, parentNode) {
}
};

AssertionVisitor.prototype.leave = function (currentNode, parentNode) {
// nothing to do now
};

AssertionVisitor.prototype.verifyNotInstrumented = function (currentNode) {
if (currentNode.type !== syntax.CallExpression) {
return;
Expand Down Expand Up @@ -218,6 +222,9 @@ function addToProps (props, createNode, name, value) {
name: name
}),
value: value,
method: false,
shorthand: false,
computed: false,
kind: 'init'
}));
}
Expand Down
18 changes: 6 additions & 12 deletions lib/instrumentor.js
Expand Up @@ -27,9 +27,9 @@ Instrumentor.prototype.instrument = function (ast) {
enter: function (currentNode, parentNode) {
var controller = this,
path = controller.path(),
currentPath = path ? path[path.length - 1] : null;
currentKey = path ? path[path.length - 1] : null;
if (assertionVisitor) {
if (toBeSkipped(currentNode, parentNode, currentPath)) {
if (toBeSkipped(currentNode, parentNode, currentKey)) {
skipping = true;
return controller.skip();
}
Expand All @@ -49,7 +49,8 @@ Instrumentor.prototype.instrument = function (ast) {
},
leave: function (currentNode, parentNode) {
var path = this.path(),
resultTree = currentNode;
resultTree = currentNode,
currentKey = path ? path[path.length - 1] : null;
if (!assertionVisitor) {
return undefined;
}
Expand All @@ -58,16 +59,14 @@ Instrumentor.prototype.instrument = function (ast) {
return undefined;
}
if (assertionVisitor.isLeavingAssertion(path)) {
assertionVisitor.leave(currentNode, parentNode);
assertionVisitor = null;
return undefined;
}
if (!assertionVisitor.isCapturingArgument()) {
return undefined;
}
if (isCalleeOfParent(currentNode, parentNode)) {
return undefined;
}
if (toBeCaptured(currentNode)) {
if (toBeCaptured(currentNode, parentNode, currentKey)) {
resultTree = assertionVisitor.captureNode(currentNode, path);
}
if (assertionVisitor.isLeavingArgument(path)) {
Expand All @@ -79,11 +78,6 @@ Instrumentor.prototype.instrument = function (ast) {
return result;
};

function isCalleeOfParent(currentNode, parentNode) {
return (parentNode.type === syntax.CallExpression || parentNode.type === syntax.NewExpression) &&
parentNode.callee === currentNode;
}

function verifyAstPrerequisites (ast, options) {
var errorMessage;
if (typeof ast.loc === 'undefined') {
Expand Down
3 changes: 3 additions & 0 deletions lib/rules/supported-node-types.js
Expand Up @@ -16,5 +16,8 @@ module.exports = [
syntax.ArrayExpression,
syntax.ConditionalExpression,
syntax.UpdateExpression,
syntax.TemplateLiteral,
syntax.TaggedTemplateExpression,
syntax.SpreadElement,
syntax.Property
];
52 changes: 35 additions & 17 deletions lib/rules/to-be-captured.js
@@ -1,21 +1,39 @@
'use strict';

var estraverse = require('estraverse'),
syntax = estraverse.Syntax;
var estraverse = require('estraverse');
var syntax = estraverse.Syntax;
var caputuringTargetTypes = [
// syntax.Property,
// syntax.ObjectExpression,
syntax.ArrayExpression,
// syntax.ConditionalExpression,
syntax.Identifier,
syntax.MemberExpression,
syntax.CallExpression,
syntax.UnaryExpression,
syntax.BinaryExpression,
syntax.LogicalExpression,
syntax.AssignmentExpression,
syntax.NewExpression,
syntax.UpdateExpression,
syntax.TemplateLiteral,
syntax.TaggedTemplateExpression
];

module.exports = function toBeCaptured (currentNode) {
switch(currentNode.type) {
case syntax.Identifier:
case syntax.MemberExpression:
case syntax.CallExpression:
case syntax.UnaryExpression:
case syntax.BinaryExpression:
case syntax.LogicalExpression:
case syntax.AssignmentExpression:
case syntax.UpdateExpression:
case syntax.NewExpression:
return true;
default:
return false;
}
function isCaputuringTargetType (currentNode) {
return caputuringTargetTypes.indexOf(currentNode.type) !== -1;
}

function isCalleeOfParent(parentNode, currentKey) {
return (parentNode.type === syntax.CallExpression || parentNode.type === syntax.NewExpression) && currentKey === 'callee';
}

function isChildOfTaggedTemplateExpression(parentNode) {
return parentNode.type === syntax.TaggedTemplateExpression;
}

module.exports = function toBeCaptured (currentNode, parentNode, currentKey) {
return isCaputuringTargetType(currentNode) &&
!isCalleeOfParent(parentNode, currentKey) &&
!isChildOfTaggedTemplateExpression(parentNode);
};

0 comments on commit 839bf34

Please sign in to comment.