'use strict'; var t = require('babel-types'); var template = require('babel-template'); var wrapWithHelper = template([ 'HELPER_ID(function () {', ' return EXP;', '}, {', ' line: LINE,', ' column: COLUMN,', ' source: SOURCE,', ' filename: FILE', '});' ].join('\n')); var buildHelper = template([ 'function HELPER_ID(fn, data) {', ' try {', ' return fn();', ' } catch (e) {', ' var type = typeof e;', ' if (e !== null && (type === "object" || type === "function")) {', ' try {', ' Object.defineProperty(e, "_avaThrowsHelperData", {', ' value: data', ' });', ' } catch (e) {}', ' }', ' throw e;', ' }', '}' ].join('\n')); var assertionVisitor = { CallExpression: function (path, state) { if (isThrowsMember(path.get('callee'))) { var arg0 = path.node.arguments[0]; path.node.arguments[0] = wrapWithHelper({ HELPER_ID: t.identifier(this.avaThrowHelper()), EXP: arg0, LINE: t.numericLiteral(arg0.loc.start.line), COLUMN: t.numericLiteral(arg0.loc.start.column), SOURCE: t.stringLiteral(state.file.code.substring(arg0.start, arg0.end)), FILE: t.stringLiteral(state.file.opts.filename) }).expression; } } }; module.exports = function () { return { visitor: { Program: function (path, state) { var HELPER_ID = path.scope.generateUid('avaThrowsHelper'); var created = false; path.traverse(assertionVisitor, { avaThrowHelper: function () { if (!created) { created = true; path.unshiftContainer('body', buildHelper({ HELPER_ID: t.identifier(HELPER_ID) })); } return HELPER_ID; }, file: state.file }); } } }; }; function isThrowsMember(path) { return path.isMemberExpression() && path.get('object').isIdentifier({name: 't'}) && ( path.get('property').isIdentifier({name: 'throws'}) || path.get('property').isIdentifier({name: 'notThrows'}) ); }