From 6b088df9c6f1260ddff5ff36798d1c398b537ade Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Wed, 19 Jun 2024 15:11:47 +0000 Subject: [PATCH 1/4] eslint: add rule: no-unreachable Also delete tests which have not been enabled since 2017. --- .eslintrc | 3 ++- .../pg/test/integration/client/ssl-tests.js | 21 ------------------- .../pg/test/unit/client/simple-query-tests.js | 12 ----------- 3 files changed, 2 insertions(+), 34 deletions(-) delete mode 100644 packages/pg/test/integration/client/ssl-tests.js diff --git a/.eslintrc b/.eslintrc index fd9bb8ddc..3ea313b51 100644 --- a/.eslintrc +++ b/.eslintrc @@ -16,6 +16,7 @@ "@typescript-eslint/no-unused-vars": ["error", { "args": "none" }], - "no-unused-vars": "off" + "no-unused-vars": "off", + "no-unreachable": "error" } } diff --git a/packages/pg/test/integration/client/ssl-tests.js b/packages/pg/test/integration/client/ssl-tests.js deleted file mode 100644 index 97aa59492..000000000 --- a/packages/pg/test/integration/client/ssl-tests.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict' -var pg = require('../../../lib') -var config = require('./test-helper').config -test('can connect with ssl', function () { - return false - config.ssl = { - rejectUnauthorized: false, - } - pg.connect( - config, - assert.success(function (client) { - return false - client.query( - 'SELECT NOW()', - assert.success(function () { - pg.end() - }) - ) - }) - ) -}) diff --git a/packages/pg/test/unit/client/simple-query-tests.js b/packages/pg/test/unit/client/simple-query-tests.js index 2c3ea5e4e..d7a893a1f 100644 --- a/packages/pg/test/unit/client/simple-query-tests.js +++ b/packages/pg/test/unit/client/simple-query-tests.js @@ -109,18 +109,6 @@ test('executing query', function () { text: 'INSERT 31 1', }) }) - - test('removes itself after another readyForQuery message', function () { - return false - assert.emits(query, 'end', function (msg) { - // TODO do we want to check the complete messages? - }) - con.emit('readyForQuery') - // this would never actually happen - ;['dataRow', 'rowDescription', 'commandComplete'].forEach(function (msg) { - assert.equal(con.emit(msg), false, "Should no longer be picking up '" + msg + "' messages") - }) - }) }) test('handles errors', function () { From f3d4eca36150cea27e6c8298d5f721d99d096c25 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Thu, 20 Feb 2025 07:40:44 +0000 Subject: [PATCH 2/4] re-introduce removed file --- .../pg/test/integration/client/ssl-tests.js | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 packages/pg/test/integration/client/ssl-tests.js diff --git a/packages/pg/test/integration/client/ssl-tests.js b/packages/pg/test/integration/client/ssl-tests.js new file mode 100644 index 000000000..bece48f2f --- /dev/null +++ b/packages/pg/test/integration/client/ssl-tests.js @@ -0,0 +1,24 @@ +'use strict' +const helper = require('./test-helper') +const assert = require('assert') +const suite = new helper.Suite() + +suite.test('can connect with ssl', function () { + const config = { + ...helper.config, + ssl: { + rejectUnauthorized: false, + }, + } + const client = new helper.pg.Client(config) + client.connect( + assert.success(function () { + client.query( + 'SELECT NOW()', + assert.success(function () { + client.end() + }) + ) + }) + ) +}) From e1b9fe687123b3a9c3ddca40d0743db993dc4eb7 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Thu, 20 Feb 2025 07:42:00 +0000 Subject: [PATCH 3/4] re-intro test --- packages/pg/test/unit/client/simple-query-tests.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/pg/test/unit/client/simple-query-tests.js b/packages/pg/test/unit/client/simple-query-tests.js index c27ae26ac..3fecc1435 100644 --- a/packages/pg/test/unit/client/simple-query-tests.js +++ b/packages/pg/test/unit/client/simple-query-tests.js @@ -112,6 +112,10 @@ test('executing query', function () { text: 'INSERT 31 1', }) }) + + test('removes itself after another readyForQuery message', function () { + return false + }) }) test('handles errors', function () { From 08fe7f652f82f571a1a641519ffbcedbeff9a5e0 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Sun, 6 Apr 2025 14:52:08 +0000 Subject: [PATCH 4/4] add eslint:recommended; fix violations --- .eslintrc | 15 +++++++++---- packages/pg-cloudflare/src/index.ts | 1 + packages/pg-connection-string/index.js | 2 +- packages/pg-native/index.js | 6 ++++-- packages/pg-pool/test/idle-timeout-exit.js | 1 - packages/pg-protocol/src/buffer-reader.ts | 1 + .../pg-protocol/src/inbound-parser.test.ts | 8 ------- packages/pg-protocol/src/parser.ts | 21 ++++++++++--------- packages/pg-query-stream/test/error.ts | 4 ++-- packages/pg/bench.js | 8 +++---- packages/pg/lib/crypto/cert-signatures.js | 21 ++++++++++--------- packages/pg/lib/native/client.js | 1 + packages/pg/lib/stream.js | 8 +++++-- .../client/big-simple-query-tests.js | 2 +- .../test/integration/gh-issues/3174-tests.js | 1 + .../pg/test/unit/client/sasl-scram-tests.js | 2 +- .../environment-variable-tests.js | 4 ++-- 17 files changed, 57 insertions(+), 49 deletions(-) diff --git a/.eslintrc b/.eslintrc index 3ea313b51..742dfac20 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,15 +1,14 @@ { "plugins": ["@typescript-eslint", "prettier"], "parser": "@typescript-eslint/parser", - "extends": ["plugin:prettier/recommended", "prettier"], + "extends": ["eslint:recommended", "plugin:prettier/recommended", "prettier"], "ignorePatterns": ["node_modules", "coverage", "packages/pg-protocol/dist/**/*", "packages/pg-query-stream/dist/**/*"], "parserOptions": { - "ecmaVersion": 2017, "sourceType": "module" }, "env": { "node": true, - "es6": true, + "es2020": true, "mocha": true }, "rules": { @@ -18,5 +17,13 @@ }], "no-unused-vars": "off", "no-unreachable": "error" - } + }, + "overrides": [ + { + "files": ["*.ts", "*.mts", "*.cts", "*.tsx"], + "rules": { + "no-undef": "off" + } + } + ] } diff --git a/packages/pg-cloudflare/src/index.ts b/packages/pg-cloudflare/src/index.ts index 98dfc3570..6de7e7888 100644 --- a/packages/pg-cloudflare/src/index.ts +++ b/packages/pg-cloudflare/src/index.ts @@ -61,6 +61,7 @@ export class CloudflareSocket extends EventEmitter { } async _listen() { + // eslint-disable-next-line no-constant-condition while (true) { log('awaiting receive from CF socket') const { done, value } = await this._cfReader!.read() diff --git a/packages/pg-connection-string/index.js b/packages/pg-connection-string/index.js index c7fc72a36..746e66e73 100644 --- a/packages/pg-connection-string/index.js +++ b/packages/pg-connection-string/index.js @@ -19,7 +19,7 @@ function parse(str) { let dummyHost = false if (/ |%[^a-f0-9]|%[a-f0-9][^a-f0-9]/i.test(str)) { // Ensure spaces are encoded as %20 - str = encodeURI(str).replace(/\%25(\d\d)/g, '%$1') + str = encodeURI(str).replace(/%25(\d\d)/g, '%$1') } try { diff --git a/packages/pg-native/index.js b/packages/pg-native/index.js index a3c3f070b..2dd9b992f 100644 --- a/packages/pg-native/index.js +++ b/packages/pg-native/index.js @@ -183,8 +183,10 @@ Client.prototype._emitResult = function (pq) { case 'PGRES_TUPLES_OK': case 'PGRES_COMMAND_OK': case 'PGRES_EMPTY_QUERY': - const result = this._consumeQueryResults(this.pq) - this.emit('result', result) + { + const result = this._consumeQueryResults(this.pq) + this.emit('result', result) + } break case 'PGRES_COPY_OUT': diff --git a/packages/pg-pool/test/idle-timeout-exit.js b/packages/pg-pool/test/idle-timeout-exit.js index dbfccf392..7304bcff1 100644 --- a/packages/pg-pool/test/idle-timeout-exit.js +++ b/packages/pg-pool/test/idle-timeout-exit.js @@ -11,7 +11,6 @@ if (module === require.main) { pool.query('SELECT NOW()', (err, res) => console.log('completed first')) pool.on('remove', () => { console.log('removed') - done() }) setTimeout(() => { diff --git a/packages/pg-protocol/src/buffer-reader.ts b/packages/pg-protocol/src/buffer-reader.ts index a1b30b875..62b16a2ed 100644 --- a/packages/pg-protocol/src/buffer-reader.ts +++ b/packages/pg-protocol/src/buffer-reader.ts @@ -46,6 +46,7 @@ export class BufferReader { public cstring(): string { const start = this.offset let end = start + // eslint-disable-next-line no-empty while (this.buffer[end++] !== 0) {} this.offset = end return this.buffer.toString(this.encoding, start, end - 1) diff --git a/packages/pg-protocol/src/inbound-parser.test.ts b/packages/pg-protocol/src/inbound-parser.test.ts index 345d1ca8a..d518d348b 100644 --- a/packages/pg-protocol/src/inbound-parser.test.ts +++ b/packages/pg-protocol/src/inbound-parser.test.ts @@ -50,16 +50,8 @@ var rowWithBigOids = { } var bigOidDescBuff = buffers.rowDescription([rowWithBigOids]) -var emptyRowFieldBuf = new BufferList().addInt16(0).join(true, 'D') - var emptyRowFieldBuf = buffers.dataRow([]) -var oneFieldBuf = new BufferList() - .addInt16(1) // number of fields - .addInt32(5) // length of bytes of fields - .addCString('test') - .join(true, 'D') - var oneFieldBuf = buffers.dataRow(['test']) var expectedAuthenticationOkayMessage = { diff --git a/packages/pg-protocol/src/parser.ts b/packages/pg-protocol/src/parser.ts index 3b901aefe..f7313f235 100644 --- a/packages/pg-protocol/src/parser.ts +++ b/packages/pg-protocol/src/parser.ts @@ -328,16 +328,17 @@ export class Parser { } break case 10: // AuthenticationSASL - message.name = 'authenticationSASL' - message.mechanisms = [] - let mechanism: string - do { - mechanism = this.reader.cstring() - - if (mechanism) { - message.mechanisms.push(mechanism) - } - } while (mechanism) + { + message.name = 'authenticationSASL' + message.mechanisms = [] + let mechanism: string + do { + mechanism = this.reader.cstring() + if (mechanism) { + message.mechanisms.push(mechanism) + } + } while (mechanism) + } break case 11: // AuthenticationSASLContinue message.name = 'authenticationSASLContinue' diff --git a/packages/pg-query-stream/test/error.ts b/packages/pg-query-stream/test/error.ts index 9f1d136cf..8ddb4da7d 100644 --- a/packages/pg-query-stream/test/error.ts +++ b/packages/pg-query-stream/test/error.ts @@ -75,7 +75,7 @@ describe('error recovery', () => { const client = new Client() const stmt = 'SELECT * FROM goose;' await client.connect() - return new Promise(async (resolve) => { + return new Promise((resolve) => { let queryError: Error | undefined client.query(stmt).catch((e) => { queryError = e @@ -86,7 +86,7 @@ describe('error recovery', () => { assert(queryError, 'query should have errored due to client ending') resolve() }) - await client.end() + client.end() }) }) diff --git a/packages/pg/bench.js b/packages/pg/bench.js index 8f966c581..7fbd4e2a4 100644 --- a/packages/pg/bench.js +++ b/packages/pg/bench.js @@ -25,13 +25,11 @@ const exec = async (client, q) => { const bench = async (client, q, time) => { let start = Date.now() let count = 0 - while (true) { + do { await exec(client, q) count++ - if (Date.now() - start > time) { - return count - } - } + } while (Date.now() - start > time) + return count } const run = async () => { diff --git a/packages/pg/lib/crypto/cert-signatures.js b/packages/pg/lib/crypto/cert-signatures.js index 3497d963a..da1182bdc 100644 --- a/packages/pg/lib/crypto/cert-signatures.js +++ b/packages/pg/lib/crypto/cert-signatures.js @@ -1,5 +1,5 @@ function x509Error(msg, cert) { - throw new Error('SASL channel binding: ' + msg + ' when parsing public certificate ' + cert.toString('base64')) + return new Error('SASL channel binding: ' + msg + ' when parsing public certificate ' + cert.toString('base64')) } function readASN1Length(data, index) { @@ -7,7 +7,7 @@ function readASN1Length(data, index) { if (length < 0x80) return { length, index } const lengthBytes = length & 0x7f - if (lengthBytes > 4) x509Error('bad length', data) + if (lengthBytes > 4) throw x509Error('bad length', data) length = 0 for (let i = 0; i < lengthBytes; i++) { @@ -18,11 +18,11 @@ function readASN1Length(data, index) { } function readASN1OID(data, index) { - if (data[index++] !== 0x6) x509Error('non-OID data', data) // 6 = OID + if (data[index++] !== 0x6) throw x509Error('non-OID data', data) // 6 = OID const { length: OIDLength, index: indexAfterOIDLength } = readASN1Length(data, index) index = indexAfterOIDLength - lastIndex = index + OIDLength + let lastIndex = index + OIDLength const byte1 = data[index++] let oid = ((byte1 / 40) >> 0) + '.' + (byte1 % 40) @@ -43,7 +43,7 @@ function readASN1OID(data, index) { } function expectASN1Seq(data, index) { - if (data[index++] !== 0x30) x509Error('non-sequence data', data) // 30 = Sequence + if (data[index++] !== 0x30) throw x509Error('non-sequence data', data) // 30 = Sequence return readASN1Length(data, index) } @@ -85,10 +85,10 @@ function signatureAlgorithmHashFromCertificate(data, index) { case '1.2.840.10045.4.3.4': return 'SHA-512' // RSASSA-PSS: hash is indicated separately - case '1.2.840.113549.1.1.10': + case '1.2.840.113549.1.1.10': { index = indexAfterOID index = expectASN1Seq(data, index).index - if (data[index++] !== 0xa0) x509Error('non-tag data', data) // a0 = constructed tag 0 + if (data[index++] !== 0xa0) throw x509Error('non-tag data', data) // a0 = constructed tag 0 index = readASN1Length(data, index).index // skip over tag length field index = expectASN1Seq(data, index).index // skip over sequence length field const { oid: hashOID } = readASN1OID(data, index) @@ -105,7 +105,8 @@ function signatureAlgorithmHashFromCertificate(data, index) { case '2.16.840.1.101.3.4.2.3': return 'SHA-512' } - x509Error('unknown hash OID ' + hashOID, data) + throw x509Error('unknown hash OID ' + hashOID, data) + } // Ed25519 -- see https: return//github.com/openssl/openssl/issues/15477 case '1.3.101.110': case '1.3.101.112': // ph @@ -113,9 +114,9 @@ function signatureAlgorithmHashFromCertificate(data, index) { // Ed448 -- still not in pg 17.2 (if supported, digest would be SHAKE256 x 64 bytes) case '1.3.101.111': case '1.3.101.113': // ph - x509Error('Ed448 certificate channel binding is not currently supported by Postgres') + throw x509Error('Ed448 certificate channel binding is not currently supported by Postgres') } - x509Error('unknown OID ' + oid, data) + throw x509Error('unknown OID ' + oid, data) } module.exports = { signatureAlgorithmHashFromCertificate } diff --git a/packages/pg/lib/native/client.js b/packages/pg/lib/native/client.js index 6494375f1..d45d08ffc 100644 --- a/packages/pg/lib/native/client.js +++ b/packages/pg/lib/native/client.js @@ -2,6 +2,7 @@ // eslint-disable-next-line var Native +// eslint-disable-next-line no-useless-catch try { // Wrap this `require()` in a try-catch to avoid upstream bundlers from complaining that this might not be available since it is an optional import Native = require('pg-native') diff --git a/packages/pg/lib/stream.js b/packages/pg/lib/stream.js index cb0839878..5de353462 100644 --- a/packages/pg/lib/stream.js +++ b/packages/pg/lib/stream.js @@ -60,8 +60,12 @@ function getCloudflareStreamFuncs() { function isCloudflareRuntime() { // Since 2022-03-21 the `global_navigator` compatibility flag is on for Cloudflare Workers // which means that `navigator.userAgent` will be defined. - if (typeof navigator === 'object' && navigator !== null && typeof navigator.userAgent === 'string') { - return navigator.userAgent === 'Cloudflare-Workers' + if ( + typeof globalThis.navigator === 'object' && + globalThis.navigator !== null && + typeof globalThis.navigator.userAgent === 'string' + ) { + return globalThis.navigator.userAgent === 'Cloudflare-Workers' } // In case `navigator` or `navigator.userAgent` is not defined then try a more sneaky approach if (typeof Response === 'function') { diff --git a/packages/pg/test/integration/client/big-simple-query-tests.js b/packages/pg/test/integration/client/big-simple-query-tests.js index a7e6770e8..d751a0bd7 100644 --- a/packages/pg/test/integration/client/big-simple-query-tests.js +++ b/packages/pg/test/integration/client/big-simple-query-tests.js @@ -99,7 +99,7 @@ var runBigQuery = function (client) { function (err, result) { if (err != null) { console.log(err) - throw Err + throw err } assert.lengthIs(result.rows, 26) } diff --git a/packages/pg/test/integration/gh-issues/3174-tests.js b/packages/pg/test/integration/gh-issues/3174-tests.js index 49ac5905a..9949c8071 100644 --- a/packages/pg/test/integration/gh-issues/3174-tests.js +++ b/packages/pg/test/integration/gh-issues/3174-tests.js @@ -60,6 +60,7 @@ const startMockServer = (port, badBuffer, callback) => { setImmediate(() => { socket.write(badBuffer) }) + break default: // console.log('got code', code) } diff --git a/packages/pg/test/unit/client/sasl-scram-tests.js b/packages/pg/test/unit/client/sasl-scram-tests.js index ba9b9304b..9aa4a4f26 100644 --- a/packages/pg/test/unit/client/sasl-scram-tests.js +++ b/packages/pg/test/unit/client/sasl-scram-tests.js @@ -225,7 +225,7 @@ suite.test('sasl/scram', function () { 0x0d, // signature algorithm length 0x06, // ASN.1 OID 0x09, // OID length - 0x2a, // OID: 1.2.840.113549.1.1.11 (RSASSA-PKCS1-v1_5 / SHA-256​) + 0x2a, // OID: 1.2.840.113549.1.1.11 (RSASSA-PKCS1-v1_5 / SHA-256) 0x86, 0x48, 0x86, diff --git a/packages/pg/test/unit/connection-parameters/environment-variable-tests.js b/packages/pg/test/unit/connection-parameters/environment-variable-tests.js index e4e08ebd5..43f484038 100644 --- a/packages/pg/test/unit/connection-parameters/environment-variable-tests.js +++ b/packages/pg/test/unit/connection-parameters/environment-variable-tests.js @@ -7,7 +7,7 @@ var defaults = require('../../../lib').defaults // clear process.env var realEnv = {} -for (var key in process.env) { +for (const key in process.env) { realEnv[key] = process.env[key] delete process.env[key] } @@ -122,6 +122,6 @@ testVal('verify-full', true) testVal('no-verify', { rejectUnauthorized: false }) // restore process.env -for (var key in realEnv) { +for (const key in realEnv) { process.env[key] = realEnv[key] }