aboutsummaryrefslogtreecommitdiff
path: root/node_modules/babel-plugin-espower/lib
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/babel-plugin-espower/lib')
-rw-r--r--node_modules/babel-plugin-espower/lib/babel-assertion-visitor.js341
-rw-r--r--node_modules/babel-plugin-espower/lib/babel-espower-visitor.js86
-rw-r--r--node_modules/babel-plugin-espower/lib/create-espower-visitor.js32
-rw-r--r--node_modules/babel-plugin-espower/lib/default-options.js19
-rw-r--r--node_modules/babel-plugin-espower/lib/define-properties.js12
-rw-r--r--node_modules/babel-plugin-espower/lib/power-assert-recorder.js26
-rw-r--r--node_modules/babel-plugin-espower/lib/to-be-captured.js56
-rw-r--r--node_modules/babel-plugin-espower/lib/to-be-skipped.js107
8 files changed, 679 insertions, 0 deletions
diff --git a/node_modules/babel-plugin-espower/lib/babel-assertion-visitor.js b/node_modules/babel-plugin-espower/lib/babel-assertion-visitor.js
new file mode 100644
index 000000000..6135f5766
--- /dev/null
+++ b/node_modules/babel-plugin-espower/lib/babel-assertion-visitor.js
@@ -0,0 +1,341 @@
+'use strict';
+
+var EspowerLocationDetector = require('espower-location-detector');
+var estraverse = require('estraverse');
+var cloneWithWhitelist = require('espurify').cloneWithWhitelist;
+var babelgen = require('babel-generator');
+var define = require('./define-properties');
+var toBeCaptured = require('./to-be-captured');
+var toBeSkipped = require('./to-be-skipped');
+var fs = require('fs');
+var helperCode = '(' +
+ fs.readFileSync(require.resolve('./power-assert-recorder.js'), 'utf8')
+ .split('\n')
+ .slice(2)
+ .join('\n')
+ + ')()';
+
+function BabelAssertionVisitor (babel, matcher, options) {
+ this.babel = babel;
+ this.matcher = matcher;
+ this.options = options;
+ this.currentArgumentNodePath = null;
+ this.argumentModified = false;
+ this.valueRecorder = null;
+ this.locationDetector = new EspowerLocationDetector(this.options);
+ var babelTemplate = babel.template;
+ this.helperTemplate = babelTemplate(helperCode);
+ var whiteListWithRange = Object.keys(options.astWhiteList).reduce(function (acc, key) {
+ acc[key] = options.astWhiteList[key].concat(['range']);
+ return acc;
+ }, {});
+ this.purifyAst = cloneWithWhitelist(whiteListWithRange);
+}
+
+BabelAssertionVisitor.prototype.enter = function (nodePath) {
+ this.assertionNodePath = nodePath;
+ var currentNode = nodePath.node;
+ this.location = this.locationDetector.locationFor(currentNode);
+ var enclosingFunc = this.findEnclosingFunction(nodePath);
+ this.withinGenerator = enclosingFunc && enclosingFunc.generator;
+ this.withinAsync = enclosingFunc && enclosingFunc.async;
+ this.generateCanonicalCode(nodePath, currentNode); // should be next to enclosingFunc detection
+ // store original espath for each node
+ var visitorKeys = this.options.visitorKeys;
+ estraverse.traverse(currentNode, {
+ keys: visitorKeys,
+ enter: function (node) {
+ if (this.path()) {
+ var espath = this.path().join('/');
+ define(node, { _espowerEspath: espath });
+ }
+ }
+ });
+};
+
+BabelAssertionVisitor.prototype.enterArgument = function (nodePath) {
+ var currentNode = nodePath.node;
+ var parentNode = nodePath.parent;
+ var argMatchResult = this.matcher.matchArgument(currentNode, parentNode);
+ if (!argMatchResult) {
+ return;
+ }
+ if (argMatchResult.name === 'message' && argMatchResult.kind === 'optional') {
+ // skip optional message argument
+ return;
+ }
+ this.verifyNotInstrumented(currentNode);
+ // create recorder per argument
+ this.valueRecorder = this.createNewRecorder(nodePath);
+ // entering target argument
+ this.currentArgumentNodePath = nodePath;
+};
+
+BabelAssertionVisitor.prototype.leave = function (nodePath) {
+ var currentNode = nodePath.node;
+ var visitorKeys = this.options.visitorKeys;
+ estraverse.traverse(currentNode, {
+ keys: visitorKeys,
+ enter: function (node) {
+ delete node._espowerEspath;
+ }
+ });
+};
+
+BabelAssertionVisitor.prototype.leaveArgument = function (resultTree) {
+ try {
+ return this.argumentModified ? this.captureArgument(resultTree) : resultTree;
+ } finally {
+ this.currentArgumentNodePath = null;
+ this.argumentModified = false;
+ this.valueRecorder = null;
+ }
+};
+
+BabelAssertionVisitor.prototype.captureNode = function (nodePath) {
+ var currentNode = nodePath.node;
+ var t = this.babel.types;
+ this.argumentModified = true;
+ var relativeEsPath = currentNode._espowerEspath;
+ var newNode = t.callExpression(
+ t.memberExpression(this.valueRecorder, t.identifier('_capt')),
+ [
+ currentNode,
+ t.valueToNode(relativeEsPath)
+ ]);
+ define(newNode, { _generatedByEspower: true });
+ return newNode;
+};
+
+BabelAssertionVisitor.prototype.toBeSkipped = function (nodePath) {
+ return toBeSkipped(this.babel.types, nodePath);
+};
+
+BabelAssertionVisitor.prototype.toBeCaptured = function (nodePath) {
+ return toBeCaptured(this.babel.types, nodePath);
+};
+
+BabelAssertionVisitor.prototype.isArgumentModified = function () {
+ return !!this.argumentModified;
+};
+
+BabelAssertionVisitor.prototype.isCapturingArgument = function () {
+ return !!this.currentArgumentNodePath;
+};
+
+BabelAssertionVisitor.prototype.isLeavingAssertion = function (nodePath) {
+ return this.assertionNodePath === nodePath;
+};
+
+BabelAssertionVisitor.prototype.isLeavingArgument = function (nodePath) {
+ return this.currentArgumentNodePath === nodePath;
+};
+
+BabelAssertionVisitor.prototype.isGeneratedNode = function (nodePath) {
+ var currentNode = nodePath.node;
+ return !!currentNode._generatedByEspower;
+};
+
+// internal
+
+BabelAssertionVisitor.prototype.generateCanonicalCode = function (nodePath, node) {
+ var file = nodePath.hub.file;
+ var gen = new babelgen.CodeGenerator(node, { concise: true, comments: false });
+ var output = gen.generate();
+ this.canonicalCode = output.code;
+ if (!this.options.embedAst) {
+ return;
+ }
+ var astAndTokens = this.parseCanonicalCode(file, this.canonicalCode);
+ this.ast = JSON.stringify(this.purifyAst(astAndTokens.expression));
+ this.tokens = JSON.stringify(astAndTokens.tokens);
+ var _this = this;
+ var types = this.babel.types;
+ this.visitorKeys = this.getOrCreateNode(nodePath, 'powerAssertVisitorKeys', function () {
+ return types.stringLiteral(JSON.stringify(_this.options.visitorKeys));
+ });
+};
+
+BabelAssertionVisitor.prototype.parseCanonicalCode = function (file, code) {
+ var ast, tokens;
+
+ function doParse(wrapper) {
+ var content = wrapper ? wrapper(code) : code;
+ var output = file.parse(content);
+ if (wrapper) {
+ ast = output.program.body[0].body;
+ tokens = output.tokens.slice(6, -2);
+ } else {
+ ast = output.program;
+ tokens = output.tokens.slice(0, -1);
+ }
+ }
+
+ if (this.withinAsync) {
+ doParse(wrappedInAsync);
+ } else if (this.withinGenerator) {
+ doParse(wrappedInGenerator);
+ } else {
+ doParse();
+ }
+
+ var exp = ast.body[0].expression;
+ var columnOffset = exp.loc.start.column;
+ var offsetTree = estraverse.replace(exp, {
+ keys: this.options.visitorKeys,
+ enter: function (eachNode) {
+ eachNode.range = [
+ eachNode.loc.start.column - columnOffset,
+ eachNode.loc.end.column - columnOffset
+ ];
+ delete eachNode.loc;
+ return eachNode;
+ }
+ });
+
+ return {
+ tokens: offsetAndSlimDownTokens(tokens),
+ expression: offsetTree
+ };
+};
+
+function wrappedInGenerator (jsCode) {
+ return 'function *wrapper() { ' + jsCode + ' }';
+}
+
+function wrappedInAsync (jsCode) {
+ return 'async function wrapper() { ' + jsCode + ' }';
+}
+
+function offsetAndSlimDownTokens (tokens) {
+ var i, token, newToken, result = [];
+ var columnOffset;
+ for(i = 0; i < tokens.length; i += 1) {
+ token = tokens[i];
+ if (i === 0) {
+ columnOffset = token.loc.start.column;
+ }
+ newToken = {
+ type: {
+ label: token.type.label
+ }
+ };
+ if (typeof token.value !== 'undefined') {
+ newToken.value = token.value;
+ }
+ newToken.range = [
+ token.loc.start.column - columnOffset,
+ token.loc.end.column - columnOffset
+ ];
+ result.push(newToken);
+ }
+ return result;
+}
+
+BabelAssertionVisitor.prototype.captureArgument = function (node) {
+ var t = this.babel.types;
+ var props = {
+ content: this.canonicalCode,
+ filepath: this.location.source,
+ line: this.location.line
+ };
+ if (this.withinAsync) {
+ props.async = true;
+ }
+ if (this.withinGenerator) {
+ props.generator = true;
+ }
+ if (this.ast) {
+ props.ast = this.ast;
+ }
+ if (this.tokens) {
+ props.tokens = this.tokens;
+ }
+ var propsNode = t.valueToNode(props);
+ if (this.visitorKeys) {
+ var visitorKeysNode = t.objectProperty(t.identifier('visitorKeys'), this.visitorKeys);
+ propsNode.properties.push(visitorKeysNode);
+ }
+ var newNode = t.callExpression(
+ t.memberExpression(this.valueRecorder, t.identifier('_expr')),
+ [
+ node,
+ propsNode
+ ]
+ );
+ define(newNode, { _generatedByEspower: true });
+ return newNode;
+};
+
+BabelAssertionVisitor.prototype.verifyNotInstrumented = function (currentNode) {
+ var types = this.babel.types;
+ if (!types.isCallExpression(currentNode)) {
+ return;
+ }
+ if (!types.isMemberExpression(currentNode.callee)) {
+ return;
+ }
+ var prop = currentNode.callee.property;
+ if (types.isIdentifier(prop) && prop.name === '_expr') {
+ var errorMessage = '[espower] Attempted to transform AST twice.';
+ if (this.options.path) {
+ errorMessage += ' path: ' + this.options.path;
+ }
+ throw new Error(errorMessage);
+ }
+};
+
+BabelAssertionVisitor.prototype.createNewRecorder = function (nodePath) {
+ var _this = this;
+ var types = this.babel.types;
+ var helperNameNode = this.getOrCreateNode(nodePath, 'powerAssertRecorder', function () {
+ return types.toExpression(_this.helperTemplate());
+ });
+ var recorderIdent = nodePath.scope.generateUidIdentifier('rec');
+ define(recorderIdent, { _generatedByEspower: true });
+ var init = types.newExpression(helperNameNode, []);
+ define(init, { _generatedByEspower: true });
+ nodePath.scope.push({ id: recorderIdent, init: init });
+ return recorderIdent;
+};
+
+BabelAssertionVisitor.prototype.getOrCreateNode = function (nodePath, keyName, generateNode) {
+ var file = nodePath.hub.file;
+ var ident = file.get(keyName);
+ if (!ident) {
+ ident = this.createNode(nodePath, keyName, generateNode);
+ // helperNameNode = file.addImport('power-assert-runtime/recorder', 'default', 'recorder');
+ }
+ return ident;
+};
+
+BabelAssertionVisitor.prototype.createNode = function (nodePath, keyName, generateNode) {
+ var file = nodePath.hub.file;
+ var programScope = nodePath.scope.getProgramParent();
+ var ident = programScope.generateUidIdentifier(keyName);
+ define(ident, { _generatedByEspower: true });
+ file.set(keyName, ident);
+ var generatedNode = generateNode();
+ var visitorKeys = this.options.visitorKeys;
+ estraverse.traverse(generatedNode, {
+ keys: visitorKeys,
+ enter: function (node) {
+ define(node, { _generatedByEspower: true });
+ }
+ });
+ generatedNode._compact = true;
+ programScope.push({ id: ident, init: generatedNode });
+ return ident;
+};
+
+BabelAssertionVisitor.prototype.findEnclosingFunction = function (nodePath) {
+ if (!nodePath) {
+ return null;
+ }
+ if (this.babel.types.isFunction(nodePath.node)) {
+ return nodePath.node;
+ }
+ return this.findEnclosingFunction(nodePath.parentPath);
+};
+
+module.exports = BabelAssertionVisitor;
diff --git a/node_modules/babel-plugin-espower/lib/babel-espower-visitor.js b/node_modules/babel-plugin-espower/lib/babel-espower-visitor.js
new file mode 100644
index 000000000..61a7e37be
--- /dev/null
+++ b/node_modules/babel-plugin-espower/lib/babel-espower-visitor.js
@@ -0,0 +1,86 @@
+'use strict';
+
+var CallMatcher = require('call-matcher');
+var babylon = require('babylon');
+var assign = require('core-js/library/fn/object/assign');
+var find = require('core-js/library/fn/array/find');
+var BabelAssertionVisitor = require('./babel-assertion-visitor');
+
+function BabelEspowerVisitor (babel, opts) {
+ this.babel = babel;
+ this.matchers = opts.patterns.map(function (pattern) {
+ var signatureAst = babylon.parse(pattern);
+ var expression = signatureAst.program.body[0].expression;
+ return new CallMatcher(expression, opts);
+ });
+ this.options = opts;
+}
+
+BabelEspowerVisitor.prototype.enter = function (nodePath) {
+ var currentNode = nodePath.node;
+ var file = nodePath.hub.file;
+ var assertionVisitor = file.get('espowerAssertionVisitor');
+ if (assertionVisitor) {
+ if (assertionVisitor.isGeneratedNode(nodePath) || assertionVisitor.toBeSkipped(nodePath)) {
+ // skipping this Node
+ // MEMO: exit() will not be called when skip() is called
+ nodePath.skip();
+ return;
+ }
+ if (!assertionVisitor.isCapturingArgument() && !this.isCalleeOfParentCallExpression(nodePath)) {
+ // entering argument
+ assertionVisitor.enterArgument(nodePath);
+ }
+ } else if (nodePath.isCallExpression()) {
+ var matcher = find(this.matchers, function (m) { return m.test(currentNode); });
+ if (matcher) {
+ // entering assertion
+ var espowerOptions = assign({
+ path: file.opts.filename, // or opts.sourceFileName?
+ sourceMap: file.opts.inputSourceMap
+ }, this.options);
+ assertionVisitor = new BabelAssertionVisitor(this.babel, matcher, espowerOptions);
+ assertionVisitor.enter(nodePath);
+ file.set('espowerAssertionVisitor', assertionVisitor);
+ }
+ }
+};
+
+BabelEspowerVisitor.prototype.exit = function (nodePath) {
+ var currentNode = nodePath.node;
+ var resultTree = currentNode;
+ var file = nodePath.hub.file;
+ var assertionVisitor = file.get('espowerAssertionVisitor');
+ if (!assertionVisitor) {
+ return;
+ }
+ if (assertionVisitor.isLeavingAssertion(nodePath)) {
+ // leaving assertion
+ assertionVisitor.leave(nodePath);
+ file.delete('espowerAssertionVisitor');
+ return;
+ }
+ if (!assertionVisitor.isCapturingArgument()) {
+ return;
+ }
+ if (assertionVisitor.toBeCaptured(nodePath)) {
+ // capturing Node
+ resultTree = assertionVisitor.captureNode(nodePath);
+ }
+ if (assertionVisitor.isLeavingArgument(nodePath)) {
+ // capturing whole argument on leaving argument
+ resultTree = assertionVisitor.leaveArgument(resultTree);
+ }
+ if (resultTree !== currentNode) {
+ nodePath.replaceWith(resultTree);
+ }
+};
+
+BabelEspowerVisitor.prototype.isCalleeOfParentCallExpression = function (nodePath) {
+ var currentKey = nodePath.key;
+ var parentNode = nodePath.parent;
+ var types = this.babel.types;
+ return types.isCallExpression(parentNode) && currentKey === 'callee';
+};
+
+module.exports = BabelEspowerVisitor;
diff --git a/node_modules/babel-plugin-espower/lib/create-espower-visitor.js b/node_modules/babel-plugin-espower/lib/create-espower-visitor.js
new file mode 100644
index 000000000..eab911ab8
--- /dev/null
+++ b/node_modules/babel-plugin-espower/lib/create-espower-visitor.js
@@ -0,0 +1,32 @@
+'use strict';
+
+var defaultOptions = require('./default-options');
+var assign = require('core-js/library/fn/object/assign');
+var BabelEspowerVisitor = require('./babel-espower-visitor');
+
+module.exports = function createEspowerVisitor (babel, options) {
+ return {
+ visitor: {
+ Program: function (path, state) {
+ var opts = assign(defaultOptions(), {
+ astWhiteList: babel.types.BUILDER_KEYS,
+ visitorKeys: babel.types.VISITOR_KEYS,
+ sourceRoot: process.cwd()
+ }, options, state.opts);
+ var espowerVisitor = new BabelEspowerVisitor(babel, opts);
+ var innerVisitor = Object.keys(opts.visitorKeys).reduce(function (handlers, nodeType) {
+ handlers[nodeType] = {
+ enter: function (nodePath, pluginPass) {
+ espowerVisitor.enter(nodePath);
+ },
+ exit: function (nodePath, pluginPass) {
+ espowerVisitor.exit(nodePath);
+ }
+ };
+ return handlers;
+ }, {});
+ path.traverse(innerVisitor, state);
+ }
+ }
+ };
+};
diff --git a/node_modules/babel-plugin-espower/lib/default-options.js b/node_modules/babel-plugin-espower/lib/default-options.js
new file mode 100644
index 000000000..d9d6cc1c6
--- /dev/null
+++ b/node_modules/babel-plugin-espower/lib/default-options.js
@@ -0,0 +1,19 @@
+'use strict';
+
+module.exports = function defaultOptions () {
+ return {
+ embedAst: false,
+ patterns: [
+ 'assert(value, [message])',
+ 'assert.ok(value, [message])',
+ 'assert.equal(actual, expected, [message])',
+ 'assert.notEqual(actual, expected, [message])',
+ 'assert.strictEqual(actual, expected, [message])',
+ 'assert.notStrictEqual(actual, expected, [message])',
+ 'assert.deepEqual(actual, expected, [message])',
+ 'assert.notDeepEqual(actual, expected, [message])',
+ 'assert.deepStrictEqual(actual, expected, [message])',
+ 'assert.notDeepStrictEqual(actual, expected, [message])'
+ ]
+ };
+};
diff --git a/node_modules/babel-plugin-espower/lib/define-properties.js b/node_modules/babel-plugin-espower/lib/define-properties.js
new file mode 100644
index 000000000..9f86150fb
--- /dev/null
+++ b/node_modules/babel-plugin-espower/lib/define-properties.js
@@ -0,0 +1,12 @@
+'use strict';
+
+module.exports = function defineProperties (obj, map) {
+ Object.keys(map).forEach(function (name) {
+ Object.defineProperty(obj, name, {
+ configurable: true,
+ enumerable: false,
+ value: map[name],
+ writable: true
+ });
+ });
+};
diff --git a/node_modules/babel-plugin-espower/lib/power-assert-recorder.js b/node_modules/babel-plugin-espower/lib/power-assert-recorder.js
new file mode 100644
index 000000000..0e59999f5
--- /dev/null
+++ b/node_modules/babel-plugin-espower/lib/power-assert-recorder.js
@@ -0,0 +1,26 @@
+'use strict';
+module.exports = /* intentional newline */
+ function () {
+ function PowerAssertRecorder() {
+ this.captured = [];
+ }
+
+ PowerAssertRecorder.prototype._capt = function _capt (value, espath) {
+ this.captured.push({value: value, espath: espath});
+ return value;
+ };
+
+ PowerAssertRecorder.prototype._expr = function _expr (value, source) {
+ var capturedValues = this.captured;
+ this.captured = [];
+ return {
+ powerAssertContext: {
+ value: value,
+ events: capturedValues
+ },
+ source: source
+ };
+ };
+
+ return PowerAssertRecorder;
+}
diff --git a/node_modules/babel-plugin-espower/lib/to-be-captured.js b/node_modules/babel-plugin-espower/lib/to-be-captured.js
new file mode 100644
index 000000000..248fe5366
--- /dev/null
+++ b/node_modules/babel-plugin-espower/lib/to-be-captured.js
@@ -0,0 +1,56 @@
+'use strict';
+
+var typesToBeCaptured = [
+ 'Identifier',
+ 'BinaryExpression',
+ 'MemberExpression',
+ 'CallExpression',
+ 'UnaryExpression',
+ 'LogicalExpression',
+ 'ArrayExpression',
+ 'ObjectExpression',
+ 'TemplateLiteral',
+ 'YieldExpression',
+ 'AwaitExpression',
+ 'NewExpression',
+ 'AssignmentExpression',
+ 'UpdateExpression',
+ 'TaggedTemplateExpression'
+];
+
+function isCaputuringTargetType (types, nodePath) {
+ var currentNode = nodePath.node;
+ return typesToBeCaptured.some(function (nodeType) {
+ return types['is' + nodeType](currentNode);
+ });
+}
+
+function isCalleeOfParent(types, nodePath) {
+ var currentKey = nodePath.key;
+ var parentNode = nodePath.parent;
+ return (types.isCallExpression(parentNode) || types.isNewExpression(parentNode)) && currentKey === 'callee';
+}
+
+function isChildOfTaggedTemplateExpression(types, nodePath) {
+ var parentNode = nodePath.parent;
+ return types.isTaggedTemplateExpression(parentNode);
+}
+
+function isYieldOrAwaitArgument(types, nodePath) {
+ var currentKey = nodePath.key;
+ var parentNode = nodePath.parent;
+ // capture the yielded/await result, not the promise
+ return (types.isYieldExpression(parentNode) || types.isAwaitExpression(parentNode)) && currentKey === 'argument';
+}
+
+var blacklist = [
+ isYieldOrAwaitArgument,
+ isCalleeOfParent,
+ isChildOfTaggedTemplateExpression
+];
+
+module.exports = function toBeCaptured (types, nodePath) {
+ return isCaputuringTargetType(types, nodePath) && !blacklist.some(function (predicate) {
+ return predicate(types, nodePath);
+ });
+};
diff --git a/node_modules/babel-plugin-espower/lib/to-be-skipped.js b/node_modules/babel-plugin-espower/lib/to-be-skipped.js
new file mode 100644
index 000000000..92b2528c8
--- /dev/null
+++ b/node_modules/babel-plugin-espower/lib/to-be-skipped.js
@@ -0,0 +1,107 @@
+'use strict';
+
+var typesNotToBeSkippedDuringCapturing = [
+ 'Identifier',
+ 'BinaryExpression',
+ 'MemberExpression',
+ 'CallExpression',
+ 'UnaryExpression',
+ 'LogicalExpression',
+ 'ArrayExpression',
+ 'ObjectExpression',
+ 'SequenceExpression',
+ 'TemplateLiteral',
+ 'YieldExpression',
+ 'AwaitExpression',
+ 'NewExpression',
+ 'AssignmentExpression',
+ 'UpdateExpression',
+ 'TaggedTemplateExpression',
+ 'ConditionalExpression',
+ 'SpreadElement',
+ 'Property'
+];
+
+function isTypeNotToBeSkippedDuringCapturing (types, nodePath) {
+ var currentNode = nodePath.node;
+ return typesNotToBeSkippedDuringCapturing.some(function (nodeType) {
+ return types['is' + nodeType](currentNode);
+ });
+}
+
+function isTypeToBeSkippedDuringCapturing (types, nodePath) {
+ return !isTypeNotToBeSkippedDuringCapturing(types, nodePath);
+}
+
+function isLeftHandSideOfAssignment(types, nodePath) {
+ var currentKey = nodePath.key;
+ var parentNode = nodePath.parent;
+ // Do not instrument left due to 'Invalid left-hand side in assignment'
+ return types.isAssignmentExpression(parentNode) && currentKey === 'left';
+}
+
+function isChildOfObjectLiteral (types, parentNode) {
+ return types.isObjectProperty(parentNode) ||
+ types.isObjectMethod(parentNode) ||
+ types.isSpreadProperty(parentNode);
+}
+
+function isObjectLiteralKey (types, parentNode, currentKey) {
+ return isChildOfObjectLiteral(types, parentNode) && currentKey === 'key';
+}
+
+function isObjectLiteralValue (types, parentNode, currentKey) {
+ return isChildOfObjectLiteral(types, parentNode) && currentKey === 'value';
+}
+
+function isNonComputedObjectLiteralKey(types, nodePath) {
+ var currentKey = nodePath.key;
+ var parentNode = nodePath.parent;
+ // Do not instrument non-computed Object literal key
+ return isObjectLiteralKey(types, parentNode, currentKey) && !parentNode.computed;
+}
+
+function isShorthandedValueOfObjectLiteral(types, nodePath) {
+ var currentKey = nodePath.key;
+ var parentNode = nodePath.parent;
+ // Do not instrument shorthanded Object literal value
+ return isObjectLiteralValue(types, parentNode, currentKey) && parentNode.shorthand;
+}
+
+function isUpdateExpression(types, nodePath) {
+ var parentNode = nodePath.parent;
+ // Just wrap UpdateExpression, not digging in.
+ return types.isUpdateExpression(parentNode);
+}
+
+function isCallExpressionWithNonComputedMemberExpression(types, nodePath) {
+ var currentKey = nodePath.key;
+ var currentNode = nodePath.node;
+ var parentNode = nodePath.parent;
+ // Do not instrument non-computed property of MemberExpression within CallExpression.
+ return types.isIdentifier(currentNode) && types.isMemberExpression(parentNode) && !parentNode.computed && currentKey === 'property';
+}
+
+function isTypeOfOrDeleteUnaryExpression(types, nodePath) {
+ var currentKey = nodePath.key;
+ var currentNode = nodePath.node;
+ var parentNode = nodePath.parent;
+ // 'typeof Identifier' or 'delete Identifier' is not instrumented
+ return types.isIdentifier(currentNode) && types.isUnaryExpression(parentNode) && (parentNode.operator === 'typeof' || parentNode.operator === 'delete') && currentKey === 'argument';
+}
+
+var criteriaForSkipping = [
+ isTypeToBeSkippedDuringCapturing,
+ isLeftHandSideOfAssignment,
+ isNonComputedObjectLiteralKey,
+ isShorthandedValueOfObjectLiteral,
+ isUpdateExpression,
+ isCallExpressionWithNonComputedMemberExpression,
+ isTypeOfOrDeleteUnaryExpression,
+];
+
+module.exports = function toBeSkipped (types, nodePath) {
+ return criteriaForSkipping.some(function (predicate) {
+ return predicate(types, nodePath);
+ });
+};