From 2b59209cf3ca816ac3271c8592143c06263873c3 Mon Sep 17 00:00:00 2001 From: Charmander <~@charmander.me> Date: Tue, 17 Dec 2019 08:02:38 -0800 Subject: [PATCH] Warn when functions intended as constructors are called without new (#2021) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Warn when pg.Pool() isn’t called as a constructor in preparation for #1541. `eval` is a bit awkward, but it’s more accurate than an `instanceof` check and will work on platforms new enough to support pg 8 (i.e. only not Node 4). * Warn when Query() isn’t called as a constructor --- lib/compat/check-constructor.js | 22 ++++++++++++++++++++++ lib/compat/warn-deprecation.js | 19 +++++++++++++++++++ lib/index.js | 4 ++++ lib/query.js | 5 ++++- 4 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 lib/compat/check-constructor.js create mode 100644 lib/compat/warn-deprecation.js diff --git a/lib/compat/check-constructor.js b/lib/compat/check-constructor.js new file mode 100644 index 000000000..5920633a0 --- /dev/null +++ b/lib/compat/check-constructor.js @@ -0,0 +1,22 @@ +'use strict' + +const warnDeprecation = require('./warn-deprecation') + +// Node 4 doesn’t support new.target. +let hasNewTarget + +try { + // eslint-disable-next-line no-eval + eval('(function () { new.target })') + hasNewTarget = true +} catch (error) { + hasNewTarget = false +} + +const checkConstructor = (name, code, getNewTarget) => { + if (hasNewTarget && getNewTarget() === undefined) { + warnDeprecation(`Constructing a ${name} without new is deprecated and will stop working in pg 8.`, code) + } +} + +module.exports = checkConstructor diff --git a/lib/compat/warn-deprecation.js b/lib/compat/warn-deprecation.js new file mode 100644 index 000000000..362183558 --- /dev/null +++ b/lib/compat/warn-deprecation.js @@ -0,0 +1,19 @@ +'use strict' + +const util = require('util') + +const dummyFunctions = new Map() + +// Node 4 doesn’t support process.emitWarning(message, 'DeprecationWarning', code). +const emitDeprecationWarning = (message, code) => { + let dummy = dummyFunctions.get(code) + + if (dummy === undefined) { + dummy = util.deprecate(() => {}, message) + dummyFunctions.set(code, dummy) + } + + dummy() +} + +module.exports = emitDeprecationWarning diff --git a/lib/index.js b/lib/index.js index 8e000a378..de33c086d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -12,9 +12,13 @@ var Client = require('./client') var defaults = require('./defaults') var Connection = require('./connection') var Pool = require('pg-pool') +const checkConstructor = require('./compat/check-constructor') const poolFactory = (Client) => { var BoundPool = function (options) { + // eslint-disable-next-line no-eval + checkConstructor('pg.Pool', 'PG-POOL-NEW', () => eval('new.target')) + var config = Object.assign({ Client: Client }, options) return new Pool(config) } diff --git a/lib/query.js b/lib/query.js index 250e8950d..548380fe1 100644 --- a/lib/query.js +++ b/lib/query.js @@ -9,12 +9,15 @@ var EventEmitter = require('events').EventEmitter var util = require('util') +const checkConstructor = require('./compat/check-constructor') var Result = require('./result') var utils = require('./utils') var Query = function (config, values, callback) { - // use of "new" optional + // use of "new" optional in pg 7 + // eslint-disable-next-line no-eval + checkConstructor('Query', 'PG-QUERY-NEW', () => eval('new.target')) if (!(this instanceof Query)) { return new Query(config, values, callback) } config = utils.normalizeQueryConfig(config, values, callback)