From 96a04ec593237adbbfa7210922e22a805f08090e Mon Sep 17 00:00:00 2001 From: Paul Melnikow Date: Sat, 19 Oct 2019 13:21:18 +0200 Subject: [PATCH 1/3] Replace several more uses of lodash with native --- lib/back.js | 7 +++---- lib/common.js | 10 +++++----- lib/intercept.js | 19 +++++++++---------- lib/interceptor.js | 18 +++++++++--------- lib/match_body.js | 15 +++------------ lib/playback_interceptor.js | 3 +-- 6 files changed, 30 insertions(+), 42 deletions(-) diff --git a/lib/back.js b/lib/back.js index acf9d3489..288576f99 100644 --- a/lib/back.js +++ b/lib/back.js @@ -1,6 +1,5 @@ 'use strict' -const _ = require('lodash') const recorder = require('./recorder') const { activate, @@ -61,7 +60,7 @@ function Back(fixtureName, options, nockedFn) { ) } - if (!_.isString(fixtureName)) { + if (typeof fixtureName !== 'string') { throw new Error('Parameter fixtureName must be a string') } @@ -70,7 +69,7 @@ function Back(fixtureName, options, nockedFn) { } else if (arguments.length === 2) { // If 2nd parameter is a function then `options` has been omitted // otherwise `options` haven't been omitted but `nockedFn` was. - if (_.isFunction(options)) { + if (typeof options === 'function') { nockedFn = options options = {} } @@ -88,7 +87,7 @@ function Back(fixtureName, options, nockedFn) { debug('context:', context) // If nockedFn is a function then invoke it, otherwise return a promise resolving to nockDone. - if (_.isFunction(nockedFn)) { + if (typeof nockedFn === 'function') { nockedFn.call(context, nockDone) } else { return Promise.resolve({ nockDone, context }) diff --git a/lib/common.js b/lib/common.js index db8085e14..3becb7b5a 100644 --- a/lib/common.js +++ b/lib/common.js @@ -176,7 +176,7 @@ function stringifyRequest(options, body) { function isContentEncoded(headers) { const contentEncoding = headers['content-encoding'] - return _.isString(contentEncoding) && contentEncoding !== '' + return typeof contentEncoding === 'string' && contentEncoding !== '' } function contentEncoding(headers, encoder) { @@ -365,7 +365,7 @@ function deleteHeadersField(headers, fieldNameToDelete) { throw Error('headers must be an object') } - if (!_.isString(fieldNameToDelete)) { + if (typeof fieldNameToDelete !== 'string') { throw Error('field name must be a string') } @@ -446,7 +446,7 @@ function formatQueryValue(key, value, stringFormattingFn) { case value === undefined: value = '' break - case _.isString(value): + case typeof value === 'string': if (stringFormattingFn) { value = stringFormattingFn(value) } @@ -459,7 +459,7 @@ function formatQueryValue(key, value, stringFormattingFn) { }) break } - case _.isObject(value): { + case typeof value === 'object': { value = Object.entries(value).reduce(function(acc, [subKey, subVal]) { const subPair = formatQueryValue(subKey, subVal, stringFormattingFn) acc[subPair[0]] = subPair[1] @@ -479,7 +479,7 @@ function isStream(obj) { obj && typeof obj !== 'string' && !Buffer.isBuffer(obj) && - _.isFunction(obj.setEncoding) + typeof obj.setEncoding === 'function' ) } diff --git a/lib/intercept.js b/lib/intercept.js index 3e07f26ea..8b4ee23b9 100644 --- a/lib/intercept.js +++ b/lib/intercept.js @@ -53,9 +53,9 @@ let allowNetConnect * nock.enableNetConnect(/(google|amazon)/); */ function enableNetConnect(matcher) { - if (_.isString(matcher)) { + if (typeof matcher === 'string') { allowNetConnect = new RegExp(matcher) - } else if (_.isObject(matcher) && _.isFunction(matcher.test)) { + } else if (matcher instanceof RegExp) { allowNetConnect = matcher } else { allowNetConnect = /.*/ @@ -174,7 +174,7 @@ function interceptorsFor(options) { matchingInterceptor = [ { options: { allowUnmocked: true }, - matchAddress() { + matchOrigin() { return false }, }, @@ -389,13 +389,12 @@ function activate() { const interceptors = interceptorsFor(options) if (isOn() && interceptors) { - const matches = !!_.find(interceptors, function(interceptor) { - return interceptor.matchAddress(options) - }) - - const allowUnmocked = !!_.find(interceptors, function(interceptor) { - return interceptor.options.allowUnmocked - }) + const matches = interceptors.some(interceptor => + interceptor.matchOrigin(options) + ) + const allowUnmocked = interceptors.some( + interceptor => interceptor.options.allowUnmocked + ) if (!matches && allowUnmocked) { let req diff --git a/lib/interceptor.js b/lib/interceptor.js index a7ca885aa..e4c33afcd 100644 --- a/lib/interceptor.js +++ b/lib/interceptor.js @@ -104,7 +104,7 @@ module.exports = class Interceptor { reply(statusCode, body, rawHeaders) { // support the format of only passing in a callback - if (_.isFunction(statusCode)) { + if (typeof statusCode === 'function') { if (arguments.length > 1) { // It's not very Javascript-y to throw an error for extra args to a function, but because // of legacy behavior, this error was added to reduce confusion for those migrating. @@ -120,7 +120,7 @@ module.exports = class Interceptor { } this.statusCode = statusCode || 200 - if (_.isFunction(body)) { + if (typeof body === 'function') { this.replyFunction = body body = null } @@ -207,7 +207,7 @@ module.exports = class Interceptor { } if (reqHeader !== undefined && header !== undefined) { - if (_.isFunction(reqHeader)) { + if (typeof reqHeader === 'function') { return reqHeader(header) } else if (common.matchStringOrRegexp(header, reqHeader)) { return true @@ -346,9 +346,9 @@ module.exports = class Interceptor { * Return true when the interceptor's method, protocol, host, port, and path * match the provided options. */ - matchAddress(options) { - const isRegex = _.isRegExp(this.path) - const isRegexBasePath = _.isRegExp(this.scope.basePath) + matchOrigin(options) { + const isRegex = this.path instanceof RegExp + const isRegexBasePath = this.scope.basePath instanceof RegExp const method = (options.method || 'GET').toUpperCase() let { path } = options @@ -389,7 +389,7 @@ module.exports = class Interceptor { debug('Interceptor queries: %j', this.queries) debug(' Request queries: %j', reqQueries) - if (_.isFunction(this.queries)) { + if (typeof this.queries === 'function') { return this.queries(reqQueries) } @@ -450,7 +450,7 @@ module.exports = class Interceptor { return this } - if (_.isFunction(queries)) { + if (typeof queries === 'function') { this.queries = queries return this } @@ -547,7 +547,7 @@ module.exports = class Interceptor { if (_.isNumber(opts)) { headDelay = opts bodyDelay = 0 - } else if (_.isObject(opts)) { + } else if (typeof opts === 'object') { headDelay = opts.head || 0 bodyDelay = opts.body || 0 } else { diff --git a/lib/match_body.js b/lib/match_body.js index 3b915ce68..2819c4049 100644 --- a/lib/match_body.js +++ b/lib/match_body.js @@ -59,12 +59,7 @@ module.exports = function matchBody(options, spec, body) { // Because the nature of URL encoding, all the values in the body have been cast to strings. // dataEqual does strict checking so we we have to cast the non-regexp values in the spec too. if (isUrlencoded) { - spec = mapValuesDeep(spec, function(val) { - if (_.isRegExp(val)) { - return val - } - return `${val}` - }) + spec = mapValuesDeep(spec, val => (val instanceof RegExp ? val : `${val}`)) } return common.dataEqual(spec, body) @@ -76,14 +71,10 @@ module.exports = function matchBody(options, spec, body) { */ function mapValuesDeep(obj, cb) { if (Array.isArray(obj)) { - return obj.map(function(v) { - return mapValuesDeep(v, cb) - }) + return obj.map(v => mapValuesDeep(v, cb)) } if (_.isPlainObject(obj)) { - return _.mapValues(obj, function(v) { - return mapValuesDeep(v, cb) - }) + return _.mapValues(obj, v => mapValuesDeep(v, cb)) } return cb(obj) } diff --git a/lib/playback_interceptor.js b/lib/playback_interceptor.js index 105dc3919..b2c555561 100644 --- a/lib/playback_interceptor.js +++ b/lib/playback_interceptor.js @@ -4,7 +4,6 @@ const util = require('util') const timers = require('timers') const zlib = require('zlib') const debug = require('debug')('nock.playback_interceptor') -const _ = require('lodash') const common = require('./common') const DelayedBody = require('./delayed_body') @@ -101,7 +100,7 @@ function playbackInterceptor({ interceptor.markConsumed() let error - if (_.isObject(interceptor.errorMessage)) { + if (typeof interceptor.errorMessage === 'object') { error = interceptor.errorMessage } else { error = new Error(interceptor.errorMessage) From 32b1cfa3619f7d85bf788213d9d066c646e0389f Mon Sep 17 00:00:00 2001 From: Paul Melnikow Date: Sat, 26 Oct 2019 11:42:01 -0400 Subject: [PATCH 2/3] =?UTF-8?q?`typeof=20foo=20=3D=3D=3D=20=E2=80=98functi?= =?UTF-8?q?on=E2=80=99`=20->=20`foo=20instanceof=20Function`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/back.js | 6 +++--- lib/common.js | 6 +++--- lib/intercept.js | 1 - lib/intercepted_request_router.js | 8 ++++---- lib/interceptor.js | 14 +++++++------- lib/match_body.js | 4 ++-- lib/playback_interceptor.js | 2 +- lib/recorder.js | 4 ++-- 8 files changed, 22 insertions(+), 23 deletions(-) diff --git a/lib/back.js b/lib/back.js index 288576f99..1c401915c 100644 --- a/lib/back.js +++ b/lib/back.js @@ -69,7 +69,7 @@ function Back(fixtureName, options, nockedFn) { } else if (arguments.length === 2) { // If 2nd parameter is a function then `options` has been omitted // otherwise `options` haven't been omitted but `nockedFn` was. - if (typeof options === 'function') { + if (options instanceof Function) { nockedFn = options options = {} } @@ -87,7 +87,7 @@ function Back(fixtureName, options, nockedFn) { debug('context:', context) // If nockedFn is a function then invoke it, otherwise return a promise resolving to nockDone. - if (typeof nockedFn === 'function') { + if (nockedFn instanceof Function) { nockedFn.call(context, nockDone) } else { return Promise.resolve({ nockDone, context }) @@ -168,7 +168,7 @@ const record = { if (context.isRecording) { let outputs = recorder.outputs() - if (typeof options.afterRecord === 'function') { + if (options.afterRecord instanceof Function) { outputs = options.afterRecord(outputs) } diff --git a/lib/common.js b/lib/common.js index 17c7ab544..8b4158bf4 100644 --- a/lib/common.js +++ b/lib/common.js @@ -314,7 +314,7 @@ const noDuplicatesHeaders = new Set([ */ function addHeaderLine(headers, name, value) { let values // code below expects `values` to be an array of strings - if (typeof value === 'function') { + if (value instanceof Function) { // Function values are evaluated towards the end of the response, before that we use a placeholder // string just to designate that the header exists. Useful when `Content-Type` is set with a function. values = [value.name] @@ -473,7 +473,7 @@ function isStream(obj) { obj && typeof obj !== 'string' && !Buffer.isBuffer(obj) && - typeof obj.setEncoding === 'function' + obj.setEncoding instanceof Function ) } @@ -497,7 +497,7 @@ function normalizeClientRequestArgs(input, options, cb) { input = null } - if (typeof options === 'function') { + if (options instanceof Function) { cb = options options = input || {} } else { diff --git a/lib/intercept.js b/lib/intercept.js index 93181175a..00dd7fa58 100644 --- a/lib/intercept.js +++ b/lib/intercept.js @@ -8,7 +8,6 @@ const { InterceptedRequestRouter } = require('./intercepted_request_router') const common = require('./common') const { inherits } = require('util') const http = require('http') -const _ = require('lodash') const debug = require('debug')('nock.intercept') const globalEmitter = require('./global_emitter') diff --git a/lib/intercepted_request_router.js b/lib/intercepted_request_router.js index 784db577a..825f16b22 100644 --- a/lib/intercepted_request_router.js +++ b/lib/intercepted_request_router.js @@ -113,7 +113,7 @@ class InterceptedRequestRouter { } this.requestBodyBuffers.push(buffer) } - if (typeof callback === 'function') { + if (callback instanceof Function) { callback() } } else { @@ -131,17 +131,17 @@ class InterceptedRequestRouter { debug('req.end') const { req } = this - if (typeof chunk === 'function') { + if (chunk instanceof Function) { callback = chunk chunk = null - } else if (typeof encoding === 'function') { + } else if (encoding instanceof Function) { callback = encoding encoding = null } if (!req.aborted && !this.playbackStarted) { req.write(chunk, encoding, () => { - if (typeof callback === 'function') { + if (callback instanceof Function) { callback() } this.startPlayback() diff --git a/lib/interceptor.js b/lib/interceptor.js index 4db8368a4..a1a865287 100644 --- a/lib/interceptor.js +++ b/lib/interceptor.js @@ -110,7 +110,7 @@ module.exports = class Interceptor { reply(statusCode, body, rawHeaders) { // support the format of only passing in a callback - if (typeof statusCode === 'function') { + if (statusCode instanceof Function) { if (arguments.length > 1) { // It's not very Javascript-y to throw an error for extra args to a function, but because // of legacy behavior, this error was added to reduce confusion for those migrating. @@ -126,7 +126,7 @@ module.exports = class Interceptor { } this.statusCode = statusCode || 200 - if (typeof body === 'function') { + if (body instanceof Function) { this.replyFunction = body body = null } @@ -213,7 +213,7 @@ module.exports = class Interceptor { } if (reqHeader !== undefined && header !== undefined) { - if (typeof reqHeader === 'function') { + if (reqHeader instanceof Function) { return reqHeader(header) } else if (common.matchStringOrRegexp(header, reqHeader)) { return true @@ -248,7 +248,7 @@ module.exports = class Interceptor { const requestMatchesFilter = ({ name, value: predicate }) => { const headerValue = req.getHeader(name) - if (typeof predicate === 'function') { + if (predicate instanceof Function) { return predicate(headerValue) } else { return common.matchStringOrRegexp(headerValue, predicate) @@ -315,7 +315,7 @@ module.exports = class Interceptor { matchKey = common.normalizeOrigin(proto, options.host, options.port) } - if (typeof this.uri === 'function') { + if (this.uri instanceof Function) { matches = common.matchStringOrRegexp(matchKey, this.basePath) && // This is a false positive, as `uri` is not bound to `this`. @@ -395,7 +395,7 @@ module.exports = class Interceptor { debug('Interceptor queries: %j', this.queries) debug(' Request queries: %j', reqQueries) - if (typeof this.queries === 'function') { + if (this.queries instanceof Function) { return this.queries(reqQueries) } @@ -456,7 +456,7 @@ module.exports = class Interceptor { return this } - if (typeof queries === 'function') { + if (queries instanceof Function) { this.queries = queries return this } diff --git a/lib/match_body.js b/lib/match_body.js index 6eda62dd5..84753d008 100644 --- a/lib/match_body.js +++ b/lib/match_body.js @@ -26,7 +26,7 @@ module.exports = function matchBody(options, spec, body) { // try to transform body to json let json - if (typeof spec === 'object' || typeof spec === 'function') { + if (typeof spec === 'object' || spec instanceof Function) { try { json = JSON.parse(body) } catch (err) { @@ -39,7 +39,7 @@ module.exports = function matchBody(options, spec, body) { } } - if (typeof spec === 'function') { + if (spec instanceof Function) { return spec.call(options, body) } diff --git a/lib/playback_interceptor.js b/lib/playback_interceptor.js index 10d77fe71..b1df24c8f 100644 --- a/lib/playback_interceptor.js +++ b/lib/playback_interceptor.js @@ -270,7 +270,7 @@ function playbackInterceptor({ // Evaluate functional headers. common.forEachHeader(response.rawHeaders, (value, fieldName, i) => { - if (typeof value === 'function') { + if (value instanceof Function) { response.rawHeaders[i + 1] = value(req, response, responseBody) } }) diff --git a/lib/recorder.js b/lib/recorder.js index f5cf28e2d..ec961a982 100644 --- a/lib/recorder.js +++ b/lib/recorder.js @@ -344,10 +344,10 @@ function record(recOptions) { const oldEnd = req.end req.end = function(chunk, encoding, callback) { debug('req.end') - if (typeof chunk === 'function') { + if (chunk instanceof Function) { callback = chunk chunk = null - } else if (typeof encoding === 'function') { + } else if (encoding instanceof Function) { callback = encoding encoding = null } From 8e2d42047cba6dbf7d7234e945f79c65eab55b08 Mon Sep 17 00:00:00 2001 From: Paul Melnikow Date: Sat, 26 Oct 2019 11:47:59 -0400 Subject: [PATCH 3/3] Defer dropping partial support of String constructor to next breaking change --- lib/back.js | 4 +++- lib/common.js | 9 ++++++--- lib/intercept.js | 4 +++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/back.js b/lib/back.js index 1c401915c..a0e4467d7 100644 --- a/lib/back.js +++ b/lib/back.js @@ -1,5 +1,6 @@ 'use strict' +const _ = require('lodash') const recorder = require('./recorder') const { activate, @@ -60,7 +61,8 @@ function Back(fixtureName, options, nockedFn) { ) } - if (typeof fixtureName !== 'string') { + // TODO-12.x: Replace with `typeof fixtureName === 'string'`. + if (!_.isString(fixtureName)) { throw new Error('Parameter fixtureName must be a string') } diff --git a/lib/common.js b/lib/common.js index 8b4158bf4..995a06239 100644 --- a/lib/common.js +++ b/lib/common.js @@ -170,7 +170,8 @@ function stringifyRequest(options, body) { function isContentEncoded(headers) { const contentEncoding = headers['content-encoding'] - return typeof contentEncoding === 'string' && contentEncoding !== '' + // TODO-12.x: Replace with `typeof contentEncoding === 'string'`. + return _.isString(contentEncoding) && contentEncoding !== '' } function contentEncoding(headers, encoder) { @@ -359,7 +360,8 @@ function deleteHeadersField(headers, fieldNameToDelete) { throw Error('headers must be an object') } - if (typeof fieldNameToDelete !== 'string') { + // TODO-12.x: Replace with `typeof fieldNameToDelete !== 'string'`. + if (!_.isString(fieldNameToDelete)) { throw Error('field name must be a string') } @@ -440,7 +442,8 @@ function formatQueryValue(key, value, stringFormattingFn) { case value === undefined: value = '' break - case typeof value === 'string': + // TODO-12.x: Replace with `typeof value === 'string'`. + case _.isString(value): if (stringFormattingFn) { value = stringFormattingFn(value) } diff --git a/lib/intercept.js b/lib/intercept.js index 00dd7fa58..cc2cd7dfe 100644 --- a/lib/intercept.js +++ b/lib/intercept.js @@ -8,6 +8,7 @@ const { InterceptedRequestRouter } = require('./intercepted_request_router') const common = require('./common') const { inherits } = require('util') const http = require('http') +const _ = require('lodash') const debug = require('debug')('nock.intercept') const globalEmitter = require('./global_emitter') @@ -51,7 +52,8 @@ let allowNetConnect * nock.enableNetConnect(/(google|amazon)/); */ function enableNetConnect(matcher) { - if (typeof matcher === 'string') { + // TODO-12.x: Replace with `typeof matcher === 'string'`. + if (_.isString(matcher)) { allowNetConnect = new RegExp(matcher) } else if (matcher instanceof RegExp) { allowNetConnect = matcher