diff --git a/bin/test-naming-rules.js b/bin/test-naming-rules.js index d55747f908..1aee5361bf 100755 --- a/bin/test-naming-rules.js +++ b/bin/test-naming-rules.js @@ -1,4 +1,4 @@ -#! /usr/bin/env node +#!/usr/bin/env node /* * Copyright 2020 New Relic Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 diff --git a/bin/utils.js b/bin/utils.js index 58ee8e570b..83c8bd20e8 100644 --- a/bin/utils.js +++ b/bin/utils.js @@ -1,4 +1,3 @@ -#! /usr/bin/env node /* * Copyright 2020 New Relic Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 diff --git a/eslint.config.js b/eslint.config.js index 6c24c76dc3..02a33964ba 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -12,6 +12,20 @@ const header = require('./eslint-plugin-newrelic-header.js') // The new eslint configuration format is a simple array of configuration // objects. See https://eslint.org/docs/latest/use/configure/configuration-files#configuration-objects. +// +// While working on the config, it can be helpful to run: +// npx @eslint/config-inspector + +// This should be used to override rules we don't need applied to our +// test suites. +const testFiles = [ + 'test/benchmark/**', + 'test/integration/**', + 'test/unit/**', + 'test/smoke/**', + 'test/versioned/**', + 'bin/test/**' +] // See https://eslint.org/docs/latest/use/configure/ignore#ignoring-files const globalIgnores = { @@ -66,13 +80,7 @@ const newrelicConfigOverrides = { } const sonarjsTestsConfig = { - files: [ - 'test/benchmark/**', - 'test/integration/**', - 'test/unit/**', - 'test/smoke/**', - 'test/versioned/**', - ], + files: testFiles, rules: { // We sometimes need to shadow things like Promise for testing: @@ -157,6 +165,12 @@ const jsdocOverrides = { } } +const nodeRecommended = neostandard.plugins.n.configs['flat/recommended'] +delete nodeRecommended.languageOptions.sourceType +nodeRecommended.rules['n/no-unsupported-features/node-builtins'] = ['error', { version: '>=18.8.0' }] +nodeRecommended.rules['n/no-process-exit'] = 'off' +nodeRecommended.ignores = testFiles + // Configuration objects are merged in order. That is, the last object in the // list will merge with objects earlier in the list. This allows for overriding // any settings by adding objects to the end of the list. @@ -177,6 +191,17 @@ module.exports = [ jsdocConfig, jsdocOverrides, + // Add customized eslint-plugin-n recommended rules: + nodeRecommended, + { + files: [ + 'bin/*.js' + ], + rules: { + 'n/hashbang': 'off' + } + }, + // Apply local configuration and overrides: localConfig, newrelicConfigOverrides, diff --git a/lib/instrumentation/aws-sdk/v3/common.js b/lib/instrumentation/aws-sdk/v3/common.js index 53e4be08b9..cc6dbaedb8 100644 --- a/lib/instrumentation/aws-sdk/v3/common.js +++ b/lib/instrumentation/aws-sdk/v3/common.js @@ -34,9 +34,7 @@ function headerMiddleware(shim, config, next) { * @param {Shim} shim * @param {Object} config AWS command configuration * @param {function} next next function in middleware chain - * @param {Object} contxt AWS command context - * cons - * @param context + * @param {Object} context AWS command context * @returns {function} */ function attrMiddleware(shim, config, next, context) { @@ -46,12 +44,10 @@ function attrMiddleware(shim, config, next, context) { region = await config.region() } catch (err) { shim.logger.debug(err, 'Failed to get the AWS region') - } finally { - const result = await next(args) - addAwsAttributes({ result, config, region, shim, context }) - // eslint-disable-next-line no-unsafe-finally - return result } + const result = await next(args) + addAwsAttributes({ result, config, region, shim, context }) + return result } } diff --git a/lib/instrumentation/core/http-outbound.js b/lib/instrumentation/core/http-outbound.js index 2cf58c81fa..24d93acee6 100644 --- a/lib/instrumentation/core/http-outbound.js +++ b/lib/instrumentation/core/http-outbound.js @@ -68,6 +68,7 @@ function getDefaultHostName(opts) { */ function parseOpts(opts) { if (typeof opts === 'string') { + // eslint-disable-next-line n/no-deprecated-api opts = url.parse(opts) } else { opts = copy.shallow(opts) diff --git a/lib/instrumentation/core/http.js b/lib/instrumentation/core/http.js index d18d3e3187..456eee1759 100644 --- a/lib/instrumentation/core/http.js +++ b/lib/instrumentation/core/http.js @@ -74,6 +74,7 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) { tracer.bindEmitter(response, segment) // the error tracer needs a URL for tracing, even though naming overwrites + // eslint-disable-next-line n/no-deprecated-api transaction.parsedUrl = url.parse(request.url, true) transaction.url = urltils.obfuscatePath(agent.config, transaction.parsedUrl.pathname) transaction.verb = request.method @@ -411,6 +412,7 @@ function wrapRequest(agent, request) { const transaction = agent.tracer.getTransaction() if (!transaction || internalOnly) { if (!internalOnly && logger.traceEnabled()) { + // eslint-disable-next-line n/no-deprecated-api const logOpts = typeof options === 'string' ? url.parse(options) : options logger.trace( 'No transaction, not recording external to %s:%s', diff --git a/lib/instrumentation/undici.js b/lib/instrumentation/undici.js index d6c0418939..fca5d17bb7 100644 --- a/lib/instrumentation/undici.js +++ b/lib/instrumentation/undici.js @@ -10,7 +10,9 @@ const recordExternal = require('../metrics/recorders/http_external') const logger = require('../logger').child({ component: 'undici' }) const NAMES = require('../metrics/names') const symbols = require('../symbols') +// eslint-disable-next-line n/no-unsupported-features/node-builtins const { executionAsyncResource } = require('async_hooks') +// eslint-disable-next-line n/no-unsupported-features/node-builtins const diagnosticsChannel = require('diagnostics_channel') const synthetics = require('../synthetics') const urltils = require('../util/urltils') diff --git a/lib/transaction/index.js b/lib/transaction/index.js index a12f395d64..ccb1df0aba 100644 --- a/lib/transaction/index.js +++ b/lib/transaction/index.js @@ -657,6 +657,7 @@ Transaction.prototype.getScrubbedUrl = function getScrubbedUrl() { if (!this.url) { return } + // eslint-disable-next-line n/no-deprecated-api this.parsedUrl = url.parse(this.url) } diff --git a/lib/util/urltils.js b/lib/util/urltils.js index d19c4d4732..dbf8044844 100644 --- a/lib/util/urltils.js +++ b/lib/util/urltils.js @@ -88,6 +88,7 @@ module.exports = { */ scrub: function scrub(requestURL) { if (typeof requestURL === 'string') { + // eslint-disable-next-line n/no-deprecated-api requestURL = url.parse(requestURL) } @@ -123,6 +124,7 @@ module.exports = { let parsed = requestURL if (typeof requestURL === 'string') { + // eslint-disable-next-line n/no-deprecated-api parsed = url.parse(requestURL, true) } @@ -154,6 +156,7 @@ module.exports = { */ scrubAndParseParameters: function scrubAndParseParameters(requestURL) { if (typeof requestURL === 'string') { + // eslint-disable-next-line n/no-deprecated-api requestURL = url.parse(requestURL, true) } return { diff --git a/lib/utilization/common.js b/lib/utilization/common.js index b5721fa9b7..57c464d2a3 100644 --- a/lib/utilization/common.js +++ b/lib/utilization/common.js @@ -60,6 +60,7 @@ exports.request = function request(opts, agent, cb) { // Add default timeout of a second to the request if (typeof opts === 'string') { + // eslint-disable-next-line n/no-deprecated-api opts = url.parse(opts) } diff --git a/test/lib/promise-resolvers.js b/test/lib/promise-resolvers.js index ea43a6aff3..f7fefd096b 100644 --- a/test/lib/promise-resolvers.js +++ b/test/lib/promise-resolvers.js @@ -13,10 +13,15 @@ * @returns {{resolve, reject, promise: Promise}} */ module.exports = function promiseResolvers() { + // We are disabling this lint rule because it complains about + // `withResolvers` not being available until Node 22. We know that. + // We are doing feature detection. + /* eslint-disable n/no-unsupported-features/es-syntax */ if (typeof Promise.withResolvers === 'function') { // Node.js >=22 natively supports this. return Promise.withResolvers() } + /* eslint-enable n/no-unsupported-features/es-syntax */ let resolve let reject