Merge pull request #639 from github/dependabot/npm_and_yarn/nock-13.1.1

Bump nock from 12.0.3 to 13.1.1
This commit is contained in:
Edoardo Pirovano 2021-07-27 18:54:22 +01:00 committed by GitHub
commit cc561bc122
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 1778 additions and 653 deletions

13
node_modules/.package-lock.json generated vendored
View file

@ -3351,6 +3351,12 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/lodash.set": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
"integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=",
"dev": true
},
"node_modules/lodash.snakecase": { "node_modules/lodash.snakecase": {
"version": "4.1.1", "version": "4.1.1",
"dev": true, "dev": true,
@ -3573,13 +3579,14 @@
} }
}, },
"node_modules/nock": { "node_modules/nock": {
"version": "12.0.3", "version": "13.1.1",
"resolved": "https://registry.npmjs.org/nock/-/nock-13.1.1.tgz",
"integrity": "sha512-YKTR9MjfK3kS9/l4nuTxyYm30cgOExRHzkLNhL8nhEUyU4f8Za/dRxOqjhVT1vGs0svWo3dDnJTUX1qxYeWy5w==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"debug": "^4.1.0", "debug": "^4.1.0",
"json-stringify-safe": "^5.0.1", "json-stringify-safe": "^5.0.1",
"lodash": "^4.17.13", "lodash.set": "^4.3.2",
"propagate": "^2.0.0" "propagate": "^2.0.0"
}, },
"engines": { "engines": {

47
node_modules/lodash.set/LICENSE generated vendored Normal file
View file

@ -0,0 +1,47 @@
Copyright jQuery Foundation and other contributors <https://jquery.org/>
Based on Underscore.js, copyright Jeremy Ashkenas,
DocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>
This software consists of voluntary contributions made by many
individuals. For exact contribution history, see the revision history
available at https://github.com/lodash/lodash
The following license applies to all parts of this software except as
documented below:
====
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
====
Copyright and related rights for sample code are waived via CC0. Sample
code is defined as all source code displayed within the prose of the
documentation.
CC0: http://creativecommons.org/publicdomain/zero/1.0/
====
Files located in the node_modules and vendor directories are externally
maintained libraries used by this software which have their own
licenses; we recommend you read them, as their terms may differ from the
terms above.

18
node_modules/lodash.set/README.md generated vendored Normal file
View file

@ -0,0 +1,18 @@
# lodash.set v4.3.2
The [lodash](https://lodash.com/) method `_.set` exported as a [Node.js](https://nodejs.org/) module.
## Installation
Using npm:
```bash
$ {sudo -H} npm i -g npm
$ npm i --save lodash.set
```
In Node.js:
```js
var set = require('lodash.set');
```
See the [documentation](https://lodash.com/docs#set) or [package source](https://github.com/lodash/lodash/blob/4.3.2-npm-packages/lodash.set) for more details.

990
node_modules/lodash.set/index.js generated vendored Normal file
View file

@ -0,0 +1,990 @@
/**
* lodash (Custom Build) <https://lodash.com/>
* Build: `lodash modularize exports="npm" -o ./`
* Copyright jQuery Foundation and other contributors <https://jquery.org/>
* Released under MIT license <https://lodash.com/license>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
*/
/** Used as the `TypeError` message for "Functions" methods. */
var FUNC_ERROR_TEXT = 'Expected a function';
/** Used to stand-in for `undefined` hash values. */
var HASH_UNDEFINED = '__lodash_hash_undefined__';
/** Used as references for various `Number` constants. */
var INFINITY = 1 / 0,
MAX_SAFE_INTEGER = 9007199254740991;
/** `Object#toString` result references. */
var funcTag = '[object Function]',
genTag = '[object GeneratorFunction]',
symbolTag = '[object Symbol]';
/** Used to match property names within property paths. */
var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
reIsPlainProp = /^\w*$/,
reLeadingDot = /^\./,
rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
/**
* Used to match `RegExp`
* [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
*/
var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
/** Used to match backslashes in property paths. */
var reEscapeChar = /\\(\\)?/g;
/** Used to detect host constructors (Safari). */
var reIsHostCtor = /^\[object .+?Constructor\]$/;
/** Used to detect unsigned integer values. */
var reIsUint = /^(?:0|[1-9]\d*)$/;
/** Detect free variable `global` from Node.js. */
var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
/** Detect free variable `self`. */
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
/** Used as a reference to the global object. */
var root = freeGlobal || freeSelf || Function('return this')();
/**
* Gets the value at `key` of `object`.
*
* @private
* @param {Object} [object] The object to query.
* @param {string} key The key of the property to get.
* @returns {*} Returns the property value.
*/
function getValue(object, key) {
return object == null ? undefined : object[key];
}
/**
* Checks if `value` is a host object in IE < 9.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a host object, else `false`.
*/
function isHostObject(value) {
// Many host objects are `Object` objects that can coerce to strings
// despite having improperly defined `toString` methods.
var result = false;
if (value != null && typeof value.toString != 'function') {
try {
result = !!(value + '');
} catch (e) {}
}
return result;
}
/** Used for built-in method references. */
var arrayProto = Array.prototype,
funcProto = Function.prototype,
objectProto = Object.prototype;
/** Used to detect overreaching core-js shims. */
var coreJsData = root['__core-js_shared__'];
/** Used to detect methods masquerading as native. */
var maskSrcKey = (function() {
var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
return uid ? ('Symbol(src)_1.' + uid) : '';
}());
/** Used to resolve the decompiled source of functions. */
var funcToString = funcProto.toString;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var objectToString = objectProto.toString;
/** Used to detect if a method is native. */
var reIsNative = RegExp('^' +
funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
.replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
);
/** Built-in value references. */
var Symbol = root.Symbol,
splice = arrayProto.splice;
/* Built-in method references that are verified to be native. */
var Map = getNative(root, 'Map'),
nativeCreate = getNative(Object, 'create');
/** Used to convert symbols to primitives and strings. */
var symbolProto = Symbol ? Symbol.prototype : undefined,
symbolToString = symbolProto ? symbolProto.toString : undefined;
/**
* Creates a hash object.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function Hash(entries) {
var index = -1,
length = entries ? entries.length : 0;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}
/**
* Removes all key-value entries from the hash.
*
* @private
* @name clear
* @memberOf Hash
*/
function hashClear() {
this.__data__ = nativeCreate ? nativeCreate(null) : {};
}
/**
* Removes `key` and its value from the hash.
*
* @private
* @name delete
* @memberOf Hash
* @param {Object} hash The hash to modify.
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function hashDelete(key) {
return this.has(key) && delete this.__data__[key];
}
/**
* Gets the hash value for `key`.
*
* @private
* @name get
* @memberOf Hash
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function hashGet(key) {
var data = this.__data__;
if (nativeCreate) {
var result = data[key];
return result === HASH_UNDEFINED ? undefined : result;
}
return hasOwnProperty.call(data, key) ? data[key] : undefined;
}
/**
* Checks if a hash value for `key` exists.
*
* @private
* @name has
* @memberOf Hash
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function hashHas(key) {
var data = this.__data__;
return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);
}
/**
* Sets the hash `key` to `value`.
*
* @private
* @name set
* @memberOf Hash
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
* @returns {Object} Returns the hash instance.
*/
function hashSet(key, value) {
var data = this.__data__;
data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
return this;
}
// Add methods to `Hash`.
Hash.prototype.clear = hashClear;
Hash.prototype['delete'] = hashDelete;
Hash.prototype.get = hashGet;
Hash.prototype.has = hashHas;
Hash.prototype.set = hashSet;
/**
* Creates an list cache object.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function ListCache(entries) {
var index = -1,
length = entries ? entries.length : 0;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}
/**
* Removes all key-value entries from the list cache.
*
* @private
* @name clear
* @memberOf ListCache
*/
function listCacheClear() {
this.__data__ = [];
}
/**
* Removes `key` and its value from the list cache.
*
* @private
* @name delete
* @memberOf ListCache
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function listCacheDelete(key) {
var data = this.__data__,
index = assocIndexOf(data, key);
if (index < 0) {
return false;
}
var lastIndex = data.length - 1;
if (index == lastIndex) {
data.pop();
} else {
splice.call(data, index, 1);
}
return true;
}
/**
* Gets the list cache value for `key`.
*
* @private
* @name get
* @memberOf ListCache
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function listCacheGet(key) {
var data = this.__data__,
index = assocIndexOf(data, key);
return index < 0 ? undefined : data[index][1];
}
/**
* Checks if a list cache value for `key` exists.
*
* @private
* @name has
* @memberOf ListCache
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function listCacheHas(key) {
return assocIndexOf(this.__data__, key) > -1;
}
/**
* Sets the list cache `key` to `value`.
*
* @private
* @name set
* @memberOf ListCache
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
* @returns {Object} Returns the list cache instance.
*/
function listCacheSet(key, value) {
var data = this.__data__,
index = assocIndexOf(data, key);
if (index < 0) {
data.push([key, value]);
} else {
data[index][1] = value;
}
return this;
}
// Add methods to `ListCache`.
ListCache.prototype.clear = listCacheClear;
ListCache.prototype['delete'] = listCacheDelete;
ListCache.prototype.get = listCacheGet;
ListCache.prototype.has = listCacheHas;
ListCache.prototype.set = listCacheSet;
/**
* Creates a map cache object to store key-value pairs.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function MapCache(entries) {
var index = -1,
length = entries ? entries.length : 0;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}
/**
* Removes all key-value entries from the map.
*
* @private
* @name clear
* @memberOf MapCache
*/
function mapCacheClear() {
this.__data__ = {
'hash': new Hash,
'map': new (Map || ListCache),
'string': new Hash
};
}
/**
* Removes `key` and its value from the map.
*
* @private
* @name delete
* @memberOf MapCache
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function mapCacheDelete(key) {
return getMapData(this, key)['delete'](key);
}
/**
* Gets the map value for `key`.
*
* @private
* @name get
* @memberOf MapCache
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function mapCacheGet(key) {
return getMapData(this, key).get(key);
}
/**
* Checks if a map value for `key` exists.
*
* @private
* @name has
* @memberOf MapCache
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function mapCacheHas(key) {
return getMapData(this, key).has(key);
}
/**
* Sets the map `key` to `value`.
*
* @private
* @name set
* @memberOf MapCache
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
* @returns {Object} Returns the map cache instance.
*/
function mapCacheSet(key, value) {
getMapData(this, key).set(key, value);
return this;
}
// Add methods to `MapCache`.
MapCache.prototype.clear = mapCacheClear;
MapCache.prototype['delete'] = mapCacheDelete;
MapCache.prototype.get = mapCacheGet;
MapCache.prototype.has = mapCacheHas;
MapCache.prototype.set = mapCacheSet;
/**
* Assigns `value` to `key` of `object` if the existing value is not equivalent
* using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
* for equality comparisons.
*
* @private
* @param {Object} object The object to modify.
* @param {string} key The key of the property to assign.
* @param {*} value The value to assign.
*/
function assignValue(object, key, value) {
var objValue = object[key];
if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
(value === undefined && !(key in object))) {
object[key] = value;
}
}
/**
* Gets the index at which the `key` is found in `array` of key-value pairs.
*
* @private
* @param {Array} array The array to inspect.
* @param {*} key The key to search for.
* @returns {number} Returns the index of the matched value, else `-1`.
*/
function assocIndexOf(array, key) {
var length = array.length;
while (length--) {
if (eq(array[length][0], key)) {
return length;
}
}
return -1;
}
/**
* The base implementation of `_.isNative` without bad shim checks.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a native function,
* else `false`.
*/
function baseIsNative(value) {
if (!isObject(value) || isMasked(value)) {
return false;
}
var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor;
return pattern.test(toSource(value));
}
/**
* The base implementation of `_.set`.
*
* @private
* @param {Object} object The object to modify.
* @param {Array|string} path The path of the property to set.
* @param {*} value The value to set.
* @param {Function} [customizer] The function to customize path creation.
* @returns {Object} Returns `object`.
*/
function baseSet(object, path, value, customizer) {
if (!isObject(object)) {
return object;
}
path = isKey(path, object) ? [path] : castPath(path);
var index = -1,
length = path.length,
lastIndex = length - 1,
nested = object;
while (nested != null && ++index < length) {
var key = toKey(path[index]),
newValue = value;
if (index != lastIndex) {
var objValue = nested[key];
newValue = customizer ? customizer(objValue, key, nested) : undefined;
if (newValue === undefined) {
newValue = isObject(objValue)
? objValue
: (isIndex(path[index + 1]) ? [] : {});
}
}
assignValue(nested, key, newValue);
nested = nested[key];
}
return object;
}
/**
* The base implementation of `_.toString` which doesn't convert nullish
* values to empty strings.
*
* @private
* @param {*} value The value to process.
* @returns {string} Returns the string.
*/
function baseToString(value) {
// Exit early for strings to avoid a performance hit in some environments.
if (typeof value == 'string') {
return value;
}
if (isSymbol(value)) {
return symbolToString ? symbolToString.call(value) : '';
}
var result = (value + '');
return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
}
/**
* Casts `value` to a path array if it's not one.
*
* @private
* @param {*} value The value to inspect.
* @returns {Array} Returns the cast property path array.
*/
function castPath(value) {
return isArray(value) ? value : stringToPath(value);
}
/**
* Gets the data for `map`.
*
* @private
* @param {Object} map The map to query.
* @param {string} key The reference key.
* @returns {*} Returns the map data.
*/
function getMapData(map, key) {
var data = map.__data__;
return isKeyable(key)
? data[typeof key == 'string' ? 'string' : 'hash']
: data.map;
}
/**
* Gets the native function at `key` of `object`.
*
* @private
* @param {Object} object The object to query.
* @param {string} key The key of the method to get.
* @returns {*} Returns the function if it's native, else `undefined`.
*/
function getNative(object, key) {
var value = getValue(object, key);
return baseIsNative(value) ? value : undefined;
}
/**
* Checks if `value` is a valid array-like index.
*
* @private
* @param {*} value The value to check.
* @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
* @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
*/
function isIndex(value, length) {
length = length == null ? MAX_SAFE_INTEGER : length;
return !!length &&
(typeof value == 'number' || reIsUint.test(value)) &&
(value > -1 && value % 1 == 0 && value < length);
}
/**
* Checks if `value` is a property name and not a property path.
*
* @private
* @param {*} value The value to check.
* @param {Object} [object] The object to query keys on.
* @returns {boolean} Returns `true` if `value` is a property name, else `false`.
*/
function isKey(value, object) {
if (isArray(value)) {
return false;
}
var type = typeof value;
if (type == 'number' || type == 'symbol' || type == 'boolean' ||
value == null || isSymbol(value)) {
return true;
}
return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
(object != null && value in Object(object));
}
/**
* Checks if `value` is suitable for use as unique object key.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is suitable, else `false`.
*/
function isKeyable(value) {
var type = typeof value;
return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
? (value !== '__proto__')
: (value === null);
}
/**
* Checks if `func` has its source masked.
*
* @private
* @param {Function} func The function to check.
* @returns {boolean} Returns `true` if `func` is masked, else `false`.
*/
function isMasked(func) {
return !!maskSrcKey && (maskSrcKey in func);
}
/**
* Converts `string` to a property path array.
*
* @private
* @param {string} string The string to convert.
* @returns {Array} Returns the property path array.
*/
var stringToPath = memoize(function(string) {
string = toString(string);
var result = [];
if (reLeadingDot.test(string)) {
result.push('');
}
string.replace(rePropName, function(match, number, quote, string) {
result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
});
return result;
});
/**
* Converts `value` to a string key if it's not a string or symbol.
*
* @private
* @param {*} value The value to inspect.
* @returns {string|symbol} Returns the key.
*/
function toKey(value) {
if (typeof value == 'string' || isSymbol(value)) {
return value;
}
var result = (value + '');
return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
}
/**
* Converts `func` to its source code.
*
* @private
* @param {Function} func The function to process.
* @returns {string} Returns the source code.
*/
function toSource(func) {
if (func != null) {
try {
return funcToString.call(func);
} catch (e) {}
try {
return (func + '');
} catch (e) {}
}
return '';
}
/**
* Creates a function that memoizes the result of `func`. If `resolver` is
* provided, it determines the cache key for storing the result based on the
* arguments provided to the memoized function. By default, the first argument
* provided to the memoized function is used as the map cache key. The `func`
* is invoked with the `this` binding of the memoized function.
*
* **Note:** The cache is exposed as the `cache` property on the memoized
* function. Its creation may be customized by replacing the `_.memoize.Cache`
* constructor with one whose instances implement the
* [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
* method interface of `delete`, `get`, `has`, and `set`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Function
* @param {Function} func The function to have its output memoized.
* @param {Function} [resolver] The function to resolve the cache key.
* @returns {Function} Returns the new memoized function.
* @example
*
* var object = { 'a': 1, 'b': 2 };
* var other = { 'c': 3, 'd': 4 };
*
* var values = _.memoize(_.values);
* values(object);
* // => [1, 2]
*
* values(other);
* // => [3, 4]
*
* object.a = 2;
* values(object);
* // => [1, 2]
*
* // Modify the result cache.
* values.cache.set(object, ['a', 'b']);
* values(object);
* // => ['a', 'b']
*
* // Replace `_.memoize.Cache`.
* _.memoize.Cache = WeakMap;
*/
function memoize(func, resolver) {
if (typeof func != 'function' || (resolver && typeof resolver != 'function')) {
throw new TypeError(FUNC_ERROR_TEXT);
}
var memoized = function() {
var args = arguments,
key = resolver ? resolver.apply(this, args) : args[0],
cache = memoized.cache;
if (cache.has(key)) {
return cache.get(key);
}
var result = func.apply(this, args);
memoized.cache = cache.set(key, result);
return result;
};
memoized.cache = new (memoize.Cache || MapCache);
return memoized;
}
// Assign cache to `_.memoize`.
memoize.Cache = MapCache;
/**
* Performs a
* [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
* comparison between two values to determine if they are equivalent.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @returns {boolean} Returns `true` if the values are equivalent, else `false`.
* @example
*
* var object = { 'a': 1 };
* var other = { 'a': 1 };
*
* _.eq(object, object);
* // => true
*
* _.eq(object, other);
* // => false
*
* _.eq('a', 'a');
* // => true
*
* _.eq('a', Object('a'));
* // => false
*
* _.eq(NaN, NaN);
* // => true
*/
function eq(value, other) {
return value === other || (value !== value && other !== other);
}
/**
* Checks if `value` is classified as an `Array` object.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an array, else `false`.
* @example
*
* _.isArray([1, 2, 3]);
* // => true
*
* _.isArray(document.body.children);
* // => false
*
* _.isArray('abc');
* // => false
*
* _.isArray(_.noop);
* // => false
*/
var isArray = Array.isArray;
/**
* Checks if `value` is classified as a `Function` object.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a function, else `false`.
* @example
*
* _.isFunction(_);
* // => true
*
* _.isFunction(/abc/);
* // => false
*/
function isFunction(value) {
// The use of `Object#toString` avoids issues with the `typeof` operator
// in Safari 8-9 which returns 'object' for typed array and other constructors.
var tag = isObject(value) ? objectToString.call(value) : '';
return tag == funcTag || tag == genTag;
}
/**
* Checks if `value` is the
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(_.noop);
* // => true
*
* _.isObject(null);
* // => false
*/
function isObject(value) {
var type = typeof value;
return !!value && (type == 'object' || type == 'function');
}
/**
* Checks if `value` is object-like. A value is object-like if it's not `null`
* and has a `typeof` result of "object".
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
* @example
*
* _.isObjectLike({});
* // => true
*
* _.isObjectLike([1, 2, 3]);
* // => true
*
* _.isObjectLike(_.noop);
* // => false
*
* _.isObjectLike(null);
* // => false
*/
function isObjectLike(value) {
return !!value && typeof value == 'object';
}
/**
* Checks if `value` is classified as a `Symbol` primitive or object.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
* @example
*
* _.isSymbol(Symbol.iterator);
* // => true
*
* _.isSymbol('abc');
* // => false
*/
function isSymbol(value) {
return typeof value == 'symbol' ||
(isObjectLike(value) && objectToString.call(value) == symbolTag);
}
/**
* Converts `value` to a string. An empty string is returned for `null`
* and `undefined` values. The sign of `-0` is preserved.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to process.
* @returns {string} Returns the string.
* @example
*
* _.toString(null);
* // => ''
*
* _.toString(-0);
* // => '-0'
*
* _.toString([1, 2, 3]);
* // => '1,2,3'
*/
function toString(value) {
return value == null ? '' : baseToString(value);
}
/**
* Sets the value at `path` of `object`. If a portion of `path` doesn't exist,
* it's created. Arrays are created for missing index properties while objects
* are created for all other missing properties. Use `_.setWith` to customize
* `path` creation.
*
* **Note:** This method mutates `object`.
*
* @static
* @memberOf _
* @since 3.7.0
* @category Object
* @param {Object} object The object to modify.
* @param {Array|string} path The path of the property to set.
* @param {*} value The value to set.
* @returns {Object} Returns `object`.
* @example
*
* var object = { 'a': [{ 'b': { 'c': 3 } }] };
*
* _.set(object, 'a[0].b.c', 4);
* console.log(object.a[0].b.c);
* // => 4
*
* _.set(object, ['x', '0', 'y', 'z'], 5);
* console.log(object.x[0].y.z);
* // => 5
*/
function set(object, path, value) {
return object == null ? object : baseSet(object, path, value);
}
module.exports = set;

19
node_modules/lodash.set/package.json generated vendored Normal file
View file

@ -0,0 +1,19 @@
{
"name": "lodash.set",
"version": "4.3.2",
"description": "The lodash method `_.set` exported as a module.",
"homepage": "https://lodash.com/",
"icon": "https://lodash.com/icon.svg",
"license": "MIT",
"keywords": "lodash-modularized, set",
"author": "John-David Dalton <john.david.dalton@gmail.com> (http://allyoucanleet.com/)",
"contributors": [
"John-David Dalton <john.david.dalton@gmail.com> (http://allyoucanleet.com/)",
"Blaine Bublitz <blaine.bublitz@gmail.com> (https://github.com/phated)",
"Mathias Bynens <mathias@qiwi.be> (https://mathiasbynens.be/)"
],
"repository": "lodash/lodash",
"scripts": {
"test": "echo \"See https://travis-ci.org/lodash/lodash-cli for testing details.\""
}
}

5
node_modules/nock/CHANGELOG.md generated vendored
View file

@ -1,3 +1,6 @@
# Changelog # Changelog
Nocks changelog can be found directly in the [GitHub release notes](https://github.com/nock/nock/releases). These are automatically created by [semantic-release](https://github.com/semantic-release/semantic-release) based on their [commit message conventions](https://semantic-release.gitbook.io/semantic-release#commit-message-format). Nocks changelog can be found directly in the [GitHub release notes](https://github.com/nock/nock/releases).
These are automatically created by [semantic-release](https://github.com/semantic-release/semantic-release) based on their [commit message conventions](https://semantic-release.gitbook.io/semantic-release#commit-message-format).
Migration guides are available for major versions in the [migration guides directory](https://github.com/nock/nock/tree/main/migration_guides).

263
node_modules/nock/README.md generated vendored
View file

@ -3,7 +3,6 @@
[![npm](https://img.shields.io/npm/v/nock.svg)][npmjs] [![npm](https://img.shields.io/npm/v/nock.svg)][npmjs]
[![Build Status](https://travis-ci.org/nock/nock.svg)][build] [![Build Status](https://travis-ci.org/nock/nock.svg)][build]
![Coverage Status](http://img.shields.io/badge/coverage-100%25-brightgreen.svg) ![Coverage Status](http://img.shields.io/badge/coverage-100%25-brightgreen.svg)
[![Greenkeeper](https://badges.greenkeeper.io/nock/nock.svg)](https://greenkeeper.io/)
[![Backers on Open Collective](https://opencollective.com/nock/backers/badge.svg)](#backers) [![Backers on Open Collective](https://opencollective.com/nock/backers/badge.svg)](#backers)
[![Sponsors on Open Collective](https://opencollective.com/nock/sponsors/badge.svg)](#sponsors) [![Sponsors on Open Collective](https://opencollective.com/nock/sponsors/badge.svg)](#sponsors)
@ -43,10 +42,11 @@ For instance, if a module performs HTTP requests to a CouchDB server or makes HT
- [Support for HTTP and HTTPS](#support-for-http-and-https) - [Support for HTTP and HTTPS](#support-for-http-and-https)
- [Non-standard ports](#non-standard-ports) - [Non-standard ports](#non-standard-ports)
- [Repeat response n times](#repeat-response-n-times) - [Repeat response n times](#repeat-response-n-times)
- [Delay the response body](#delay-the-response-body)
- [Delay the response](#delay-the-response) - [Delay the response](#delay-the-response)
- [Delay the connection](#delay-the-connection) - [Delay the connection](#delay-the-connection)
- [Socket timeout](#socket-timeout) - [Technical Details](#technical-details)
- [Delay the response body](#delay-the-response-body)
- [Technical Details](#technical-details-1)
- [Chaining](#chaining) - [Chaining](#chaining)
- [Scope filtering](#scope-filtering) - [Scope filtering](#scope-filtering)
- [Conditional scope filtering](#conditional-scope-filtering) - [Conditional scope filtering](#conditional-scope-filtering)
@ -63,7 +63,6 @@ For instance, if a module performs HTTP requests to a CouchDB server or makes HT
- [.pendingMocks()](#pendingmocks) - [.pendingMocks()](#pendingmocks)
- [.activeMocks()](#activemocks) - [.activeMocks()](#activemocks)
- [.isActive()](#isactive) - [.isActive()](#isactive)
- [Logging](#logging)
- [Restoring](#restoring) - [Restoring](#restoring)
- [Activating](#activating) - [Activating](#activating)
- [Turning Nock Off (experimental!)](#turning-nock-off-experimental) - [Turning Nock Off (experimental!)](#turning-nock-off-experimental)
@ -86,9 +85,10 @@ For instance, if a module performs HTTP requests to a CouchDB server or makes HT
- [Usage](#usage-1) - [Usage](#usage-1)
- [Options](#options-1) - [Options](#options-1)
- [Example](#example) - [Example](#example)
- [Modes](#modes) - [Modes](#modes)
- [Common issues](#common-issues) - [Common issues](#common-issues)
- [Axios](#axios) - [Axios](#axios)
- [Memory issues with Jest](#memory-issues-with-jest)
- [Debugging](#debugging) - [Debugging](#debugging)
- [Contributing](#contributing) - [Contributing](#contributing)
- [Contributors](#contributors) - [Contributors](#contributors)
@ -260,9 +260,7 @@ nock('http://www.example.com')
Nock understands query strings. Search parameters can be included as part of the path: Nock understands query strings. Search parameters can be included as part of the path:
```js ```js
nock('http://example.com') nock('http://example.com').get('/users?foo=bar').reply(200)
.get('/users?foo=bar')
.reply(200)
``` ```
Instead of placing the entire URL, you can specify the query part as an object: Instead of placing the entire URL, you can specify the query part as an object:
@ -294,10 +292,7 @@ A `URLSearchParams` instance can be provided.
```js ```js
const params = new URLSearchParams({ foo: 'bar' }) const params = new URLSearchParams({ foo: 'bar' })
nock('http://example.com') nock('http://example.com').get('/').query(params).reply(200)
.get('/')
.query(params)
.reply(200)
``` ```
Nock supports passing a function to query. The function determines if the actual query matches or not. Nock supports passing a function to query. The function determines if the actual query matches or not.
@ -338,9 +333,7 @@ nock('http://example.com', { encodedQueryParams: true })
You can specify the return status code for a path on the first argument of reply like this: You can specify the return status code for a path on the first argument of reply like this:
```js ```js
const scope = nock('http://myapp.iriscouch.com') const scope = nock('http://myapp.iriscouch.com').get('/users/1').reply(404)
.get('/users/1')
.reply(404)
``` ```
You can also specify the reply body as a string: You can also specify the reply body as a string:
@ -354,13 +347,11 @@ const scope = nock('http://www.google.com')
or as a JSON-encoded object: or as a JSON-encoded object:
```js ```js
const scope = nock('http://myapp.iriscouch.com') const scope = nock('http://myapp.iriscouch.com').get('/').reply(200, {
.get('/') username: 'pgte',
.reply(200, { email: 'pedro.teixeira@gmail.com',
username: 'pgte', _id: '4324243fsd',
email: 'pedro.teixeira@gmail.com', })
_id: '4324243fsd',
})
``` ```
or even as a file: or even as a file:
@ -384,7 +375,7 @@ const scope = nock('http://www.google.com')
In Nock 11.x it was possible to invoke `.reply()` with a status code and a In Nock 11.x it was possible to invoke `.reply()` with a status code and a
function that returns an array containing a status code and body. (The status function that returns an array containing a status code and body. (The status
code from the array would take precedence over the one passed directly to code from the array would take precedence over the one passed directly to
reply.) This is no longer allowed. In 12.x, either call `.reply()` with a reply.) This is no longer allowed. In Nock 12 and later, either call `.reply()` with a
status code and a function that returns the body, or call it with a single status code and a function that returns the body, or call it with a single
argument: a function that returns an array containing both the status code and argument: a function that returns an array containing both the status code and
body. body.
@ -443,7 +434,7 @@ If you're using the reply callback style, you can access the original client req
```js ```js
const scope = nock('http://www.google.com') const scope = nock('http://www.google.com')
.get('/cat-poems') .get('/cat-poems')
.reply(function(uri, requestBody) { .reply(function (uri, requestBody) {
console.log('path:', this.req.path) console.log('path:', this.req.path)
console.log('headers:', this.req.headers) console.log('headers:', this.req.headers)
// ... // ...
@ -465,12 +456,10 @@ nock('http://www.google.com')
JSON error responses are allowed too: JSON error responses are allowed too:
```js ```js
nock('http://www.google.com') nock('http://www.google.com').get('/cat-poems').replyWithError({
.get('/cat-poems') message: 'something awful happened',
.replyWithError({ code: 'AWFUL_ERROR',
message: 'something awful happened', })
code: 'AWFUL_ERROR',
})
``` ```
> Note: This will emit an `error` event on the `request` object, not the reply. > Note: This will emit an `error` event on the `request` object, not the reply.
@ -584,7 +573,7 @@ const scope = nock('http://www.headdy.com')
#### Including Content-Length Header Automatically #### Including Content-Length Header Automatically
When using `scope.reply()` to set a response body manually, you can have the When using `interceptor.reply()` to set a response body manually, you can have the
`Content-Length` header calculated automatically. `Content-Length` header calculated automatically.
```js ```js
@ -644,61 +633,45 @@ You are able to specify a non-standard port like this:
```js ```js
const scope = nock('http://my.server.com:8081') const scope = nock('http://my.server.com:8081')
...
``` ```
### Repeat response n times ### Repeat response n times
You are able to specify the number of times to repeat the same response. You are able to specify the number of times to repeat the same response.
**NOTE:** When request times is more than the number you specified, you will get an error before cleaning this interceptor.
```js ```js
nock('http://zombo.com') nock('http://zombo.com').get('/').times(4).reply(200, 'Ok')
.get('/')
.times(4)
.reply(200, 'Ok')
http.get('http://zombo.com/') // respond body "Ok" http.get('http://zombo.com/') // respond body "Ok"
http.get('http://zombo.com/') // respond body "Ok" http.get('http://zombo.com/') // respond body "Ok"
http.get('http://zombo.com/') // respond body "Ok" http.get('http://zombo.com/') // respond body "Ok"
http.get('http://zombo.com/') // respond body "Ok" http.get('http://zombo.com/') // respond body "Ok"
http.get('http://zombo.com/') // respond with zombo.com result
// This code will get an error with message:
// Nock: No match for request
http.get('http://zombo.com/')
// clean your interceptor
nock.cleanAll()
http.get('http://zombo.com/') // real respond with zombo.com result
``` ```
Sugar syntax Sugar syntax
```js ```js
nock('http://zombo.com') nock('http://zombo.com').get('/').once().reply(200, 'Ok')
.get('/') nock('http://zombo.com').get('/').twice().reply(200, 'Ok')
.once() nock('http://zombo.com').get('/').thrice().reply(200, 'Ok')
.reply(200, 'Ok')
nock('http://zombo.com')
.get('/')
.twice()
.reply(200, 'Ok')
nock('http://zombo.com')
.get('/')
.thrice()
.reply(200, 'Ok')
``` ```
To repeat this response for as long as nock is active, use [.persist()](#persist). To repeat this response for as long as nock is active, use [.persist()](#persist).
### Delay the response body
You are able to specify the number of milliseconds that the response body should be delayed. Response header will be replied immediately.
`delayBody(1000)` is equivalent to `delay({body: 1000})`.
```js
nock('http://my.server.com')
.get('/')
.delayBody(2000) // 2 seconds
.reply(200, '<html></html>')
```
NOTE: the [`'response'`](http://nodejs.org/api/http.html#http_event_response) event will occur immediately, but the [IncomingMessage](http://nodejs.org/api/http.html#http_http_incomingmessage) will not emit its `'end'` event until after the delay.
### Delay the response ### Delay the response
Nock can simulate response latency to allow you to test timeouts, race conditions, an other timing related scenarios.
You are able to specify the number of milliseconds that your reply should be delayed. You are able to specify the number of milliseconds that your reply should be delayed.
```js ```js
@ -708,53 +681,54 @@ nock('http://my.server.com')
.reply(200, '<html></html>') .reply(200, '<html></html>')
``` ```
`delay()` could also be used as `delay(1000)` is an alias for `delayConnection(1000).delayBody(0)`
`delay({ head: 1000, body: 2000 })` is an alias for `delayConnection(1000).delayBody(2000)`
Both of which are covered in detail below.
``` #### Delay the connection
delay({
head: headDelayInMs,
body: bodyDelayInMs
})
```
for example You are able to specify the number of milliseconds that your connection should be idle before it starts to receive the response.
To simulate a socket timeout, provide a larger value than the timeout setting on the request.
```js ```js
nock('http://my.server.com') nock('http://my.server.com')
.get('/') .get('/')
.delay({ .delayConnection(2000) // 2 seconds
head: 2000, // header will be delayed for 2 seconds, i.e. the whole response will be delayed for 2 seconds.
body: 3000, // body will be delayed for another 3 seconds after header is sent out.
})
.reply(200, '<html></html>') .reply(200, '<html></html>')
req = http.request('http://my.server.com', { timeout: 1000 })
``` ```
### Delay the connection Nock emits timeout events almost immediately by comparing the requested connection delay to the timeout parameter passed to `http.request()` or `http.ClientRequest#setTimeout()`.
This allows you to test timeouts without using fake timers or slowing down your tests.
If the client chooses to _not_ take an action (e.g. abort the request), the request and response will continue on as normal, after real clock time has passed.
`delayConnection(1000)` is equivalent to `delay({ head: 1000 })`. ##### Technical Details
### Socket timeout Following the `'finish'` event being emitted by `ClientRequest`, Nock will wait for the next event loop iteration before checking if the request has been aborted.
At this point, any connection delay value is compared against any request timeout setting and a [`'timeout'`](https://nodejs.org/api/http.html#http_event_timeout) is emitted when appropriate from the socket and the request objects.
A Node timeout timer is then registered with any connection delay value to delay real time before checking again if the request has been aborted and the [`'response'`](http://nodejs.org/api/http.html#http_event_response) is emitted by the request.
You are able to specify the number of milliseconds that your connection should be idle, to simulate a socket timeout. A similar method, `.socketDelay()` was removed in version 13. It was thought that having two methods so subtlety similar was confusing.
The discussion can be found at https://github.com/nock/nock/pull/1974.
#### Delay the response body
You are able to specify the number of milliseconds that the response body should be delayed.
This is the time between the headers being received and the body starting to be received.
```js ```js
nock('http://my.server.com') nock('http://my.server.com')
.get('/') .get('/')
.socketDelay(2000) // 2 seconds .delayBody(2000) // 2 seconds
.reply(200, '<html></html>') .reply(200, '<html></html>')
``` ```
To test a request like the following: ##### Technical Details
```js Following the [`'response'`](http://nodejs.org/api/http.html#http_event_response) being emitted by `ClientRequest`,
req = http.request('http://my.server.com', res => { Nock will register a timeout timer with the body delay value to delay real time before the [IncomingMessage](http://nodejs.org/api/http.html#http_http_incomingmessage) emits its first `'data'` or the `'end'` event.
...
})
req.setTimeout(1000, () => { req.abort() })
req.end()
```
NOTE: the timeout will be fired immediately, and will not leave the simulated connection idle for the specified period of time.
### Chaining ### Chaining
@ -914,20 +888,14 @@ example.pendingMocks() // ["GET http://example.com:80/path"]
// ...After a request to example.com/pathA: // ...After a request to example.com/pathA:
example.pendingMocks() // [] example.pendingMocks() // []
example example.get('/pathB').optionally().reply(200)
.get('/pathB')
.optionally()
.reply(200)
example.pendingMocks() // [] example.pendingMocks() // []
// You can also pass a boolean argument to `optionally()`. This // You can also pass a boolean argument to `optionally()`. This
// is useful if you want to conditionally make a mocked request // is useful if you want to conditionally make a mocked request
// optional. // optional.
const getMock = optional => const getMock = optional =>
example example.get('/pathC').optionally(optional).reply(200)
.get('/pathC')
.optionally(optional)
.reply(200)
getMock(true) getMock(true)
example.pendingMocks() // [] example.pendingMocks() // []
@ -977,9 +945,7 @@ setTimeout(() => {
You can call `isDone()` on a single expectation to determine if the expectation was met: You can call `isDone()` on a single expectation to determine if the expectation was met:
```js ```js
const scope = nock('http://google.com') const scope = nock('http://google.com').get('/').reply(200)
.get('/')
.reply(200)
scope.isDone() // will return false scope.isDone() // will return false
``` ```
@ -1022,10 +988,7 @@ Note that while a persisted scope will always intercept the requests, it is cons
If you want to stop persisting an individual persisted mock you can call `persist(false)`: If you want to stop persisting an individual persisted mock you can call `persist(false)`:
```js ```js
const scope = nock('http://example.com') const scope = nock('http://example.com').persist().get('/').reply(200, 'ok')
.persist()
.get('/')
.reply(200, 'ok')
// Do some tests ... // Do some tests ...
@ -1081,16 +1044,6 @@ if (!nock.isActive()) {
} }
``` ```
## Logging
Nock can log matches if you pass in a log function like this:
```js
const scope = nock('http://google.com')
.log(console.log)
...
```
## Restoring ## Restoring
You can restore the HTTP interceptor to the normal unmocked behaviour by calling: You can restore the HTTP interceptor to the normal unmocked behaviour by calling:
@ -1119,7 +1072,7 @@ You can bypass Nock completely by setting the `NOCK_OFF` environment variable to
This way you can have your tests hit the real servers just by switching on this environment variable. This way you can have your tests hit the real servers just by switching on this environment variable.
```js ```shell script
$ NOCK_OFF=true node my_test.js $ NOCK_OFF=true node my_test.js
``` ```
@ -1260,7 +1213,7 @@ If you save this as a JSON file, you can load them directly through `nock.load(p
```js ```js
nocks = nock.load(pathToJson) nocks = nock.load(pathToJson)
nocks.forEach(function(nock) { nocks.forEach(function (nock) {
nock.filteringRequestBody = (body, aRecordedBody) => { nock.filteringRequestBody = (body, aRecordedBody) => {
if (typeof body !== 'string' || typeof aRecordedBody !== 'string') { if (typeof body !== 'string' || typeof aRecordedBody !== 'string') {
return body return body
@ -1269,9 +1222,12 @@ nocks.forEach(function(nock) {
const recordedBodyResult = /timestamp:([0-9]+)/.exec(aRecordedBody) const recordedBodyResult = /timestamp:([0-9]+)/.exec(aRecordedBody)
if (recordedBodyResult) { if (recordedBodyResult) {
const recordedTimestamp = recordedBodyResult[1] const recordedTimestamp = recordedBodyResult[1]
return body.replace(/(timestamp):([0-9]+)/g, function(match, key, value) { return body.replace(
return key + ':' + recordedTimestamp /(timestamp):([0-9]+)/g,
}) function (match, key, value) {
return key + ':' + recordedTimestamp
}
)
} else { } else {
return body return body
} }
@ -1355,10 +1311,10 @@ nock.removeInterceptor({
```js ```js
nock.removeInterceptor({ nock.removeInterceptor({
hostname : 'localhost', hostname: 'localhost',
path : '/login' path: '/login',
method: 'POST' method: 'POST',
proto : 'https' proto: 'https',
}) })
``` ```
@ -1425,7 +1381,7 @@ nockBack('zomboFixture.json', nockDone => {
nockDone() nockDone()
// usage of the created fixture // usage of the created fixture
nockBack('zomboFixture.json', function(nockDone) { nockBack('zomboFixture.json', function (nockDone) {
http.get('http://zombo.com/').end() // respond body "Ok" http.get('http://zombo.com/').end() // respond body "Ok"
this.assertScopesFinished() //throws an exception if all nocks in fixture were not satisfied this.assertScopesFinished() //throws an exception if all nocks in fixture were not satisfied
@ -1439,12 +1395,10 @@ nockBack('zomboFixture.json', nockDone => {
If your tests are using promises then use `nockBack` like this: If your tests are using promises then use `nockBack` like this:
``` ```js
return nockBack('promisedFixture.json') return nockBack('promisedFixture.json').then(({ nockDone, context }) => {
.then(({ nockDone, context }) => { // do your tests returning a promise and chain it with
// do your tests returning a promise and chain it with // `.then(nockDone)`
// `.then(nockDone)`
})
}) })
``` ```
@ -1462,7 +1416,7 @@ As an optional second parameter you can pass the following options
```js ```js
function prepareScope(scope) { function prepareScope(scope) {
scope.filteringRequestBody = (body, aRecordedBody) => { scope.filteringRequestBody = (body, aRecordedBody) => {
if (typeof(body) !== 'string' || typeof(aRecordedBody) !== 'string') { if (typeof body !== 'string' || typeof aRecordedBody !== 'string') {
return body return body
} }
@ -1479,15 +1433,15 @@ function prepareScope(scope) {
} }
} }
nockBack('zomboFixture.json', { before: prepareScope }, nockDone => { nockBack('exampleFixture.json', { before: prepareScope }, nockDone => {
request.get('http://zombo.com', function(err, res, body) { request.get('http://example.com', function (err, res, body) {
// do your tests // do your tests
nockDone() nockDone()
} })
} })
``` ```
#### Modes ### Modes
To set the mode call `nockBack.setMode(mode)` or run the tests with the `NOCK_BACK_MODE` environment variable set before loading nock. If the mode needs to be changed programmatically, the following is valid: `nockBack.setMode(nockBack.currentMode)` To set the mode call `nockBack.setMode(mode)` or run the tests with the `NOCK_BACK_MODE` environment variable set before loading nock. If the mode needs to be changed programmatically, the following is valid: `nockBack.setMode(nockBack.currentMode)`
@ -1512,14 +1466,14 @@ The same is true for `.replyWithError()`.
Adding `{ retry: 0 }` to the `got` invocations will disable retrying, e.g.: Adding `{ retry: 0 }` to the `got` invocations will disable retrying, e.g.:
``` ```js
await got("http://example.test/", { retry: 0 }) await got('http://example.test/', { retry: 0 })
``` ```
If you need to do this in all your tests, you can create a module If you need to do this in all your tests, you can create a module
`got_client.js` which exports a custom got instance: `got_client.js` which exports a custom got instance:
``` ```js
const got = require('got') const got = require('got')
module.exports = got.extend({ retry: 0 }) module.exports = got.extend({ retry: 0 })
@ -1566,12 +1520,37 @@ test('can fetch test response', async t => {
[axios]: https://github.com/axios/axios [axios]: https://github.com/axios/axios
### Memory issues with Jest
Memory issues can be avoided by calling [`nock.restore()`](#restoring) after each test suite.
One of the core principles of [Jest](https://jestjs.io/) is that it runs tests in isolation.
It does this by manipulating the modules cache of Node in a way that conflicts with how Nock monkey patches the builtin `http` and `https` modules.
[Related issue with more details](https://github.com/nock/nock/issues/1817).
## Debugging ## Debugging
Nock uses [`debug`](https://github.com/visionmedia/debug), so just run with environmental variable `DEBUG` set to `nock.*`. Nock uses [`debug`](https://github.com/visionmedia/debug), so just run with environmental variable `DEBUG` set to `nock.*`.
```console
user@local$ DEBUG=nock.* node my_test.js
```
Each step in the matching process is logged this way and can be useful when determining why a request was not intercepted by Nock.
For example the following shows that matching failed because the request had an extra search parameter.
```js ```js
$ DEBUG=nock.* node my_test.js nock('http://example.com').get('/').query({ foo: 'bar' }).reply()
await got('http://example.com/?foo=bar&baz=foz')
```
```console
user@local$ DEBUG=nock.scope:example.com node my_test.js
...
nock.scope:example.com Interceptor queries: {"foo":"bar"} +1ms
nock.scope:example.com Request queries: {"foo":"bar","baz":"foz"} +0ms
nock.scope:example.com query matching failed +0ms
``` ```
## Contributing ## Contributing

30
node_modules/nock/lib/back.js generated vendored
View file

@ -73,7 +73,7 @@ function Back(fixtureName, options, nockedFn) {
const fixture = path.join(Back.fixtures, fixtureName) const fixture = path.join(Back.fixtures, fixtureName)
const context = _mode.start(fixture, options) const context = _mode.start(fixture, options)
const nockDone = function() { const nockDone = function () {
_mode.finish(fixture, options, context) _mode.finish(fixture, options, context)
} }
@ -92,24 +92,24 @@ function Back(fixtureName, options, nockedFn) {
*******************************************************************************/ *******************************************************************************/
const wild = { const wild = {
setup: function() { setup: function () {
cleanAll() cleanAll()
recorder.restore() recorder.restore()
activate() activate()
enableNetConnect() enableNetConnect()
}, },
start: function() { start: function () {
return load() // don't load anything but get correct context return load() // don't load anything but get correct context
}, },
finish: function() { finish: function () {
// nothing to do // nothing to do
}, },
} }
const dryrun = { const dryrun = {
setup: function() { setup: function () {
recorder.restore() recorder.restore()
cleanAll() cleanAll()
activate() activate()
@ -117,20 +117,20 @@ const dryrun = {
enableNetConnect() enableNetConnect()
}, },
start: function(fixture, options) { start: function (fixture, options) {
const contexts = load(fixture, options) const contexts = load(fixture, options)
enableNetConnect() enableNetConnect()
return contexts return contexts
}, },
finish: function() { finish: function () {
// nothing to do // nothing to do
}, },
} }
const record = { const record = {
setup: function() { setup: function () {
recorder.restore() recorder.restore()
recorder.clear() recorder.clear()
cleanAll() cleanAll()
@ -138,7 +138,7 @@ const record = {
disableNetConnect() disableNetConnect()
}, },
start: function(fixture, options) { start: function (fixture, options) {
if (!fs) { if (!fs) {
throw new Error('no fs') throw new Error('no fs')
} }
@ -157,7 +157,7 @@ const record = {
return context return context
}, },
finish: function(fixture, options, context) { finish: function (fixture, options, context) {
if (context.isRecording) { if (context.isRecording) {
let outputs = recorder.outputs() let outputs = recorder.outputs()
@ -176,7 +176,7 @@ const record = {
} }
const lockdown = { const lockdown = {
setup: function() { setup: function () {
recorder.restore() recorder.restore()
recorder.clear() recorder.clear()
cleanAll() cleanAll()
@ -184,11 +184,11 @@ const lockdown = {
disableNetConnect() disableNetConnect()
}, },
start: function(fixture, options) { start: function (fixture, options) {
return load(fixture, options) return load(fixture, options)
}, },
finish: function() { finish: function () {
// nothing to do // nothing to do
}, },
} }
@ -196,7 +196,7 @@ const lockdown = {
function load(fixture, options) { function load(fixture, options) {
const context = { const context = {
scopes: [], scopes: [],
assertScopesFinished: function() { assertScopesFinished: function () {
assertScopes(this.scopes, fixture) assertScopes(this.scopes, fixture)
}, },
} }
@ -261,7 +261,7 @@ const Modes = {
lockdown, // use recorded nocks, disables all http calls even when not nocked, doesnt record lockdown, // use recorded nocks, disables all http calls even when not nocked, doesnt record
} }
Back.setMode = function(mode) { Back.setMode = function (mode) {
if (!(mode in Modes)) { if (!(mode in Modes)) {
throw new Error(`Unknown mode: ${mode}`) throw new Error(`Unknown mode: ${mode}`)
} }

203
node_modules/nock/lib/common.js generated vendored
View file

@ -1,9 +1,10 @@
'use strict' 'use strict'
const _ = require('lodash')
const debug = require('debug')('nock.common') const debug = require('debug')('nock.common')
const url = require('url') const set = require('lodash.set')
const timers = require('timers') const timers = require('timers')
const url = require('url')
const util = require('util')
/** /**
* Normalizes the request options so that it always has `host` property. * Normalizes the request options so that it always has `host` property.
@ -28,7 +29,7 @@ function normalizeRequestOptions(options) {
debug('options.host in the end: %j', options.host) debug('options.host in the end: %j', options.host)
/// lowercase host names /// lowercase host names
;['hostname', 'host'].forEach(function(attr) { ;['hostname', 'host'].forEach(function (attr) {
if (options[attr]) { if (options[attr]) {
options[attr] = options[attr].toLowerCase() options[attr] = options[attr].toLowerCase()
} }
@ -66,7 +67,7 @@ let requestOverrides = {}
*/ */
function overrideRequests(newRequest) { function overrideRequests(newRequest) {
debug('overriding requests') debug('overriding requests')
;['http', 'https'].forEach(function(proto) { ;['http', 'https'].forEach(function (proto) {
debug('- overriding request for', proto) debug('- overriding request for', proto)
const moduleName = proto // 1 to 1 match of protocol and module is fortunate :) const moduleName = proto // 1 to 1 match of protocol and module is fortunate :)
@ -90,7 +91,7 @@ function overrideRequests(newRequest) {
get: overriddenGet, get: overriddenGet,
} }
// https://nodejs.org/api/http.html#http_http_request_url_options_callback // https://nodejs.org/api/http.html#http_http_request_url_options_callback
module.request = function(input, options, callback) { module.request = function (input, options, callback) {
return newRequest(proto, overriddenRequest.bind(module), [ return newRequest(proto, overriddenRequest.bind(module), [
input, input,
options, options,
@ -98,7 +99,7 @@ function overrideRequests(newRequest) {
]) ])
} }
// https://nodejs.org/api/http.html#http_http_get_options_callback // https://nodejs.org/api/http.html#http_http_get_options_callback
module.get = function(input, options, callback) { module.get = function (input, options, callback) {
const req = newRequest(proto, overriddenGet.bind(module), [ const req = newRequest(proto, overriddenGet.bind(module), [
input, input,
options, options,
@ -179,7 +180,7 @@ function isContentEncoded(headers) {
function contentEncoding(headers, encoder) { function contentEncoding(headers, encoder) {
const contentEncoding = headers['content-encoding'] const contentEncoding = headers['content-encoding']
return contentEncoding === encoder return contentEncoding !== undefined && contentEncoding.toString() === encoder
} }
function isJSONContent(headers) { function isJSONContent(headers) {
@ -194,7 +195,7 @@ function isJSONContent(headers) {
* Duplicates throw an error. * Duplicates throw an error.
*/ */
function headersFieldNamesToLowerCase(headers) { function headersFieldNamesToLowerCase(headers) {
if (!_.isPlainObject(headers)) { if (!isPlainObject(headers)) {
throw Error('Headers must be provided as an object') throw Error('Headers must be provided as an object')
} }
@ -243,11 +244,11 @@ function headersInputToRawArray(headers) {
} }
// [].concat(...) is used instead of Array.flat until v11 is the minimum Node version // [].concat(...) is used instead of Array.flat until v11 is the minimum Node version
if (_.isMap(headers)) { if (util.types.isMap(headers)) {
return [].concat(...Array.from(headers, ([k, v]) => [k.toString(), v])) return [].concat(...Array.from(headers, ([k, v]) => [k.toString(), v]))
} }
if (_.isPlainObject(headers)) { if (isPlainObject(headers)) {
return [].concat(...Object.entries(headers)) return [].concat(...Object.entries(headers))
} }
@ -359,7 +360,7 @@ function addHeaderLine(headers, name, value) {
* @fieldName {String} field name - string with the case-insensitive field name * @fieldName {String} field name - string with the case-insensitive field name
*/ */
function deleteHeadersField(headers, fieldNameToDelete) { function deleteHeadersField(headers, fieldNameToDelete) {
if (!_.isPlainObject(headers)) { if (!isPlainObject(headers)) {
throw Error('headers must be an object') throw Error('headers must be an object')
} }
@ -406,11 +407,8 @@ function percentDecode(str) {
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
*/ */
function percentEncode(str) { function percentEncode(str) {
return encodeURIComponent(str).replace(/[!'()*]/g, function(c) { return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
return `%${c return `%${c.charCodeAt(0).toString(16).toUpperCase()}`
.charCodeAt(0)
.toString(16)
.toUpperCase()}`
}) })
} }
@ -418,9 +416,12 @@ function matchStringOrRegexp(target, pattern) {
const targetStr = const targetStr =
target === undefined || target === null ? '' : String(target) target === undefined || target === null ? '' : String(target)
return pattern instanceof RegExp if (pattern instanceof RegExp) {
? pattern.test(targetStr) // if the regexp happens to have a global flag, we want to ensure we test the entire target
: targetStr === String(pattern) pattern.lastIndex = 0
return pattern.test(targetStr)
}
return targetStr === String(pattern)
} }
/** /**
@ -452,13 +453,13 @@ function formatQueryValue(key, value, stringFormattingFn) {
case value instanceof RegExp: case value instanceof RegExp:
break break
case Array.isArray(value): { case Array.isArray(value): {
value = value.map(function(val, idx) { value = value.map(function (val, idx) {
return formatQueryValue(idx, val, stringFormattingFn)[1] return formatQueryValue(idx, val, stringFormattingFn)[1]
}) })
break break
} }
case typeof value === 'object': { case typeof value === 'object': {
value = Object.entries(value).reduce(function(acc, [subKey, subVal]) { value = Object.entries(value).reduce(function (acc, [subKey, subVal]) {
const subPair = formatQueryValue(subKey, subVal, stringFormattingFn) const subPair = formatQueryValue(subKey, subVal, stringFormattingFn)
acc[subPair[0]] = subPair[1] acc[subPair[0]] = subPair[1]
@ -550,8 +551,15 @@ function urlToOptions(url) {
* - The expected data can use regexp to compare values * - The expected data can use regexp to compare values
* - JSON path notation and nested objects are considered equal * - JSON path notation and nested objects are considered equal
*/ */
const dataEqual = (expected, actual) => const dataEqual = (expected, actual) => {
deepEqual(expand(expected), expand(actual)) if (isPlainObject(expected)) {
expected = expand(expected)
}
if (isPlainObject(actual)) {
actual = expand(actual)
}
return deepEqual(expected, actual)
}
/** /**
* Converts flat objects whose keys use JSON path notation to nested objects. * Converts flat objects whose keys use JSON path notation to nested objects.
@ -562,7 +570,7 @@ const dataEqual = (expected, actual) =>
* { 'foo[bar][0]': 'baz' } -> { foo: { bar: [ 'baz' ] } } * { 'foo[bar][0]': 'baz' } -> { foo: { bar: [ 'baz' ] } }
*/ */
const expand = input => const expand = input =>
Object.entries(input).reduce((acc, [k, v]) => _.set(acc, k, v), {}) Object.entries(input).reduce((acc, [k, v]) => set(acc, k, v), {})
/** /**
* Performs a recursive strict comparison between two values. * Performs a recursive strict comparison between two values.
@ -575,22 +583,70 @@ function deepEqual(expected, actual) {
return expected.test(actual) return expected.test(actual)
} }
if (Array.isArray(expected) || _.isPlainObject(expected)) { if (Array.isArray(expected) && Array.isArray(actual)) {
if (actual === undefined) { if (expected.length !== actual.length) {
return false return false
} }
const expKeys = Object.keys(expected) return expected.every((expVal, idx) => deepEqual(expVal, actual[idx]))
if (expKeys.length !== Object.keys(actual).length) { }
return false
}
return expKeys.every(key => deepEqual(expected[key], actual[key])) if (isPlainObject(expected) && isPlainObject(actual)) {
const allKeys = Array.from(
new Set(Object.keys(expected).concat(Object.keys(actual)))
)
return allKeys.every(key => deepEqual(expected[key], actual[key]))
} }
return expected === actual return expected === actual
} }
/**
* Checks if `value` is a plain object, that is, an object created by the
* `Object` constructor or one with a `[[Prototype]]` of `null`.
* https://github.com/lodash/lodash/blob/588bf3e20db0ae039a822a14a8fa238c5b298e65/isPlainObject.js
*
* @param {*} value The value to check.
* @return {boolean}
*/
function isPlainObject(value) {
const isObjectLike = typeof value === 'object' && value !== null
const tag = Object.prototype.toString.call(value)
if (!isObjectLike || tag !== '[object Object]') {
return false
}
if (Object.getPrototypeOf(value) === null) {
return true
}
let proto = value
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto)
}
return Object.getPrototypeOf(value) === proto
}
/**
* Creates an object with the same keys as `object` and values generated
* by running each own enumerable string keyed property of `object` thru
* `iteratee`. (iteration order is not guaranteed)
* The iteratee is invoked with three arguments: (value, key, object).
* https://github.com/lodash/lodash/blob/588bf3e20db0ae039a822a14a8fa238c5b298e65/mapValue.js
*
* @param {Object} object The object to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Object} Returns the new mapped object.
*/
function mapValue(object, iteratee) {
object = Object(object)
const result = {}
Object.keys(object).forEach(key => {
result[key] = iteratee(object[key], key, object)
})
return result
}
const timeouts = [] const timeouts = []
const intervals = [] const intervals = []
const immediates = [] const immediates = []
@ -617,29 +673,62 @@ function removeAllTimers() {
clearTimer(clearImmediate, immediates) clearTimer(clearImmediate, immediates)
} }
exports.normalizeClientRequestArgs = normalizeClientRequestArgs /**
exports.normalizeRequestOptions = normalizeRequestOptions * Check if the Client Request has been cancelled.
exports.normalizeOrigin = normalizeOrigin *
exports.isUtf8Representable = isUtf8Representable * Until Node 14 is the minimum, we need to look at both flags to see if the request has been cancelled.
exports.overrideRequests = overrideRequests * The two flags have the same purpose, but the Node maintainers are migrating from `abort(ed)` to
exports.restoreOverriddenRequests = restoreOverriddenRequests * `destroy(ed)` terminology, to be more consistent with `stream.Writable`.
exports.stringifyRequest = stringifyRequest * In Node 14.x+, Calling `abort()` will set both `aborted` and `destroyed` to true, however,
exports.isContentEncoded = isContentEncoded * calling `destroy()` will only set `destroyed` to true.
exports.contentEncoding = contentEncoding * Falling back on checking if the socket is destroyed to cover the case of Node <14.x where
exports.isJSONContent = isJSONContent * `destroy()` is called, but `destroyed` is undefined.
exports.headersFieldNamesToLowerCase = headersFieldNamesToLowerCase *
exports.headersFieldsArrayToLowerCase = headersFieldsArrayToLowerCase * Node Client Request history:
exports.headersArrayToObject = headersArrayToObject * - `request.abort()`: Added in: v0.3.8, Deprecated since: v14.1.0, v13.14.0
exports.headersInputToRawArray = headersInputToRawArray * - `request.aborted`: Added in: v0.11.14, Became a boolean instead of a timestamp: v11.0.0, Not deprecated (yet)
exports.deleteHeadersField = deleteHeadersField * - `request.destroy()`: Added in: v0.3.0
exports.forEachHeader = forEachHeader * - `request.destroyed`: Added in: v14.1.0, v13.14.0
exports.percentEncode = percentEncode *
exports.percentDecode = percentDecode * @param {ClientRequest} req
exports.matchStringOrRegexp = matchStringOrRegexp * @returns {boolean}
exports.formatQueryValue = formatQueryValue */
exports.isStream = isStream function isRequestDestroyed(req) {
exports.dataEqual = dataEqual return !!(
exports.setTimeout = setTimeout req.destroyed === true ||
exports.setInterval = setInterval req.aborted ||
exports.setImmediate = setImmediate (req.socket && req.socket.destroyed)
exports.removeAllTimers = removeAllTimers )
}
module.exports = {
contentEncoding,
dataEqual,
deleteHeadersField,
forEachHeader,
formatQueryValue,
headersArrayToObject,
headersFieldNamesToLowerCase,
headersFieldsArrayToLowerCase,
headersInputToRawArray,
isContentEncoded,
isJSONContent,
isPlainObject,
isRequestDestroyed,
isStream,
isUtf8Representable,
mapValue,
matchStringOrRegexp,
normalizeClientRequestArgs,
normalizeOrigin,
normalizeRequestOptions,
overrideRequests,
percentDecode,
percentEncode,
removeAllTimers,
restoreOverriddenRequests,
setImmediate,
setInterval,
setTimeout,
stringifyRequest,
}

View file

@ -1,52 +0,0 @@
'use strict'
/**
* Creates a stream which becomes the response body of the interceptor when a
* delay is set. The stream outputs the intended body and EOF after the delay.
*
* @param {String|Buffer|Stream} body - the body to write/pipe out
* @param {Integer} ms - The delay in milliseconds
* @constructor
*/
const { Transform } = require('stream')
const common = require('./common')
module.exports = class DelayedBody extends Transform {
constructor(ms, body) {
super()
const self = this
let data = ''
let ended = false
if (common.isStream(body)) {
body.on('data', function(chunk) {
data += Buffer.isBuffer(chunk) ? chunk.toString() : chunk
})
body.once('end', function() {
ended = true
})
body.resume()
}
// TODO: This would be more readable if the stream case were moved into
// the `if` statement above.
common.setTimeout(function() {
if (common.isStream(body) && !ended) {
body.once('end', function() {
self.end(data)
})
} else {
self.end(data || body)
}
}, ms)
}
_transform(chunk, encoding, cb) {
this.push(chunk)
process.nextTick(cb)
}
}

16
node_modules/nock/lib/intercept.js generated vendored
View file

@ -121,14 +121,14 @@ function remove(interceptor) {
// TODO: There is a clearer way to write that we want to delete the first // TODO: There is a clearer way to write that we want to delete the first
// matching instance. I'm also not sure why we couldn't delete _all_ // matching instance. I'm also not sure why we couldn't delete _all_
// matching instances. // matching instances.
interceptors.some(function(thisInterceptor, i) { interceptors.some(function (thisInterceptor, i) {
return thisInterceptor === interceptor ? interceptors.splice(i, 1) : false return thisInterceptor === interceptor ? interceptors.splice(i, 1) : false
}) })
} }
function removeAll() { function removeAll() {
Object.keys(allInterceptors).forEach(function(key) { Object.keys(allInterceptors).forEach(function (key) {
allInterceptors[key].interceptors.forEach(function(interceptor) { allInterceptors[key].interceptors.forEach(function (interceptor) {
interceptor.scope.keyedInterceptors = {} interceptor.scope.keyedInterceptors = {}
}) })
}) })
@ -159,7 +159,7 @@ function interceptorsFor(options) {
// If scope filtering function is defined and returns a truthy value then // If scope filtering function is defined and returns a truthy value then
// we have to treat this as a match. // we have to treat this as a match.
if (filteringScope && filteringScope(basePath)) { if (filteringScope && filteringScope(basePath)) {
debug('found matching scope interceptor') interceptor.scope.logger('found matching scope interceptor')
// Keep the filtered scope (its key) to signal the rest of the module // Keep the filtered scope (its key) to signal the rest of the module
// that this wasn't an exact but filtered match. // that this wasn't an exact but filtered match.
@ -237,7 +237,7 @@ let originalClientRequest
function ErroringClientRequest(error) { function ErroringClientRequest(error) {
http.OutgoingMessage.call(this) http.OutgoingMessage.call(this)
process.nextTick( process.nextTick(
function() { function () {
this.emit('error', error) this.emit('error', error)
}.bind(this) }.bind(this)
) )
@ -281,6 +281,8 @@ function overrideClientRequest() {
debug('using', interceptors.length, 'interceptors') debug('using', interceptors.length, 'interceptors')
// Use filtered interceptors to intercept requests. // Use filtered interceptors to intercept requests.
// TODO: this shouldn't be a class anymore
// the overrider explicitly overrides methods and attrs on the request so the `assign` below should be removed.
const overrider = new InterceptedRequestRouter({ const overrider = new InterceptedRequestRouter({
req: this, req: this,
options, options,
@ -299,7 +301,7 @@ function overrideClientRequest() {
originalClientRequest.apply(this, arguments) originalClientRequest.apply(this, arguments)
} else { } else {
common.setImmediate( common.setImmediate(
function() { function () {
const error = new NetConnectNotAllowedError( const error = new NetConnectNotAllowedError(
options.host, options.host,
options.path options.path
@ -368,7 +370,7 @@ function activate() {
// ----- Overriding http.request and https.request: // ----- Overriding http.request and https.request:
common.overrideRequests(function(proto, overriddenRequest, args) { common.overrideRequests(function (proto, overriddenRequest, args) {
// NOTE: overriddenRequest is already bound to its module. // NOTE: overriddenRequest is already bound to its module.
const { options, callback } = common.normalizeClientRequestArgs(...args) const { options, callback } = common.normalizeClientRequestArgs(...args)

View file

@ -13,6 +13,20 @@ const globalEmitter = require('./global_emitter')
const Socket = require('./socket') const Socket = require('./socket')
const { playbackInterceptor } = require('./playback_interceptor') const { playbackInterceptor } = require('./playback_interceptor')
function socketOnClose(req) {
debug('socket close')
if (!req.res && !req.socket._hadError) {
// If we don't have a response then we know that the socket
// ended prematurely and we need to emit an error on the request.
req.socket._hadError = true
const err = new Error('socket hang up')
err.code = 'ECONNRESET'
req.emit('error', err)
}
req.emit('close')
}
/** /**
* Given a group of interceptors, appropriately route an outgoing request. * Given a group of interceptors, appropriately route an outgoing request.
* Identify which interceptor ought to respond, if any, then delegate to * Identify which interceptor ought to respond, if any, then delegate to
@ -39,16 +53,24 @@ class InterceptedRequestRouter {
} }
this.response = new IncomingMessage(this.socket) this.response = new IncomingMessage(this.socket)
this.playbackStarted = false
this.requestBodyBuffers = [] this.requestBodyBuffers = []
this.playbackStarted = false
// For parity with Node, it's important the socket event is emitted before we begin playback.
// This flag is set when playback is triggered if we haven't yet gotten the
// socket event to indicate that playback should start as soon as it comes in.
this.readyToStartPlaybackOnSocketEvent = false
this.attachToReq() this.attachToReq()
// Emit a fake socket event on the next tick to mimic what would happen on a real request.
// Some clients listen for a 'socket' event to be emitted before calling end(),
// which causes Nock to hang.
process.nextTick(() => this.connectSocket())
} }
attachToReq() { attachToReq() {
const { req, response, socket, options } = this const { req, options } = this
response.req = req
for (const [name, val] of Object.entries(options.headers)) { for (const [name, val] of Object.entries(options.headers)) {
req.setHeader(name.toLowerCase(), val) req.setHeader(name.toLowerCase(), val)
@ -65,18 +87,9 @@ class InterceptedRequestRouter {
req.path = options.path req.path = options.path
req.method = options.method req.method = options.method
// ClientRequest.connection is an alias for ClientRequest.socket
// https://nodejs.org/api/http.html#http_request_socket
// https://github.com/nodejs/node/blob/b0f75818f39ed4e6bd80eb7c4010c1daf5823ef7/lib/_http_client.js#L640-L641
// The same Socket is shared between the request and response to mimic native behavior.
req.socket = req.connection = socket
propagate(['error', 'timeout'], req.socket, req)
req.write = (...args) => this.handleWrite(...args) req.write = (...args) => this.handleWrite(...args)
req.end = (...args) => this.handleEnd(...args) req.end = (...args) => this.handleEnd(...args)
req.flushHeaders = (...args) => this.handleFlushHeaders(...args) req.flushHeaders = (...args) => this.handleFlushHeaders(...args)
req.abort = (...args) => this.handleAbort(...args)
// https://github.com/nock/nock/issues/256 // https://github.com/nock/nock/issues/256
if (options.headers.expect === '100-continue') { if (options.headers.expect === '100-continue') {
@ -85,53 +98,79 @@ class InterceptedRequestRouter {
req.emit('continue') req.emit('continue')
}) })
} }
// Emit a fake socket event on the next tick to mimic what would happen on a real request.
// Some clients listen for a 'socket' event to be emitted before calling end(),
// which causes nock to hang.
process.nextTick(() => {
req.emit('socket', socket)
// https://nodejs.org/api/net.html#net_event_connect
socket.emit('connect')
// https://nodejs.org/api/tls.html#tls_event_secureconnect
if (socket.authorized) {
socket.emit('secureConnect')
}
})
} }
emitError(error) { connectSocket() {
const { req } = this const { req, socket } = this
process.nextTick(() => {
req.emit('error', error)
})
}
handleWrite(buffer, encoding, callback) { if (common.isRequestDestroyed(req)) {
debug('write', arguments) return
const { req } = this
if (!req.aborted) {
if (buffer) {
if (!Buffer.isBuffer(buffer)) {
buffer = Buffer.from(buffer, encoding)
}
this.requestBodyBuffers.push(buffer)
}
// can't use instanceof Function because some test runners
// run tests in vm.runInNewContext where Function is not same
// as that in the current context
// https://github.com/nock/nock/pull/1754#issuecomment-571531407
if (typeof callback === 'function') {
callback()
}
} else {
this.emitError(new Error('Request aborted'))
} }
common.setImmediate(function() { // ClientRequest.connection is an alias for ClientRequest.socket
// https://nodejs.org/api/http.html#http_request_socket
// https://github.com/nodejs/node/blob/b0f75818f39ed4e6bd80eb7c4010c1daf5823ef7/lib/_http_client.js#L640-L641
// The same Socket is shared between the request and response to mimic native behavior.
req.socket = req.connection = socket
propagate(['error', 'timeout'], socket, req)
socket.on('close', () => socketOnClose(req))
socket.connecting = false
req.emit('socket', socket)
// https://nodejs.org/api/net.html#net_event_connect
socket.emit('connect')
// https://nodejs.org/api/tls.html#tls_event_secureconnect
if (socket.authorized) {
socket.emit('secureConnect')
}
if (this.readyToStartPlaybackOnSocketEvent) {
this.maybeStartPlayback()
}
}
// from docs: When write function is called with empty string or buffer, it does nothing and waits for more input.
// However, actually implementation checks the state of finished and aborted before checking if the first arg is empty.
handleWrite(buffer, encoding, callback) {
debug('request write')
const { req } = this
if (req.finished) {
const err = new Error('write after end')
err.code = 'ERR_STREAM_WRITE_AFTER_END'
process.nextTick(() => req.emit('error', err))
// It seems odd to return `true` here, not sure why you'd want to have
// the stream potentially written to more, but it's what Node does.
// https://github.com/nodejs/node/blob/a9270dcbeba4316b1e179b77ecb6c46af5aa8c20/lib/_http_outgoing.js#L662-L665
return true
}
if (req.socket && req.socket.destroyed) {
return false
}
if (!buffer || buffer.length === 0) {
return true
}
if (!Buffer.isBuffer(buffer)) {
buffer = Buffer.from(buffer, encoding)
}
this.requestBodyBuffers.push(buffer)
// can't use instanceof Function because some test runners
// run tests in vm.runInNewContext where Function is not same
// as that in the current context
// https://github.com/nock/nock/pull/1754#issuecomment-571531407
if (typeof callback === 'function') {
callback()
}
common.setImmediate(function () {
req.emit('drain') req.emit('drain')
}) })
@ -139,10 +178,10 @@ class InterceptedRequestRouter {
} }
handleEnd(chunk, encoding, callback) { handleEnd(chunk, encoding, callback) {
debug('req.end') debug('request end')
const { req } = this const { req } = this
// handle the different overloaded param signatures // handle the different overloaded arg signatures
if (typeof chunk === 'function') { if (typeof chunk === 'function') {
callback = chunk callback = chunk
chunk = null chunk = null
@ -155,51 +194,18 @@ class InterceptedRequestRouter {
req.once('finish', callback) req.once('finish', callback)
} }
if (!req.aborted && !this.playbackStarted) { if (chunk) {
req.write(chunk, encoding) req.write(chunk, encoding)
this.startPlayback()
}
if (req.aborted) {
this.emitError(new Error('Request aborted'))
} }
req.finished = true
this.maybeStartPlayback()
return req return req
} }
handleFlushHeaders() { handleFlushHeaders() {
debug('req.flushHeaders') debug('request flushHeaders')
const { req } = this this.maybeStartPlayback()
if (!req.aborted && !this.playbackStarted) {
this.startPlayback()
}
if (req.aborted) {
this.emitError(new Error('Request aborted'))
}
}
handleAbort() {
debug('req.abort')
const { req, response, socket } = this
if (req.aborted) {
return
}
req.aborted = Date.now()
if (!this.playbackStarted) {
this.startPlayback()
}
const err = new Error()
err.code = 'aborted'
response.emit('close', err)
socket.destroy()
req.emit('abort')
const connResetError = new Error('socket hang up')
connResetError.code = 'ECONNRESET'
this.emitError(connResetError)
} }
/** /**
@ -233,6 +239,21 @@ class InterceptedRequestRouter {
} }
} }
maybeStartPlayback() {
const { req, socket, playbackStarted } = this
// In order to get the events in the right order we need to delay playback
// if we get here before the `socket` event is emitted.
if (socket.connecting) {
this.readyToStartPlaybackOnSocketEvent = true
return
}
if (!common.isRequestDestroyed(req) && !playbackStarted) {
this.startPlayback()
}
}
startPlayback() { startPlayback() {
debug('ending') debug('ending')
this.playbackStarted = true this.playbackStarted = true
@ -270,11 +291,14 @@ class InterceptedRequestRouter {
) )
if (matchedInterceptor) { if (matchedInterceptor) {
debug('interceptor identified, starting mocking') matchedInterceptor.scope.logger(
'interceptor identified, starting mocking'
)
matchedInterceptor.markConsumed()
// wait to emit the finish event until we know for sure an Interceptor is going to playback. // wait to emit the finish event until we know for sure an Interceptor is going to playback.
// otherwise an unmocked request might emit finish twice. // otherwise an unmocked request might emit finish twice.
req.finished = true
req.emit('finish') req.emit('finish')
playbackInterceptor({ playbackInterceptor({
@ -304,14 +328,11 @@ class InterceptedRequestRouter {
// We send the raw buffer as we received it, not as we interpreted it. // We send the raw buffer as we received it, not as we interpreted it.
newReq.end(requestBodyBuffer) newReq.end(requestBodyBuffer)
} else { } else {
const err = new Error( const reqStr = common.stringifyRequest(options, requestBodyString)
`Nock: No match for request ${common.stringifyRequest( const err = new Error(`Nock: No match for request ${reqStr}`)
options, err.code = 'ERR_NOCK_NO_MATCH'
requestBodyString
)}`
)
err.statusCode = err.status = 404 err.statusCode = err.status = 404
this.emitError(err) req.destroy(err)
} }
} }
} }

73
node_modules/nock/lib/interceptor.js generated vendored
View file

@ -1,8 +1,6 @@
'use strict' 'use strict'
const debug = require('debug')('nock.interceptor')
const stringify = require('json-stringify-safe') const stringify = require('json-stringify-safe')
const _ = require('lodash')
const querystring = require('querystring') const querystring = require('querystring')
const { URL, URLSearchParams } = require('url') const { URL, URLSearchParams } = require('url')
@ -34,8 +32,9 @@ module.exports = class Interceptor {
// When enabled filteringScope ignores the passed URL entirely so we skip validation. // When enabled filteringScope ignores the passed URL entirely so we skip validation.
if ( if (
!scope.scopeOptions.filteringScope &&
uriIsStr && uriIsStr &&
!scope.scopeOptions.filteringScope &&
!scope.basePathname &&
!uri.startsWith('/') && !uri.startsWith('/') &&
!uri.startsWith('*') !uri.startsWith('*')
) { ) {
@ -73,7 +72,7 @@ module.exports = class Interceptor {
scope.scopeOptions.badheaders || [] scope.scopeOptions.badheaders || []
) )
this.delayInMs = 0 this.delayBodyInMs = 0
this.delayConnectionInMs = 0 this.delayConnectionInMs = 0
this.optional = false this.optional = false
@ -181,8 +180,8 @@ module.exports = class Interceptor {
} }
} }
debug('reply.headers:', this.headers) this.scope.logger('reply.headers:', this.headers)
debug('reply.rawHeaders:', this.rawHeaders) this.scope.logger('reply.rawHeaders:', this.rawHeaders)
this.body = body this.body = body
@ -228,13 +227,23 @@ module.exports = class Interceptor {
} }
} }
debug("request header field doesn't match:", key, header, reqHeader) this.scope.logger(
"request header field doesn't match:",
key,
header,
reqHeader
)
return false return false
} }
match(req, options, body) { match(req, options, body) {
if (debug.enabled) { // check if the logger is enabled because the stringifies can be expensive.
debug('match %s, body = %s', stringify(options), stringify(body)) if (this.scope.logger.enabled) {
this.scope.logger(
'attempting match %s, body = %s',
stringify(options),
stringify(body)
)
} }
const method = (options.method || 'GET').toUpperCase() const method = (options.method || 'GET').toUpperCase()
@ -244,7 +253,7 @@ module.exports = class Interceptor {
const { proto } = options const { proto } = options
if (this.method !== method) { if (this.method !== method) {
debug( this.scope.logger(
`Method did not match. Request ${method} Interceptor ${this.method}` `Method did not match. Request ${method} Interceptor ${this.method}`
) )
return false return false
@ -276,6 +285,7 @@ module.exports = class Interceptor {
) )
if (!reqHeadersMatch) { if (!reqHeadersMatch) {
this.scope.logger("headers don't match")
return false return false
} }
@ -283,26 +293,32 @@ module.exports = class Interceptor {
this.scope.scopeOptions.conditionally && this.scope.scopeOptions.conditionally &&
!this.scope.scopeOptions.conditionally() !this.scope.scopeOptions.conditionally()
) { ) {
this.scope.logger(
'matching failed because Scope.conditionally() did not validate'
)
return false return false
} }
const reqContainsBadHeaders = this.badheaders.some( const badHeaders = this.badheaders.filter(
header => header in options.headers header => header in options.headers
) )
if (reqContainsBadHeaders) { if (badHeaders.length) {
this.scope.logger('request contains bad headers', ...badHeaders)
return false return false
} }
// Match query strings when using query() // Match query strings when using query()
if (this.queries === null) { if (this.queries === null) {
debug('query matching skipped') this.scope.logger('query matching skipped')
} else { } else {
// can't rely on pathname or search being in the options, but path has a default // can't rely on pathname or search being in the options, but path has a default
const [pathname, search] = path.split('?') const [pathname, search] = path.split('?')
const matchQueries = this.matchQuery({ search }) const matchQueries = this.matchQuery({ search })
debug(matchQueries ? 'query matching succeeded' : 'query matching failed') this.scope.logger(
matchQueries ? 'query matching succeeded' : 'query matching failed'
)
if (!matchQueries) { if (!matchQueries) {
return false return false
@ -405,8 +421,8 @@ module.exports = class Interceptor {
} }
const reqQueries = querystring.parse(options.search) const reqQueries = querystring.parse(options.search)
debug('Interceptor queries: %j', this.queries) this.scope.logger('Interceptor queries: %j', this.queries)
debug(' Request queries: %j', reqQueries) this.scope.logger(' Request queries: %j', reqQueries)
if (typeof this.queries === 'function') { if (typeof this.queries === 'function') {
return this.queries(reqQueries) return this.queries(reqQueries)
@ -483,7 +499,7 @@ module.exports = class Interceptor {
// Normalize the data into the shape that is matched against. // Normalize the data into the shape that is matched against.
// Duplicate keys are handled by combining the values into an array. // Duplicate keys are handled by combining the values into an array.
queries = querystring.parse(queries.toString()) queries = querystring.parse(queries.toString())
} else if (!_.isPlainObject(queries)) { } else if (!common.isPlainObject(queries)) {
throw Error(`Argument Error: ${queries}`) throw Error(`Argument Error: ${queries}`)
} }
@ -583,7 +599,7 @@ module.exports = class Interceptor {
* @return {Interceptor} - the current interceptor for chaining * @return {Interceptor} - the current interceptor for chaining
*/ */
delayBody(ms) { delayBody(ms) {
this.delayInMs += ms this.delayBodyInMs = ms
return this return this
} }
@ -594,26 +610,7 @@ module.exports = class Interceptor {
* @return {Interceptor} - the current interceptor for chaining * @return {Interceptor} - the current interceptor for chaining
*/ */
delayConnection(ms) { delayConnection(ms) {
this.delayConnectionInMs += ms this.delayConnectionInMs = ms
return this
}
/**
* @private
* @returns {number}
*/
getTotalDelay() {
return this.delayInMs + this.delayConnectionInMs
}
/**
* Make the socket idle for a certain number of ms (simulated).
*
* @param {integer} ms - Number of milliseconds to wait
* @return {Interceptor} - the current interceptor for chaining
*/
socketDelay(ms) {
this.socketDelayInMs = ms
return this return this
} }
} }

View file

@ -1,6 +1,5 @@
'use strict' 'use strict'
const _ = require('lodash')
const querystring = require('querystring') const querystring = require('querystring')
const common = require('./common') const common = require('./common')
@ -70,8 +69,8 @@ function mapValuesDeep(obj, cb) {
if (Array.isArray(obj)) { if (Array.isArray(obj)) {
return obj.map(v => mapValuesDeep(v, cb)) return obj.map(v => mapValuesDeep(v, cb))
} }
if (_.isPlainObject(obj)) { if (common.isPlainObject(obj)) {
return _.mapValues(obj, v => mapValuesDeep(v, cb)) return common.mapValue(obj, v => mapValuesDeep(v, cb))
} }
return cb(obj) return cb(obj)
} }

View file

@ -1,10 +1,10 @@
'use strict' 'use strict'
const stream = require('stream')
const util = require('util') const util = require('util')
const zlib = require('zlib') const zlib = require('zlib')
const debug = require('debug')('nock.playback_interceptor') const debug = require('debug')('nock.playback_interceptor')
const common = require('./common') const common = require('./common')
const DelayedBody = require('./delayed_body')
function parseJSONRequestBody(req, requestBody) { function parseJSONRequestBody(req, requestBody) {
if (!requestBody || !common.isJSONContent(req.headers)) { if (!requestBody || !common.isJSONContent(req.headers)) {
@ -71,6 +71,44 @@ function selectDefaultHeaders(existingHeaders, defaultHeaders) {
return result return result
} }
// Presents a list of Buffers as a Readable
class ReadableBuffers extends stream.Readable {
constructor(buffers, opts = {}) {
super(opts)
this.buffers = buffers
}
_read(size) {
while (this.buffers.length) {
if (!this.push(this.buffers.shift())) {
return
}
}
this.push(null)
}
}
function convertBodyToStream(body) {
if (common.isStream(body)) {
return body
}
if (body === undefined) {
return new ReadableBuffers([])
}
if (Buffer.isBuffer(body)) {
return new ReadableBuffers([body])
}
if (typeof body !== 'string') {
body = JSON.stringify(body)
}
return new ReadableBuffers([Buffer.from(body)])
}
/** /**
* Play back an interceptor using the given request and mock response. * Play back an interceptor using the given request and mock response.
*/ */
@ -83,28 +121,23 @@ function playbackInterceptor({
response, response,
interceptor, interceptor,
}) { }) {
function emitError(error) { const { logger } = interceptor.scope
process.nextTick(() => {
req.emit('error', error)
})
}
function start() { function start() {
interceptor.req = req
req.headers = req.getHeaders() req.headers = req.getHeaders()
interceptor.scope.emit('request', req, interceptor, requestBodyString) interceptor.scope.emit('request', req, interceptor, requestBodyString)
if (typeof interceptor.errorMessage !== 'undefined') { if (typeof interceptor.errorMessage !== 'undefined') {
interceptor.markConsumed()
let error let error
if (typeof interceptor.errorMessage === 'object') { if (typeof interceptor.errorMessage === 'object') {
error = interceptor.errorMessage error = interceptor.errorMessage
} else { } else {
error = new Error(interceptor.errorMessage) error = new Error(interceptor.errorMessage)
} }
common.setTimeout(() => emitError(error), interceptor.getTotalDelay())
const delay = interceptor.delayBodyInMs + interceptor.delayConnectionInMs
common.setTimeout(() => req.destroy(error), delay)
return return
} }
@ -114,7 +147,14 @@ function playbackInterceptor({
// Clone headers/rawHeaders to not override them when evaluating later // Clone headers/rawHeaders to not override them when evaluating later
response.rawHeaders = [...interceptor.rawHeaders] response.rawHeaders = [...interceptor.rawHeaders]
debug('response.rawHeaders:', response.rawHeaders) logger('response.rawHeaders:', response.rawHeaders)
// TODO: MAJOR: Don't tack the request onto the interceptor.
// The only reason we do this is so that it's available inside reply functions.
// It would be better to pass the request as an argument to the functions instead.
// Not adding the req as a third arg now because it should first be decided if (path, body, req)
// is the signature we want to go with going forward.
interceptor.req = req
if (interceptor.replyFunction) { if (interceptor.replyFunction) {
const parsedRequestBody = parseJSONRequestBody(req, requestBodyString) const parsedRequestBody = parseJSONRequestBody(req, requestBodyString)
@ -128,8 +168,8 @@ function playbackInterceptor({
// At this point `fn` is either a synchronous function or a promise-returning function; // At this point `fn` is either a synchronous function or a promise-returning function;
// wrapping in `Promise.resolve` makes it into a promise either way. // wrapping in `Promise.resolve` makes it into a promise either way.
Promise.resolve(fn.call(interceptor, options.path, parsedRequestBody)) Promise.resolve(fn.call(interceptor, options.path, parsedRequestBody))
.then(responseBody => continueWithResponseBody({ responseBody })) .then(continueWithResponseBody)
.catch(err => emitError(err)) .catch(err => req.destroy(err))
return return
} }
@ -142,8 +182,8 @@ function playbackInterceptor({
} }
Promise.resolve(fn.call(interceptor, options.path, parsedRequestBody)) Promise.resolve(fn.call(interceptor, options.path, parsedRequestBody))
.then(fullReplyResult => continueWithFullResponse({ fullReplyResult })) .then(continueWithFullResponse)
.catch(err => emitError(err)) .catch(err => req.destroy(err))
return return
} }
@ -155,21 +195,12 @@ function playbackInterceptor({
// of response buffers which should be mocked one by one. // of response buffers which should be mocked one by one.
// (otherwise decompressions after the first one fails as unzip expects to receive // (otherwise decompressions after the first one fails as unzip expects to receive
// buffer by buffer and not one single merged buffer) // buffer by buffer and not one single merged buffer)
if (interceptor.delayInMs) {
emitError(
new Error(
'Response delay of the body is currently not supported with content-encoded responses.'
)
)
return
}
const bufferData = Array.isArray(interceptor.body) const bufferData = Array.isArray(interceptor.body)
? interceptor.body ? interceptor.body
: [interceptor.body] : [interceptor.body]
const responseBuffers = bufferData.map(data => Buffer.from(data, 'hex')) const responseBuffers = bufferData.map(data => Buffer.from(data, 'hex'))
continueWithResponseBody({ responseBuffers }) const responseBody = new ReadableBuffers(responseBuffers)
continueWithResponseBody(responseBody)
return return
} }
@ -194,155 +225,103 @@ function playbackInterceptor({
} }
} }
return continueWithResponseBody({ responseBody }) return continueWithResponseBody(responseBody)
} }
function continueWithFullResponse({ fullReplyResult }) { function continueWithFullResponse(fullReplyResult) {
let responseBody let responseBody
try { try {
responseBody = parseFullReplyResult(response, fullReplyResult) responseBody = parseFullReplyResult(response, fullReplyResult)
} catch (innerErr) { } catch (err) {
emitError(innerErr) req.destroy(err)
return return
} }
continueWithResponseBody({ responseBody }) continueWithResponseBody(responseBody)
} }
function continueWithResponseBody({ responseBuffers, responseBody }) { function prepareResponseHeaders(body) {
// Transform the response body if it exists (it may not exist const defaultHeaders = [...interceptor.scope._defaultReplyHeaders]
// if we have `responseBuffers` instead)
if (responseBody !== undefined) {
debug('transform the response body')
if (interceptor.delayInMs) { // Include a JSON content type when JSON.stringify is called on the body.
debug( // This is a convenience added by Nock that has no analog in Node. It's added to the
'delaying the response for', // defaults, so it will be ignored if the caller explicitly provided the header already.
interceptor.delayInMs, const isJSON =
'milliseconds' body !== undefined &&
) typeof body !== 'string' &&
// Because setTimeout is called immediately in DelayedBody(), so we !Buffer.isBuffer(body) &&
// need count in the delayConnectionInMs. !common.isStream(body)
responseBody = new DelayedBody(
interceptor.getTotalDelay(),
responseBody
)
}
if (common.isStream(responseBody)) { if (isJSON) {
debug('response body is a stream') defaultHeaders.push('Content-Type', 'application/json')
responseBody.pause()
responseBody.on('data', function(d) {
response.push(d)
})
responseBody.on('end', function() {
response.push(null)
// https://nodejs.org/dist/latest-v10.x/docs/api/http.html#http_message_complete
response.complete = true
})
responseBody.on('error', function(err) {
response.emit('error', err)
})
} else if (!Buffer.isBuffer(responseBody)) {
if (typeof responseBody === 'string') {
responseBody = Buffer.from(responseBody)
} else {
responseBody = JSON.stringify(responseBody)
response.rawHeaders.push('Content-Type', 'application/json')
}
}
// Why are strings converted to a Buffer, but JSON data is left as a string?
// Related to https://github.com/nock/nock/issues/1542 ?
}
interceptor.markConsumed()
if (req.aborted) {
return
} }
response.rawHeaders.push( response.rawHeaders.push(
...selectDefaultHeaders( ...selectDefaultHeaders(response.rawHeaders, defaultHeaders)
response.rawHeaders,
interceptor.scope._defaultReplyHeaders
)
) )
// Evaluate functional headers. // Evaluate functional headers.
common.forEachHeader(response.rawHeaders, (value, fieldName, i) => { common.forEachHeader(response.rawHeaders, (value, fieldName, i) => {
if (typeof value === 'function') { if (typeof value === 'function') {
response.rawHeaders[i + 1] = value(req, response, responseBody) response.rawHeaders[i + 1] = value(req, response, body)
} }
}) })
response.headers = common.headersArrayToObject(response.rawHeaders) response.headers = common.headersArrayToObject(response.rawHeaders)
process.nextTick(() =>
respondUsingInterceptor({
responseBody,
responseBuffers,
})
)
} }
function respondUsingInterceptor({ responseBody, responseBuffers }) { function continueWithResponseBody(rawBody) {
if (req.aborted) { prepareResponseHeaders(rawBody)
return const bodyAsStream = convertBodyToStream(rawBody)
} bodyAsStream.pause()
// IncomingMessage extends Readable so we can't simply pipe.
bodyAsStream.on('data', function (chunk) {
response.push(chunk)
})
bodyAsStream.on('end', function () {
// https://nodejs.org/dist/latest-v10.x/docs/api/http.html#http_message_complete
response.complete = true
response.push(null)
interceptor.scope.emit('replied', req, interceptor)
})
bodyAsStream.on('error', function (err) {
response.emit('error', err)
})
const { delayBodyInMs, delayConnectionInMs } = interceptor
function respond() { function respond() {
if (req.aborted) { if (common.isRequestDestroyed(req)) {
return return
} }
debug('emitting response') // Even though we've had the response object for awhile at this point,
// we only attach it to the request immediately before the `response`
// event because, as in Node, it alters the error handling around aborts.
req.res = response
response.req = req
logger('emitting response')
req.emit('response', response) req.emit('response', response)
if (common.isStream(responseBody)) { common.setTimeout(() => bodyAsStream.resume(), delayBodyInMs)
debug('resuming response stream')
responseBody.resume()
} else {
responseBuffers = responseBuffers || []
if (typeof responseBody !== 'undefined') {
debug('adding body to buffer list')
responseBuffers.push(responseBody)
}
// Stream the response chunks one at a time.
common.setImmediate(function emitChunk() {
const chunk = responseBuffers.shift()
if (chunk) {
debug('emitting response chunk')
response.push(chunk)
common.setImmediate(emitChunk)
} else {
debug('ending response stream')
response.push(null)
// https://nodejs.org/dist/latest-v10.x/docs/api/http.html#http_message_complete
response.complete = true
interceptor.scope.emit('replied', req, interceptor)
}
})
}
} }
if (interceptor.socketDelayInMs && interceptor.socketDelayInMs > 0) { socket.applyDelay(delayConnectionInMs)
socket.applyDelay(interceptor.socketDelayInMs) common.setTimeout(respond, delayConnectionInMs)
}
if (
interceptor.delayConnectionInMs &&
interceptor.delayConnectionInMs > 0
) {
socket.applyDelay(interceptor.delayConnectionInMs)
common.setTimeout(respond, interceptor.delayConnectionInMs)
} else {
respond()
}
} }
start() // Calling `start` immediately could take the request all the way to the connection delay
// during a single microtask execution. This setImmediate stalls the playback to ensure the
// correct events are emitted first ('socket', 'finish') and any aborts in the in the queue or
// called during a 'finish' listener can be called.
common.setImmediate(() => {
if (!common.isRequestDestroyed(req)) {
start()
}
})
} }
module.exports = { playbackInterceptor } module.exports = { playbackInterceptor }

20
node_modules/nock/lib/recorder.js generated vendored
View file

@ -110,6 +110,10 @@ function generateRequestAndResponse({
const queryStr = req.path.slice(queryIndex + 1) const queryStr = req.path.slice(queryIndex + 1)
queryObj = querystring.parse(queryStr) queryObj = querystring.parse(queryStr)
} }
// Escape any single quotes in the path as the output uses them
path = path.replace(/'/g, `\\'`)
// Always encode the query parameters when recording. // Always encode the query parameters when recording.
const encodedQueryObj = {} const encodedQueryObj = {}
for (const key in queryObj) { for (const key in queryObj) {
@ -211,7 +215,7 @@ function record(recOptions) {
restoreOverriddenClientRequest() restoreOverriddenClientRequest()
// We override the requests so that we can save information on them before executing. // We override the requests so that we can save information on them before executing.
common.overrideRequests(function(proto, overriddenRequest, rawArgs) { common.overrideRequests(function (proto, overriddenRequest, rawArgs) {
const { options, callback } = common.normalizeClientRequestArgs(...rawArgs) const { options, callback } = common.normalizeClientRequestArgs(...rawArgs)
const bodyChunks = [] const bodyChunks = []
@ -223,11 +227,11 @@ function record(recOptions) {
} }
options._recording = true options._recording = true
const req = overriddenRequest(options, function(res) { const req = overriddenRequest(options, function (res) {
debug(thisRecordingId, 'intercepting', proto, 'request to record') debug(thisRecordingId, 'intercepting', proto, 'request to record')
// We put our 'end' listener to the front of the listener array. // We put our 'end' listener to the front of the listener array.
res.once('end', function() { res.once('end', function () {
debug(thisRecordingId, proto, 'intercepted request ended') debug(thisRecordingId, proto, 'intercepted request ended')
let reqheaders let reqheaders
@ -284,7 +288,7 @@ function record(recOptions) {
// We need to be aware of changes to the stream's encoding so that we // We need to be aware of changes to the stream's encoding so that we
// don't accidentally mangle the data. // don't accidentally mangle the data.
const { setEncoding } = res const { setEncoding } = res
res.setEncoding = function(newEncoding) { res.setEncoding = function (newEncoding) {
encoding = newEncoding encoding = newEncoding
return setEncoding.apply(this, arguments) return setEncoding.apply(this, arguments)
} }
@ -292,7 +296,7 @@ function record(recOptions) {
const dataChunks = [] const dataChunks = []
// Replace res.push with our own implementation that stores chunks // Replace res.push with our own implementation that stores chunks
const origResPush = res.push const origResPush = res.push
res.push = function(data) { res.push = function (data) {
if (data) { if (data) {
if (encoding) { if (encoding) {
data = Buffer.from(data, encoding) data = Buffer.from(data, encoding)
@ -305,8 +309,6 @@ function record(recOptions) {
if (callback) { if (callback) {
callback(res, options, callback) callback(res, options, callback)
} else {
res.resume()
} }
debug('finished setting up intercepting') debug('finished setting up intercepting')
@ -329,7 +331,7 @@ function record(recOptions) {
} }
const oldWrite = req.write const oldWrite = req.write
req.write = function(chunk, encoding) { req.write = function (chunk, encoding) {
if (typeof chunk !== 'undefined') { if (typeof chunk !== 'undefined') {
recordChunk(chunk, encoding) recordChunk(chunk, encoding)
oldWrite.apply(req, arguments) oldWrite.apply(req, arguments)
@ -342,7 +344,7 @@ function record(recOptions) {
// `write_` function instead of proxying to the public // `write_` function instead of proxying to the public
// `OutgoingMessage.write()` method, so we have to wrap `end` too. // `OutgoingMessage.write()` method, so we have to wrap `end` too.
const oldEnd = req.end const oldEnd = req.end
req.end = function(chunk, encoding, callback) { req.end = function (chunk, encoding, callback) {
debug('req.end') debug('req.end')
if (typeof chunk === 'function') { if (typeof chunk === 'function') {
callback = chunk callback = chunk

40
node_modules/nock/lib/scope.js generated vendored
View file

@ -9,7 +9,6 @@ const assert = require('assert')
const url = require('url') const url = require('url')
const debug = require('debug')('nock.scope') const debug = require('debug')('nock.scope')
const { EventEmitter } = require('events') const { EventEmitter } = require('events')
const util = require('util')
const Interceptor = require('./interceptor') const Interceptor = require('./interceptor')
let fs let fs
@ -40,7 +39,6 @@ class Scope extends EventEmitter {
this.transformPathFunction = null this.transformPathFunction = null
this.transformRequestBodyFunction = null this.transformRequestBodyFunction = null
this.matchHeaders = [] this.matchHeaders = []
this.logger = debug
this.scopeOptions = options || {} this.scopeOptions = options || {}
this.urlParts = {} this.urlParts = {}
this._persist = false this._persist = false
@ -51,13 +49,18 @@ class Scope extends EventEmitter {
this.port = null this.port = null
this._defaultReplyHeaders = [] this._defaultReplyHeaders = []
let logNamespace = String(basePath)
if (!(basePath instanceof RegExp)) { if (!(basePath instanceof RegExp)) {
this.urlParts = url.parse(basePath) this.urlParts = url.parse(basePath)
this.port = this.port =
this.urlParts.port || (this.urlParts.protocol === 'http:' ? 80 : 443) this.urlParts.port || (this.urlParts.protocol === 'http:' ? 80 : 443)
this.basePathname = this.urlParts.pathname.replace(/\/$/, '') this.basePathname = this.urlParts.pathname.replace(/\/$/, '')
this.basePath = `${this.urlParts.protocol}//${this.urlParts.hostname}:${this.port}` this.basePath = `${this.urlParts.protocol}//${this.urlParts.hostname}:${this.port}`
logNamespace = this.urlParts.host
} }
this.logger = debug.extend(logNamespace)
} }
add(key, interceptor) { add(key, interceptor) {
@ -170,7 +173,7 @@ class Scope extends EventEmitter {
const filteringArguments = arguments const filteringArguments = arguments
if (arguments[0] instanceof RegExp) { if (arguments[0] instanceof RegExp) {
return function(candidate) { return function (candidate) {
/* istanbul ignore if */ /* istanbul ignore if */
if (typeof candidate !== 'string') { if (typeof candidate !== 'string') {
// Given the way nock is written, it seems like `candidate` will always // Given the way nock is written, it seems like `candidate` will always
@ -219,11 +222,6 @@ class Scope extends EventEmitter {
return this return this
} }
log(newLogger) {
this.logger = newLogger
return this
}
persist(flag = true) { persist(flag = true) {
if (typeof flag !== 'boolean') { if (typeof flag !== 'boolean') {
throw new Error('Invalid arguments: argument should be a boolean') throw new Error('Invalid arguments: argument should be a boolean')
@ -306,17 +304,10 @@ function tryJsonParse(string) {
} }
} }
// Use a noop deprecate util instead calling emitWarning directly so we get --no-deprecation and single warning behavior for free.
const emitAsteriskDeprecation = util.deprecate(
() => {},
'Skipping body matching using "*" is deprecated. Set the definition body to undefined instead.',
'NOCK1579'
)
function define(nockDefs) { function define(nockDefs) {
const scopes = [] const scopes = []
nockDefs.forEach(function(nockDef) { nockDefs.forEach(function (nockDef) {
const nscope = getScopeFromDefinition(nockDef) const nscope = getScopeFromDefinition(nockDef)
const npath = nockDef.path const npath = nockDef.path
if (!nockDef.method) { if (!nockDef.method) {
@ -335,23 +326,12 @@ function define(nockDefs) {
options.reqheaders = reqheaders options.reqheaders = reqheaders
options.badheaders = badheaders options.badheaders = badheaders
let { body } = nockDef
if (body === '*') {
// In previous versions, it was impossible to NOT filter on request bodies. This special value
// is sniffed out for users manipulating the definitions and not wanting to match on the
// request body. For newer versions, users should remove the `body` key or set to `undefined`
// to achieve the same affect. Maintaining legacy behavior for now.
emitAsteriskDeprecation()
body = undefined
}
// Response is not always JSON as it could be a string or binary data or // Response is not always JSON as it could be a string or binary data or
// even an array of binary buffers (e.g. when content is encoded). // even an array of binary buffers (e.g. when content is encoded).
let response let response
if (!nockDef.response) { if (!nockDef.response) {
response = '' response = ''
// TODO: Rename `responseIsBinary` to `reponseIsUtf8Representable`. // TODO: Rename `responseIsBinary` to `responseIsUtf8Representable`.
} else if (nockDef.responseIsBinary) { } else if (nockDef.responseIsBinary) {
response = Buffer.from(nockDef.response, 'hex') response = Buffer.from(nockDef.response, 'hex')
} else { } else {
@ -375,7 +355,9 @@ function define(nockDefs) {
} }
}) })
scope.intercept(npath, method, body).reply(status, response, rawHeaders) scope
.intercept(npath, method, nockDef.body)
.reply(status, response, rawHeaders)
scopes.push(scope) scopes.push(scope)
}) })

55
node_modules/nock/lib/socket.js generated vendored
View file

@ -7,9 +7,12 @@ module.exports = class Socket extends EventEmitter {
constructor(options) { constructor(options) {
super() super()
// Pretend this is a TLSSocket
if (options.proto === 'https') { if (options.proto === 'https') {
// https://github.com/nock/nock/issues/158 // https://github.com/nock/nock/issues/158
this.authorized = true this.authorized = true
// https://github.com/nock/nock/issues/2147
this.encrypted = true
} }
this.bufferSize = 0 this.bufferSize = 0
@ -18,14 +21,13 @@ module.exports = class Socket extends EventEmitter {
this.readable = true this.readable = true
this.pending = false this.pending = false
this.destroyed = false this.destroyed = false
this.connecting = false this.connecting = true
// totalDelay that has already been applied to the current // Undocumented flag used by ClientRequest to ensure errors aren't double-fired
// request/connection, timeout error will be generated if this._hadError = false
// it is timed-out.
this.totalDelayMs = 0 // Maximum allowed delay. 0 means unlimited.
// Maximum allowed delay. Null means unlimited. this.timeout = 0
this.timeoutMs = null
const ipv6 = options.family === 6 const ipv6 = options.family === 6
this.remoteFamily = ipv6 ? 'IPv6' : 'IPv4' this.remoteFamily = ipv6 ? 'IPv6' : 'IPv4'
@ -48,16 +50,22 @@ module.exports = class Socket extends EventEmitter {
} }
setTimeout(timeoutMs, fn) { setTimeout(timeoutMs, fn) {
this.timeoutMs = timeoutMs this.timeout = timeoutMs
if (fn) { if (fn) {
this.once('timeout', fn) this.once('timeout', fn)
} }
return this
} }
/**
* Artificial delay that will trip socket timeouts when appropriate.
*
* Doesn't actually wait for time to pass.
* Timeout events don't necessarily end the request.
* While many clients choose to abort the request upon a timeout, Node itself does not.
*/
applyDelay(delayMs) { applyDelay(delayMs) {
this.totalDelayMs += delayMs if (this.timeout && delayMs > this.timeout) {
if (this.timeoutMs && this.totalDelayMs > this.timeoutMs) {
debug('socket timeout') debug('socket timeout')
this.emit('timeout') this.emit('timeout')
} }
@ -69,12 +77,31 @@ module.exports = class Socket extends EventEmitter {
).toString('base64') ).toString('base64')
} }
/**
* Denotes that no more I/O activity should happen on this socket.
*
* The implementation in Node if far more complex as it juggles underlying async streams.
* For the purposes of Nock, we just need it to set some flags and on the first call
* emit a 'close' and optional 'error' event. Both events propagate through the request object.
*/
destroy(err) { destroy(err) {
if (this.destroyed) {
return this
}
debug('socket destroy')
this.destroyed = true this.destroyed = true
this.readable = this.writable = false this.readable = this.writable = false
if (err) { this.readableEnded = this.writableFinished = true
this.emit('error', err)
} process.nextTick(() => {
if (err) {
this._hadError = true
this.emit('error', err)
}
this.emit('close')
})
return this return this
} }
} }

65
node_modules/nock/package.json generated vendored
View file

@ -7,7 +7,7 @@
"testing", "testing",
"isolation" "isolation"
], ],
"version": "12.0.3", "version": "13.1.1",
"author": "Pedro Teixeira <pedro.teixeira@gmail.com>", "author": "Pedro Teixeira <pedro.teixeira@gmail.com>",
"repository": { "repository": {
"type": "git", "type": "git",
@ -24,36 +24,35 @@
"dependencies": { "dependencies": {
"debug": "^4.1.0", "debug": "^4.1.0",
"json-stringify-safe": "^5.0.1", "json-stringify-safe": "^5.0.1",
"lodash": "^4.17.13", "lodash.set": "^4.3.2",
"propagate": "^2.0.0" "propagate": "^2.0.0"
}, },
"devDependencies": { "devDependencies": {
"@sinonjs/fake-timers": "^7.0.2",
"assert-rejects": "^1.0.0", "assert-rejects": "^1.0.0",
"chai": "^4.1.2", "chai": "^4.1.2",
"dirty-chai": "^2.0.1", "dirty-chai": "^2.0.1",
"dtslint": "^3.0.0", "dtslint": "^4.0.4",
"eslint": "^6.0.0", "eslint": "^7.3.1",
"eslint-config-prettier": "^6.0.0", "eslint-config-prettier": "^8.1.0",
"eslint-config-standard": "^14.0.0", "eslint-config-standard": "^16.0.2",
"eslint-plugin-import": "^2.16.0", "eslint-plugin-import": "^2.16.0",
"eslint-plugin-mocha": "^6.2.0", "eslint-plugin-mocha": "^8.0.0",
"eslint-plugin-node": "^11.0.0", "eslint-plugin-node": "^11.0.0",
"eslint-plugin-promise": "^4.1.1", "eslint-plugin-promise": "^4.1.1",
"eslint-plugin-standard": "^4.0.0", "eslint-plugin-standard": "^5.0.0",
"got": "^10.5.2", "form-data": "^4.0.0",
"@sinonjs/fake-timers": "^6.0.0", "got": "^11.3.0",
"mocha": "^7.0.1", "mocha": "^8.0.1",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"nyc": "^15.0.0", "nyc": "^15.0.0",
"prettier": "1.19.0", "prettier": "2.2.1",
"proxyquire": "^2.1.0", "proxyquire": "^2.1.0",
"request": "^2.83.0",
"rimraf": "^3.0.0", "rimraf": "^3.0.0",
"semantic-release": "^17.0.2", "semantic-release": "^17.0.2",
"sinon": "^9.0.0", "sinon": "^10.0.0",
"sinon-chai": "^3.3.0", "sinon-chai": "^3.3.0",
"superagent": "^5.0.2", "typescript": "^4.2.2"
"tap": "14.6.1"
}, },
"scripts": { "scripts": {
"format:fix": "prettier --write '**/*.{js,json,md,ts,yml,yaml}'", "format:fix": "prettier --write '**/*.{js,json,md,ts,yml,yaml}'",
@ -62,25 +61,29 @@
"lint:js": "eslint --cache --cache-location './.cache/eslint' '**/*.js'", "lint:js": "eslint --cache --cache-location './.cache/eslint' '**/*.js'",
"lint:js:fix": "eslint --cache --cache-location './.cache/eslint' --fix '**/*.js'", "lint:js:fix": "eslint --cache --cache-location './.cache/eslint' --fix '**/*.js'",
"lint:ts": "dtslint types", "lint:ts": "dtslint types",
"semantic-release": "semantic-release", "test": "nyc mocha tests",
"test": "run-s test:mocha test:tap", "test:coverage": "open coverage/lcov-report/index.html"
"test:coverage": "tap --coverage-report=html && open coverage/lcov-report/index.html",
"test:mocha": "nyc mocha $(grep -lr '^\\s*it(' tests)",
"test:tap": "tap --100 --coverage --coverage-report=text ./tests/test_*.js"
},
"nyc": {
"reporter": [
"lcov",
"text-summary"
],
"exclude": [
"tests/"
]
}, },
"license": "MIT", "license": "MIT",
"files": [ "files": [
"index.js", "index.js",
"lib", "lib",
"types/index.d.ts" "types/index.d.ts"
] ],
"release": {
"branches": [
"+([0-9])?(.{+([0-9]),x}).x",
"main",
"next",
"next-major",
{
"name": "beta",
"prerelease": true
},
{
"name": "alpha",
"prerelease": true
}
]
}
} }

4
node_modules/nock/types/index.d.ts generated vendored
View file

@ -52,7 +52,7 @@ declare namespace nock {
| RegExp | RegExp
| DataMatcherArray | DataMatcherArray
| DataMatcherMap | DataMatcherMap
interface DataMatcherArray extends Array<DataMatcher> {} interface DataMatcherArray extends ReadonlyArray<DataMatcher> {}
interface DataMatcherMap { interface DataMatcherMap {
[key: string]: DataMatcher [key: string]: DataMatcher
} }
@ -120,7 +120,6 @@ declare namespace nock {
filteringRequestBody(regex: RegExp, replace: string): this filteringRequestBody(regex: RegExp, replace: string): this
filteringRequestBody(fn: (body: string) => string): this filteringRequestBody(fn: (body: string) => string): this
log(out: (message: any, ...optionalParams: any[]) => void): this
persist(flag?: boolean): this persist(flag?: boolean): this
replyContentLength(): this replyContentLength(): this
replyDate(d?: Date): this replyDate(d?: Date): this
@ -204,7 +203,6 @@ declare namespace nock {
delay(opts: number | { head?: number; body?: number }): this delay(opts: number | { head?: number; body?: number }): this
delayBody(timeMs: number): this delayBody(timeMs: number): this
delayConnection(timeMs: number): this delayConnection(timeMs: number): this
socketDelay(timeMs: number): this
} }
interface Options { interface Options {

27
package-lock.json generated
View file

@ -52,7 +52,7 @@
"eslint-plugin-import": "^2.22.0", "eslint-plugin-import": "^2.22.0",
"eslint-plugin-no-async-foreach": "^0.1.1", "eslint-plugin-no-async-foreach": "^0.1.1",
"micromatch": "4.0.2", "micromatch": "4.0.2",
"nock": "^12.0.3", "nock": "^13.1.1",
"removeNPMAbsolutePaths": "2.0.0", "removeNPMAbsolutePaths": "2.0.0",
"sinon": "^9.0.2", "sinon": "^9.0.2",
"typescript": "^4.3.5" "typescript": "^4.3.5"
@ -3405,6 +3405,12 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/lodash.set": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
"integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=",
"dev": true
},
"node_modules/lodash.snakecase": { "node_modules/lodash.snakecase": {
"version": "4.1.1", "version": "4.1.1",
"dev": true, "dev": true,
@ -3627,13 +3633,14 @@
} }
}, },
"node_modules/nock": { "node_modules/nock": {
"version": "12.0.3", "version": "13.1.1",
"resolved": "https://registry.npmjs.org/nock/-/nock-13.1.1.tgz",
"integrity": "sha512-YKTR9MjfK3kS9/l4nuTxyYm30cgOExRHzkLNhL8nhEUyU4f8Za/dRxOqjhVT1vGs0svWo3dDnJTUX1qxYeWy5w==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"debug": "^4.1.0", "debug": "^4.1.0",
"json-stringify-safe": "^5.0.1", "json-stringify-safe": "^5.0.1",
"lodash": "^4.17.13", "lodash.set": "^4.3.2",
"propagate": "^2.0.0" "propagate": "^2.0.0"
}, },
"engines": { "engines": {
@ -7615,6 +7622,12 @@
"version": "4.6.2", "version": "4.6.2",
"dev": true "dev": true
}, },
"lodash.set": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
"integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=",
"dev": true
},
"lodash.snakecase": { "lodash.snakecase": {
"version": "4.1.1", "version": "4.1.1",
"dev": true "dev": true
@ -7764,12 +7777,14 @@
} }
}, },
"nock": { "nock": {
"version": "12.0.3", "version": "13.1.1",
"resolved": "https://registry.npmjs.org/nock/-/nock-13.1.1.tgz",
"integrity": "sha512-YKTR9MjfK3kS9/l4nuTxyYm30cgOExRHzkLNhL8nhEUyU4f8Za/dRxOqjhVT1vGs0svWo3dDnJTUX1qxYeWy5w==",
"dev": true, "dev": true,
"requires": { "requires": {
"debug": "^4.1.0", "debug": "^4.1.0",
"json-stringify-safe": "^5.0.1", "json-stringify-safe": "^5.0.1",
"lodash": "^4.17.13", "lodash.set": "^4.3.2",
"propagate": "^2.0.0" "propagate": "^2.0.0"
} }
}, },

View file

@ -67,7 +67,7 @@
"eslint-plugin-import": "^2.22.0", "eslint-plugin-import": "^2.22.0",
"eslint-plugin-no-async-foreach": "^0.1.1", "eslint-plugin-no-async-foreach": "^0.1.1",
"micromatch": "4.0.2", "micromatch": "4.0.2",
"nock": "^12.0.3", "nock": "^13.1.1",
"removeNPMAbsolutePaths": "2.0.0", "removeNPMAbsolutePaths": "2.0.0",
"sinon": "^9.0.2", "sinon": "^9.0.2",
"typescript": "^4.3.5" "typescript": "^4.3.5"