Skip to content

Commit

Permalink
fix(deps): remove lodash (#2529)
Browse files Browse the repository at this point in the history
  • Loading branch information
Uzlopak committed Oct 19, 2023
1 parent 0ba089c commit 7bfcb31
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 18 deletions.
100 changes: 87 additions & 13 deletions lib/common.js
@@ -1,8 +1,6 @@
'use strict'

const debug = require('debug')('nock.common')
const isPlainObject = require('lodash/isPlainObject')
const set = require('lodash/set')
const timers = require('timers')
const url = require('url')
const util = require('util')
Expand Down Expand Up @@ -568,17 +566,6 @@ const dataEqual = (expected, actual) => {
return deepEqual(expected, actual)
}

/**
* Converts flat objects whose keys use JSON path notation to nested objects.
*
* The input object is not mutated.
*
* @example
* { 'foo[bar][0]': 'baz' } -> { foo: { bar: [ 'baz' ] } }
*/
const expand = input =>
Object.entries(input).reduce((acc, [k, v]) => set(acc, k, v), {})

/**
* Performs a recursive strict comparison between two values.
*
Expand Down Expand Up @@ -665,10 +652,97 @@ function isRequestDestroyed(req) {
)
}

/**
* Returns true if the given value is a plain object and not an Array.
* @param {*} value
* @returns {boolean}
*/
function isPlainObject(value) {
if (typeof value !== 'object' || value === null) return false

if (Object.prototype.toString.call(value) !== '[object Object]') return false

const proto = Object.getPrototypeOf(value)
if (proto === null) return true

const Ctor =
Object.prototype.hasOwnProperty.call(proto, 'constructor') &&
proto.constructor
return (
typeof Ctor === 'function' &&
Ctor instanceof Ctor &&
Function.prototype.call(Ctor) === Function.prototype.call(value)
)
}

const prototypePollutionBlockList = ['__proto__', 'prototype', 'constructor']
const blocklistFilter = function (part) {
return prototypePollutionBlockList.indexOf(part) === -1
}

/**
* Converts flat objects whose keys use JSON path notation to nested objects.
*
* The input object is not mutated.
*
* @example
* { 'foo[bar][0]': 'baz' } -> { foo: { bar: [ 'baz' ] } }
*/
const expand = input => {
if (input === undefined || input === null) {
return input
}

const keys = Object.keys(input)

const result = {}
let resultPtr = result

for (let path of keys) {
const originalPath = path
if (path.indexOf('[') >= 0) {
path = path.replace(/\[/g, '.').replace(/]/g, '')
}

const parts = path.split('.')

const check = parts.filter(blocklistFilter)

if (check.length !== parts.length) {
return undefined
}
resultPtr = result
const lastIndex = parts.length - 1

for (let i = 0; i < parts.length; ++i) {
const part = parts[i]
if (i === lastIndex) {
if (Array.isArray(resultPtr)) {
resultPtr[+part] = input[originalPath]
} else {
resultPtr[part] = input[originalPath]
}
} else {
if (resultPtr[part] === undefined || resultPtr[part] === null) {
const nextPart = parts[i + 1]
if (/^\d+$/.test(nextPart)) {
resultPtr[part] = []
} else {
resultPtr[part] = {}
}
}
resultPtr = resultPtr[part]
}
}
}
return result
}

module.exports = {
contentEncoding,
dataEqual,
deleteHeadersField,
expand,
forEachHeader,
formatQueryValue,
headersArrayToObject,
Expand Down
9 changes: 8 additions & 1 deletion lib/match_body.js
@@ -1,6 +1,5 @@
'use strict'

const mapValues = require('lodash/mapValues')
const querystring = require('querystring')

const common = require('./common')
Expand Down Expand Up @@ -62,6 +61,14 @@ module.exports = function matchBody(options, spec, body) {
return common.dataEqual(spec, body)
}

function mapValues(object, cb) {
const keys = Object.keys(object)
for (const key of keys) {
object[key] = cb(object[key], key, object)
}
return object
}

/**
* Based on lodash issue discussion
* https://github.com/lodash/lodash/issues/1244
Expand Down
7 changes: 4 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Expand Up @@ -24,7 +24,6 @@
"dependencies": {
"debug": "^4.1.0",
"json-stringify-safe": "^5.0.1",
"lodash": "^4.17.21",
"propagate": "^2.0.0"
},
"devDependencies": {
Expand Down
96 changes: 96 additions & 0 deletions tests/test_common.js
Expand Up @@ -545,3 +545,99 @@ it('testing timers are deleted correctly', done => {
done()
})
})

describe('`isPlainObject()`', () => {
const { isPlainObject } = common

it('custom Object', () => {
function Foo() {
this.a = 1
}
expect(isPlainObject(new Foo()), false)
})

it('Array', () => {
expect(isPlainObject([1, 2, 3]), false)
})

it('Date', () => {
expect(isPlainObject(new Date()), false)
})

it('RegExp', () => {
expect(isPlainObject(/a/), false)
})

it('plain Object', () => {
expect(isPlainObject({}), true)
})

it('null', () => {
expect(isPlainObject(null), true)
})

it('null-Object /1', () => {
expect(isPlainObject({ __proto__: null }), true)
})

it('null-Object /2', () => {
expect(isPlainObject(Object.create(null)), true)
})
})

describe('`expand()`', () => {
const { expand } = common

it('undefined', () => {
expect(expand(undefined), undefined)
})

it('null', () => {
expect(expand(null), null)
})

it('throws on constructor', () => {
expect(expand({ constructor: 4 })).equal(undefined)
})

it('pure key values', () => {
expect(expand({ a: 4 })).deep.equal({ a: 4 })
})

it('nested object', () => {
expect(expand({ 'a.b': 4 })).deep.equal({ a: { b: 4 } })
})

it('nested object', () => {
expect(expand({ 'a.b': 4, 'a.c': 5 })).deep.equal({ a: { b: 4, c: 5 } })
})

it('nested object', () => {
expect(expand({ 'a.b': 4, 'b.a': 5 })).deep.equal({
a: { b: 4 },
b: { a: 5 },
})
})

it('nested array', () => {
expect(expand({ 'a.0': 4, 'a.1': 5 })).deep.equal({ a: [4, 5] })
})

it('array-like', () => {
expect(expand({ 'a[0]': 4, 'a[1]': 5 })).deep.equal({ a: [4, 5] })
})

it('example', () => {
expect(expand({ 'foo[bar][0]': 'baz' })).deep.equal({
foo: { bar: ['baz'] },
})
})

it('does not mutate original', () => {
const original = { 'foo[bar][0]': 'baz' }
const result = expand(original)
expect(result).deep.equal({ foo: { bar: ['baz'] } })
expect(original).deep.equal({ 'foo[bar][0]': 'baz' })
expect(original).not.equal(result)
})
})

0 comments on commit 7bfcb31

Please sign in to comment.