text: 'use strict';
  
  var _assign = require('babel-runtime/core-js/object/assign');
  
  var _assign2 = _interopRequireDefault(_assign);
  
  var _slicedToArray2 = require('babel-runtime/helpers/slicedToArray');
  
  var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);
  
  var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');
  
  var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);
  
  var _entries = require('babel-runtime/core-js/object/entries');
  
  var _entries2 = _interopRequireDefault(_entries);
  
  var _keys = require('babel-runtime/core-js/object/keys');
  
  var _keys2 = _interopRequireDefault(_keys);
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  var _glob = require('glob-to-regexp');
  var _express = require('path-to-regexp');
  var URL = require('url');
  var querystring = require('querystring');
  
  function normalizeRequest(url, options, Request) {
  	if (Request.prototype.isPrototypeOf(url)) {
  		return {
  			url: url.url,
  			method: url.method,
  			headers: function () {
  				var headers = {};
  				url.headers.forEach(function (name) {
  					return headers[name] = url.headers.name;
  				});
  				return headers;
  			}()
  		};
  	} else {
  		return {
  			url: url,
  			method: options && options.method || 'GET',
  			headers: options && options.headers
  		};
  	}
  }
  
  var stringMatchers = {
  	begin: function begin(targetString) {
  		return function (_ref) {
  			var url = _ref.url;
  			return url.indexOf(targetString) === 0;
  		};
  	},
  	end: function end(targetString) {
  		return function (_ref2) {
  			var url = _ref2.url;
  			return url.substr(-targetString.length) === targetString;
  		};
  	},
  	glob: function glob(targetString) {
  		var urlRX = _glob(targetString);
  		return function (_ref3) {
  			var url = _ref3.url;
  			return urlRX.test(url);
  		};
  	},
  	express: function express(targetString) {
  		var urlRX = _express(targetString);
  		return function (_ref4) {
  			var url = _ref4.url;
  			return urlRX.test(url);
  		};
  	}
  };
  
  var headersToLowerCase = function headersToLowerCase(headers) {
  	return (0, _keys2.default)(headers).reduce(function (obj, k) {
  		obj[k.toLowerCase()] = headers[k];
  		return obj;
  	}, {});
  };
  
  function areHeadersEqual(actualHeader, expectedHeader) {
  	actualHeader = Array.isArray(actualHeader) ? actualHeader : [actualHeader];
  	expectedHeader = Array.isArray(expectedHeader) ? expectedHeader : [expectedHeader];
  
  	if (actualHeader.length !== expectedHeader.length) {
  		return false;
  	}
  
  	return actualHeader.every(function (val, i) {
  		return val === expectedHeader[i];
  	});
  }
  
  function getHeaderMatcher(_ref5, Headers) {
  	var expectedHeaders = _ref5.headers;
  
  	if (!expectedHeaders) {
  		return function () {
  			return true;
  		};
  	}
  	var expectation = headersToLowerCase(expectedHeaders);
  
  	return function (_ref6) {
  		var _ref6$headers = _ref6.headers,
  		    headers = _ref6$headers === undefined ? {} : _ref6$headers;
  
  		if (headers instanceof Headers) {
  			// node-fetch 1 Headers
  			if (typeof headers.raw === 'function') {
  				headers = (0, _entries2.default)(headers.raw());
  			}
  			headers = [].concat((0, _toConsumableArray3.default)(headers)).reduce(function (map, _ref7) {
  				var _ref8 = (0, _slicedToArray3.default)(_ref7, 2),
  				    key = _ref8[0],
  				    val = _ref8[1];
  
  				map[key] = val;
  				return map;
  			}, {});
  		}
  
  		var lowerCaseHeaders = headersToLowerCase(headers);
  
  		return (0, _keys2.default)(expectation).every(function (headerName) {
  			return areHeadersEqual(lowerCaseHeaders[headerName], expectation[headerName]);
  		});
  	};
  }
  
  var getMethodMatcher = function getMethodMatcher(route) {
  	return function (_ref9) {
  		var method = _ref9.method;
  
  		return !route.method || route.method === (method ? method.toLowerCase() : 'get');
  	};
  };
  
  var getQueryStringMatcher = function getQueryStringMatcher(route) {
  	if (!route.query) {
  		return function () {
  			return true;
  		};
  	}
  	var keys = (0, _keys2.default)(route.query);
  	return function (_ref10) {
  		var url = _ref10.url;
  
  		var query = querystring.parse(URL.parse(url).query);
  		return keys.every(function (key) {
  			return query[key] === route.query[key];
  		});
  	};
  };
  
  var getUrlMatcher = function getUrlMatcher(route) {
  
  	// When the matcher is a function it shodul not be compared with the url
  	// in the normal way
  	if (typeof route.matcher === 'function') {
  		return function () {
  			return true;
  		};
  	}
  
  	if (route.matcher instanceof RegExp) {
  		var urlRX = route.matcher;
  		return function (_ref11) {
  			var url = _ref11.url;
  			return urlRX.test(url);
  		};
  	}
  
  	if (route.matcher === '*') {
  		return function () {
  			return true;
  		};
  	}
  
  	if (route.matcher.indexOf('^') === 0) {
  		throw new Error('Using \'^\' to denote the start of a url is deprecated. Use \'begin:\' instead');
  	}
  
  	for (var shorthand in stringMatchers) {
  		if (route.matcher.indexOf(shorthand + ':') === 0) {
  			var url = route.matcher.replace(new RegExp('^' + shorthand + ':'), '');
  			return stringMatchers[shorthand](url);
  		}
  	}
  
  	// if none of the special syntaxes apply, it's just a simple string match
  	var expectedUrl = route.matcher;
  	return function (_ref12) {
  		var url = _ref12.url;
  
  		if (route.query && expectedUrl.indexOf('?')) {
  			return url.indexOf(expectedUrl) === 0;
  		}
  		return url === expectedUrl;
  	};
  };
  
  var sanitizeRoute = function sanitizeRoute(route) {
  	route = (0, _assign2.default)({}, route);
  
  	if (typeof route.response === 'undefined') {
  		throw new Error('Each route must define a response');
  	}
  
  	if (!route.matcher) {
  		throw new Error('Each route must specify a string, regex or function to match calls to fetch');
  	}
  
  	if (!route.name) {
  		route.name = route.matcher.toString();
  		route.__unnamed = true;
  	}
  
  	if (route.method) {
  		route.method = route.method.toLowerCase();
  	}
  
  	return route;
  };
  
  var getFunctionMatcher = function getFunctionMatcher(route) {
  	if (typeof route.matcher === 'function') {
  		var matcher = route.matcher;
  		return function (req, _ref13) {
  			var _ref14 = (0, _slicedToArray3.default)(_ref13, 2),
  			    url = _ref14[0],
  			    options = _ref14[1];
  
  			return matcher(url, options);
  		};
  	} else {
  		return function () {
  			return true;
  		};
  	}
  };
  
  var generateMatcher = function generateMatcher(route, config) {
  	var matchers = [getQueryStringMatcher(route), getMethodMatcher(route), getHeaderMatcher(route, config.Headers), getUrlMatcher(route), getFunctionMatcher(route)];
  
  	return function (url, options) {
  		var req = normalizeRequest(url, options, config.Request);
  		return matchers.every(function (matcher) {
  			return matcher(req, [url, options]);
  		});
  	};
  };
  
  var limitMatcher = function limitMatcher(route) {
  	if (!route.repeat) {
  		return;
  	}
  
  	var matcher = route.matcher;
  	var timesLeft = route.repeat;
  	route.matcher = function (url, options) {
  		var match = timesLeft && matcher(url, options);
  		if (match) {
  			timesLeft--;
  			return true;
  		}
  	};
  	route.reset = function () {
  		return timesLeft = route.repeat;
  	};
  };
  
  module.exports = function (route) {
  	route = sanitizeRoute(route);
  
  	route.matcher = generateMatcher(route, this.config);
  
  	limitMatcher(route);
  
  	return route;
  };