Skip to content

Commit

Permalink
refactor: replace LoDash isPlainObject, mapValues, and isMap
Browse files Browse the repository at this point in the history
- `isMap` was added to `util.types` in Node 10.0
  https://nodejs.org/api/util.html#util_util_types_ismap_value
- `isPlainObject` and `mapValue` both came from LoDash's master branch, which is the pending v5.

Ref: nock#1285
  • Loading branch information
mastermatt committed Mar 28, 2020
1 parent dbabf65 commit 96e126c
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 37 deletions.
114 changes: 82 additions & 32 deletions lib/common.js
Expand Up @@ -2,8 +2,9 @@

const _ = require('lodash')
const debug = require('debug')('nock.common')
const url = require('url')
const timers = require('timers')
const url = require('url')
const util = require('util')

/**
* Normalizes the request options so that it always has `host` property.
Expand Down Expand Up @@ -194,7 +195,7 @@ function isJSONContent(headers) {
* Duplicates throw an error.
*/
function headersFieldNamesToLowerCase(headers) {
if (!_.isPlainObject(headers)) {
if (!isPlainObject(headers)) {
throw Error('Headers must be provided as an object')
}

Expand Down Expand Up @@ -243,11 +244,11 @@ function headersInputToRawArray(headers) {
}

// [].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]))
}

if (_.isPlainObject(headers)) {
if (isPlainObject(headers)) {
return [].concat(...Object.entries(headers))
}

Expand Down Expand Up @@ -359,7 +360,7 @@ function addHeaderLine(headers, name, value) {
* @fieldName {String} field name - string with the case-insensitive field name
*/
function deleteHeadersField(headers, fieldNameToDelete) {
if (!_.isPlainObject(headers)) {
if (!isPlainObject(headers)) {
throw Error('headers must be an object')
}

Expand Down Expand Up @@ -575,7 +576,7 @@ function deepEqual(expected, actual) {
return expected.test(actual)
}

if (Array.isArray(expected) || _.isPlainObject(expected)) {
if (Array.isArray(expected) || isPlainObject(expected)) {
if (actual === undefined) {
return false
}
Expand All @@ -591,6 +592,51 @@ function deepEqual(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/master/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/master/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 intervals = []
const immediates = []
Expand All @@ -617,29 +663,33 @@ function removeAllTimers() {
clearTimer(clearImmediate, immediates)
}

exports.normalizeClientRequestArgs = normalizeClientRequestArgs
exports.normalizeRequestOptions = normalizeRequestOptions
exports.normalizeOrigin = normalizeOrigin
exports.isUtf8Representable = isUtf8Representable
exports.overrideRequests = overrideRequests
exports.restoreOverriddenRequests = restoreOverriddenRequests
exports.stringifyRequest = stringifyRequest
exports.isContentEncoded = isContentEncoded
exports.contentEncoding = contentEncoding
exports.isJSONContent = isJSONContent
exports.headersFieldNamesToLowerCase = headersFieldNamesToLowerCase
exports.headersFieldsArrayToLowerCase = headersFieldsArrayToLowerCase
exports.headersArrayToObject = headersArrayToObject
exports.headersInputToRawArray = headersInputToRawArray
exports.deleteHeadersField = deleteHeadersField
exports.forEachHeader = forEachHeader
exports.percentEncode = percentEncode
exports.percentDecode = percentDecode
exports.matchStringOrRegexp = matchStringOrRegexp
exports.formatQueryValue = formatQueryValue
exports.isStream = isStream
exports.dataEqual = dataEqual
exports.setTimeout = setTimeout
exports.setInterval = setInterval
exports.setImmediate = setImmediate
exports.removeAllTimers = removeAllTimers
module.exports = {
contentEncoding,
dataEqual,
deleteHeadersField,
forEachHeader,
formatQueryValue,
headersArrayToObject,
headersFieldNamesToLowerCase,
headersFieldsArrayToLowerCase,
headersInputToRawArray,
isContentEncoded,
isJSONContent,
isPlainObject,
isStream,
isUtf8Representable,
mapValue,
matchStringOrRegexp,
normalizeClientRequestArgs,
normalizeOrigin,
normalizeRequestOptions,
overrideRequests,
percentDecode,
percentEncode,
removeAllTimers,
restoreOverriddenRequests,
setImmediate,
setInterval,
setTimeout,
stringifyRequest,
}
3 changes: 1 addition & 2 deletions lib/interceptor.js
Expand Up @@ -2,7 +2,6 @@

const debug = require('debug')('nock.interceptor')
const stringify = require('json-stringify-safe')
const _ = require('lodash')
const querystring = require('querystring')
const { URL, URLSearchParams } = require('url')

Expand Down Expand Up @@ -483,7 +482,7 @@ module.exports = class Interceptor {
// Normalize the data into the shape that is matched against.
// Duplicate keys are handled by combining the values into an array.
queries = querystring.parse(queries.toString())
} else if (!_.isPlainObject(queries)) {
} else if (!common.isPlainObject(queries)) {
throw Error(`Argument Error: ${queries}`)
}

Expand Down
5 changes: 2 additions & 3 deletions lib/match_body.js
@@ -1,6 +1,5 @@
'use strict'

const _ = require('lodash')
const querystring = require('querystring')

const common = require('./common')
Expand Down Expand Up @@ -70,8 +69,8 @@ function mapValuesDeep(obj, cb) {
if (Array.isArray(obj)) {
return obj.map(v => mapValuesDeep(v, cb))
}
if (_.isPlainObject(obj)) {
return _.mapValues(obj, v => mapValuesDeep(v, cb))
if (common.isPlainObject(obj)) {
return common.mapValue(obj, v => mapValuesDeep(v, cb))
}
return cb(obj)
}

0 comments on commit 96e126c

Please sign in to comment.