'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

exports.default = function (_ref) {
  var t = _ref.types,
      template = _ref.template;

  var generator = template('\n    UNTIL_FUNC(async fail => {\n      try {\n        ASSERT_CALL;\n        return true;\n      } catch (err) {\n        return fail(err);\n      }\n    }, UNTIL_ARGS)\n  ');

  return {
    name: 'assert-async',
    visitor: {
      CallExpression: function CallExpression(path, state) {
        // assuming `assert.async.something(arg1, arg2)`

        // assert.async.something
        var callee = path.node.callee;
        if (!t.isMemberExpression(callee)) {
          return;
        }
        // assert.async
        var calleeObject = callee.object;
        var asyncArgs = [];
        // support `assert.async(200).something(arg1, arg2)` for setting timeout
        // in this case, `calleeObject` is actually `assert.async(200)` not `assert.async`
        if (t.isCallExpression(calleeObject)) {
          asyncArgs = calleeObject.arguments; // [200]
          calleeObject = calleeObject.callee; // assert.async
        }
        if (!t.isMemberExpression(calleeObject)) {
          return;
        }

        var calleeObjectObject = calleeObject.object;
        var calleeObjectProperty = calleeObject.property;

        if (!t.isIdentifier(calleeObjectObject) || calleeObjectObject.name !== 'assert') {
          return;
        }
        if (!t.isIdentifier(calleeObjectProperty) || calleeObjectProperty.name !== 'async') {
          return;
        }

        // path === assert.async.something(arg1, arg2)

        // [arg1, arg2]
        var callArgs = path.node.arguments;

        // "assert"
        var assert = calleeObject.object.name;
        // "something"
        var meth = callee.property.name;

        if (t.isExpressionStatement(path.parent)) {
          var error = assert + '.async.' + meth + ' cannot be used as a statement (did you forget to \'await\' it?)';
          throw path.buildCodeFrameError(error);
        }

        // assert.something
        var assertDotMethod = t.memberExpression(t.identifier(assert), t.identifier(meth));
        // assert.something(arg1, arg2)
        var assertExpression = t.callExpression(assertDotMethod, callArgs);

        path.replaceWith(generator({
          ASSERT_CALL: assertExpression,
          UNTIL_ARGS: asyncArgs,
          UNTIL_FUNC: state.addImport('test-until', 'default', 'until')
        }));
      }
    }
  };
};

;