Skip to content

Commit c20c8ce

Browse files
committed
chore(deps): update eslint to v10, unicorn to v68, switch to eslint-plugin-import-x
The eslint 9->10 and unicorn 65->68 bumps turn on a large set of new recommended rules. The newly-firing ones are deactivated in the config with per-rule counts, grouped by intent (autofixable follow-up, needs-audit, never-activate), so this bump stays free of production source churn; enabling them is left to follow-ups. Some deactivated rules may surface real bugs (unicorn/no-duplicate-logical-operands, no-duplicate-if-branches, no-loop-iterable-mutation, and the core no-unassigned-vars); their config comments flag them for a focused audit. Changes the bump requires directly: 1. Port the repo's custom eslint rules to the v10 context API; context.getSourceCode() was removed in favour of context.sourceCode. 2. eslint 10 drops Node.js 18, so .nvmrc moves to 22. 3. Rename getRunInChildContextSubtype and drop an unnecessary String.raw to satisfy the two rules kept on (consistent-compound-words, prefer-string-raw). 4. Remove stale unicorn/no-array-for-each disable directives; the rule was renamed to no-for-each, which is deactivated here.
1 parent 29cb4d1 commit c20c8ce

13 files changed

Lines changed: 405 additions & 942 deletions

File tree

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
18
1+
22

eslint-rules/eslint-prefer-assert-match.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export default {
4747
},
4848

4949
create (context) {
50-
const sourceCode = context.getSourceCode()
50+
const sourceCode = context.sourceCode
5151

5252
return {
5353
CallExpression (node) {

eslint-rules/eslint-require-boolean-assert-message.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ export default {
106106

107107
if (isTrivialExpression(firstArg)) return
108108

109-
const sourceCode = context.getSourceCode()
109+
const sourceCode = context.sourceCode
110110
const fixMessage = buildAutofixMessage(firstArg, sourceCode)
111111

112112
context.report({

eslint-rules/eslint-safe-typeof-object.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export default {
2323
) {
2424
// Get the expression being checked (x or x.y)
2525
const targetNode = node.left.argument
26-
const targetExpression = context.getSourceCode().getText(targetNode)
26+
const targetExpression = context.sourceCode.getText(targetNode)
2727

2828
const hasNullCheck = isGuardedInLogicalExpression(node, targetNode) ||
2929
isGuardedInConditionalExpression(node, targetNode) ||
@@ -384,7 +384,7 @@ function isGuardedByIfStatement (node, targetNode) {
384384
}
385385

386386
function walkAst (context, node, visitor) {
387-
const visitorKeys = context.getSourceCode().visitorKeys
387+
const visitorKeys = context.sourceCode.visitorKeys
388388

389389
/** @type {unknown[]} */
390390
const stack = [node]

eslint.config.mjs

Lines changed: 90 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { readFileSync } from 'fs'
66
import eslintPluginJs from '@eslint/js'
77
import eslintPluginStylistic from '@stylistic/eslint-plugin'
88
import eslintPluginCypress from 'eslint-plugin-cypress'
9-
import eslintPluginImport from 'eslint-plugin-import'
9+
import eslintPluginImport from 'eslint-plugin-import-x'
1010
import eslintPluginJSDoc from 'eslint-plugin-jsdoc'
1111
import eslintPluginMocha from 'eslint-plugin-mocha'
1212
import eslintPluginN from 'eslint-plugin-n'
@@ -265,7 +265,7 @@ export default [
265265
'import/no-self-import': 'error',
266266
'import/order': ['error', {
267267
// `dd-trace` must be allowed first (and is often intentionally required before any other module).
268-
// eslint-plugin-import defaults can exclude some import types (notably `builtin`) from `pathGroups`,
268+
// eslint-plugin-import-x defaults can exclude some import types (notably `builtin`) from `pathGroups`,
269269
// which would make the `dd-trace` exception below a no-op. Make this explicit.
270270
pathGroupsExcludedImportTypes: [],
271271
pathGroups: [
@@ -324,6 +324,9 @@ export default [
324324
'no-sequences': 'error',
325325
'no-template-curly-in-string': 'error',
326326
'no-throw-literal': 'error',
327+
// Surfaces pre-existing latent bugs (always-undefined vars in tests/intake helpers)
328+
// unrelated to this tooling bump; worth a focused follow-up.
329+
'no-unassigned-vars': 'off',
327330
'no-undef-init': 'error',
328331
'no-unmodified-loop-condition': 'error',
329332
'no-unneeded-ternary': ['error', { defaultAssignment: false }],
@@ -353,6 +356,8 @@ export default [
353356
'prefer-const': ['error', { destructuring: 'all' }],
354357
'prefer-promise-reject-errors': 'error',
355358
'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }],
359+
// Newly enabled by the ESLint 10 bump; deferred with no-unassigned-vars above.
360+
'preserve-caught-error': 'off',
356361
'promise/param-names': 'error',
357362
'symbol-description': 'error',
358363
'unicode-bom': ['error', 'never'],
@@ -580,42 +585,120 @@ export default [
580585

581586
...eslintPluginUnicorn.configs.recommended.rules,
582587

583-
// Overriding recommended unicorn rules
588+
// Overriding recommended unicorn rules.
589+
// Rules not listed here are left at the `recommended` default. The v65→v68 bump
590+
// turned ~130 rules on in `recommended`; the entries below are the ones that fire
591+
// on our source and are intentionally kept off (counts are from the v68 run).
584592
'unicorn/catch-error-name': ['off', { name: 'err' }], // Many errors
585593
'unicorn/expiring-todo-comments': 'off',
586-
'unicorn/filename-case': ['off', { case: 'kebabCase' }], // // Many errors
594+
'unicorn/filename-case': ['off', { case: 'kebabCase' }], // Many errors
595+
'unicorn/name-replacements': 'off', // Many errors | naming churn (split out of prevent-abbreviations)
587596
'unicorn/prevent-abbreviations': 'off', // Many errors
588597

589598
// These rules require a newer Node.js version than we support
590599
'unicorn/no-array-reverse': 'off', // Node.js 20
591600
'unicorn/no-array-sort': 'off', // Node.js 20
601+
'unicorn/prefer-dispose': 'off', // Explicit resource management (newer Node.js)
602+
'unicorn/prefer-iterator-to-array': 'off', // Iterator helpers (Node.js 22)
603+
'unicorn/prefer-iterator-to-array-at-end': 'off', // Iterator helpers (Node.js 22)
604+
'unicorn/prefer-promise-with-resolvers': 'off', // 6 errors | Promise.withResolvers (Node.js 22)
605+
'unicorn/prefer-temporal': 'off', // Temporal is not stable on supported Node.js
606+
'unicorn/prefer-uint8array-base64': 'off', // Uint8Array base64 (Node.js 22)
592607

593-
// These rules could potentially evaluated again at a much later point
608+
// These rules could potentially be evaluated again at a much later point
609+
'unicorn/class-reference-in-static-methods': 'off', // 6 errors
610+
'unicorn/consistent-class-member-order': 'off', // 55 errors | ordering churn
611+
'unicorn/consistent-conditional-object-spread': 'off', // 3 errors
612+
'unicorn/consistent-optional-chaining': 'off', // 3 errors
594613
'unicorn/explicit-length-check': 'off', // Not a big advantage
614+
'unicorn/explicit-timer-delay': 'off', // Covered by our own timer lint rules
595615
'unicorn/no-array-callback-reference': 'off',
616+
'unicorn/no-computed-property-existence-check': 'off', // 160 errors | needs an audit
617+
'unicorn/no-declarations-before-early-exit': 'off', // 62 errors
618+
'unicorn/no-duplicate-if-branches': 'off', // 1 error | may surface real bugs
619+
'unicorn/no-duplicate-logical-operands': 'off', // 2 errors | may surface real bugs
620+
'unicorn/no-error-property-assignment': 'off', // 6 errors
596621
'unicorn/no-for-loop': 'off', // Activate if this is resolved https://github.com/sindresorhus/eslint-plugin-unicorn/issues/2664
622+
'unicorn/no-incorrect-template-string-interpolation': 'off', // 3 errors | audit for real bugs first
623+
'unicorn/no-invalid-argument-count': 'off', // 98 errors | high false-positive risk, worth a focused pass
624+
'unicorn/no-loop-iterable-mutation': 'off', // 2 errors | may surface real bugs
625+
'unicorn/no-nonstandard-builtin-properties': 'off', // 34 errors | needs an audit
597626
'unicorn/no-this-assignment': 'off', // This would need some further refactoring and the benefit is small
627+
'unicorn/no-undeclared-class-members': 'off', // 272 errors | requires declaring every field
628+
'unicorn/no-unreadable-array-destructuring': 'off', // 4 errors | not autofixable, needs manual rewrite
629+
'unicorn/no-unreadable-for-of-expression': 'off', // 32 errors
630+
'unicorn/no-unreadable-object-destructuring': 'off', // 57 errors
631+
'unicorn/no-unsafe-string-replacement': 'off', // 6 errors
632+
'unicorn/no-useless-recursion': 'off', // 2 errors
598633
'unicorn/prefer-code-point': 'off', // Should be activated, but needs a refactor of some code
599-
'unicorn/prefer-queue-microtask': 'off', // No advantage for us
634+
'unicorn/prefer-early-return': 'off', // 67 errors | tension with our positive-`if` style
635+
'unicorn/prefer-hoisting-branch-code': 'off', // 2 errors | reshapes branch bodies
636+
'unicorn/prefer-minimal-ternary': 'off', // 24 errors
637+
'unicorn/prefer-number-is-safe-integer': 'off', // 17 errors
638+
'unicorn/prefer-object-iterable-methods': 'off', // 56 errors
639+
'unicorn/prefer-queue-microtask': 'off', // process.nextTick semantics differ
640+
'unicorn/prefer-smaller-scope': 'off', // 3 errors
641+
'unicorn/prefer-split-limit': 'off', // 23 errors
642+
'unicorn/require-array-sort-compare': 'off', // 8 errors | may surface real default-sort bugs
600643

601644
// The following rules should not be activated!
645+
'unicorn/consistent-boolean-name': 'off', // Would rename public API and config booleans
602646
'unicorn/import-style': 'off', // Questionable benefit
647+
'unicorn/max-nested-calls': 'off', // Questionable benefit
603648
'unicorn/no-array-reduce': 'off', // Questionable benefit
604-
'unicorn/no-hex-escape': 'off', // Questionable benefit
649+
'unicorn/no-array-splice': 'off', // toSpliced copies the whole array (perf)
650+
'unicorn/no-break-in-nested-loop': 'off', // Conflicts with our performance-oriented loops
651+
'unicorn/no-global-object-property-assignment': 'off', // We use globalThis[Symbol.for('dd-trace')]
605652
'unicorn/no-nested-ternary': 'off', // Not really an issue in the code and the benefit is small
606653
'unicorn/no-new-array': 'off', // new Array is often used for performance reasons
607654
'unicorn/no-null': 'off', // We do not control external APIs and it is hard to differentiate these
655+
'unicorn/no-return-array-push': 'off', // Questionable benefit
608656
'unicorn/no-this-outside-of-class': 'off', // This will not work for us
657+
'unicorn/no-top-level-assignment-in-function': 'off', // Module-level singletons are assigned from functions
658+
'unicorn/no-useless-else': 'off', // Covered by core no-else-return
659+
'unicorn/operator-assignment': 'off', // Covered by core operator-assignment
660+
'unicorn/prefer-array-last-methods': 'off', // Questionable benefit
661+
'unicorn/prefer-await': 'off', // We avoid async/await in production hot paths
609662
'unicorn/prefer-event-target': 'off', // Benefit only outside of Node.js
610663
'unicorn/prefer-global-this': 'off', // Questionable benefit in Node.js alone
611664
'unicorn/prefer-includes-over-repeated-comparisons': 'off', // Bad for performance
612665
'unicorn/prefer-math-trunc': 'off', // Math.trunc is not a 1-to-1 replacement for most of our usage
613666
'unicorn/prefer-module': 'off', // We use CJS
614667
'unicorn/prefer-node-protocol': 'off', // May not be used due to guardrails
668+
'unicorn/prefer-number-coercion': 'off', // Number() is not a 1-to-1 replacement for parseInt/parseFloat
669+
'unicorn/prefer-private-class-fields': 'off', // Many `_underscore` fields cross module boundaries
615670
'unicorn/prefer-reflect-apply': 'off', // Questionable benefit and more than 500 matches
671+
'unicorn/prefer-short-arrow-method': 'off', // Method shorthand is intentional; arrow properties change `this`
616672
'unicorn/prefer-switch': 'off', // Questionable benefit
617673
'unicorn/prefer-top-level-await': 'off', // Only useful when using ESM
674+
'unicorn/prefer-unicode-code-point-escapes': 'off', // Replaces the dropped no-hex-escape; questionable benefit
618675
'unicorn/switch-case-braces': 'off', // Questionable benefit
676+
677+
// Safe to enable in a follow-up: autofixable and aligned with our style. Kept off
678+
// here only to keep this version bump free of source churn (counts from the v68 run).
679+
'unicorn/logical-assignment-operators': 'off', // 42 errors | matches our ??=/||= usage
680+
'unicorn/no-for-each': 'off', // 10 errors | we already prefer for-of in production
681+
'unicorn/no-negated-array-predicate': 'off', // 2 errors
682+
'unicorn/no-negated-comparison': 'off', // 1 error
683+
'unicorn/no-subtraction-comparison': 'off', // 2 errors
684+
'unicorn/no-unnecessary-boolean-comparison': 'off', // 6 errors
685+
'unicorn/no-unnecessary-global-this': 'off', // 4 errors
686+
'unicorn/no-unnecessary-splice': 'off', // 2 errors
687+
'unicorn/no-useless-concat': 'off', // 4 errors
688+
'unicorn/no-useless-continue': 'off', // 1 error
689+
'unicorn/no-useless-delete-check': 'off', // 1 error
690+
'unicorn/no-useless-fallback-in-spread': 'off', // 5 errors
691+
'unicorn/no-useless-override': 'off', // 1 error
692+
'unicorn/no-useless-template-literals': 'off', // 13 errors
693+
'unicorn/prefer-array-from-map': 'off', // 6 errors
694+
'unicorn/prefer-boolean-return': 'off', // 1 error
695+
'unicorn/prefer-continue': 'off', // 52 errors
696+
'unicorn/prefer-direct-iteration': 'off', // 5 errors
697+
'unicorn/prefer-else-if': 'off', // 6 errors
698+
'unicorn/prefer-global-number-constants': 'off', // 3 errors
699+
'unicorn/prefer-logical-operator-over-ternary': 'off', // 3 errors
700+
'unicorn/prefer-ternary': 'off', // 16 errors
701+
'unicorn/prefer-unary-minus': 'off', // 1 error
619702
},
620703
},
621704
{

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@
182182
"@actions/github": "^9.1.1",
183183
"@babel/helpers": "^8.0.0",
184184
"@eslint/eslintrc": "^3.3.5",
185-
"@eslint/js": "^9.39.2",
185+
"@eslint/js": "^10.0.1",
186186
"@msgpack/msgpack": "^3.1.3",
187187
"@openfeature/core": "^1.11.0",
188188
"@openfeature/server-sdk": "~1.22.0",
@@ -196,15 +196,15 @@
196196
"bun": "1.3.14",
197197
"codeowners-audit": "^2.9.0",
198198
"editorconfig-checker": "^6.1.1",
199-
"eslint": "^9.39.2",
199+
"eslint": "^10.5.0",
200200
"eslint-plugin-cypress": "^6.4.1",
201-
"eslint-plugin-import": "^2.32.0",
201+
"eslint-plugin-import-x": "^4.16.2",
202202
"eslint-plugin-jsdoc": "^63.0.5",
203203
"eslint-plugin-mocha": "^11.3.0",
204204
"eslint-plugin-n": "^18.1.0",
205205
"eslint-plugin-promise": "^7.3.0",
206206
"eslint-plugin-sonarjs": "^4.0.3",
207-
"eslint-plugin-unicorn": "^65.0.1",
207+
"eslint-plugin-unicorn": "^68.0.0",
208208
"express": "^5.1.0",
209209
"glob": "^10.4.5",
210210
"globals": "^17.2.0",

packages/datadog-instrumentations/src/mocha/main.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,6 @@ addHook({
546546

547547
const runner = run.apply(this, args)
548548

549-
// eslint-disable-next-line unicorn/no-array-for-each
550549
this.files.forEach((path) => {
551550
const isUnskippable = isMarkedAsUnskippable({ path })
552551
if (isUnskippable) {
@@ -899,7 +898,6 @@ addHook({
899898
status = 'skip'
900899
} else {
901900
// has to check every test in the test file
902-
// eslint-disable-next-line unicorn/no-array-for-each
903901
suitesInTestFile.forEach(suite => {
904902
suite.eachTest(test => {
905903
if (test.state === 'failed' || test.timedOut) {

packages/datadog-instrumentations/src/mocha/utils.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,6 @@ function getSuitesByTestFile (root) {
226226
suitesByTestFile[suite.file] = [suite]
227227
}
228228
}
229-
// eslint-disable-next-line unicorn/no-array-for-each
230229
suite.suites.forEach(suite => {
231230
getSuites(suite)
232231
})
@@ -817,7 +816,6 @@ function getOnPendingHandler () {
817816
function getRunTestsWrapper (runTests, config) {
818817
return function (suite) {
819818
if (config.isTestManagementTestsEnabled) {
820-
// eslint-disable-next-line unicorn/no-array-for-each
821819
suite.tests.forEach((test) => {
822820
const { isAttemptToFix, isDisabled, isQuarantined } = getTestProperties(test, config.testManagementTests)
823821
if (isAttemptToFix && !test.isPending()) {
@@ -841,7 +839,6 @@ function getRunTestsWrapper (runTests, config) {
841839
}
842840

843841
if (config.isImpactedTestsEnabled) {
844-
// eslint-disable-next-line unicorn/no-array-for-each
845842
suite.tests.forEach((test) => {
846843
isModifiedCh.publish({
847844
modifiedFiles: config.modifiedFiles,
@@ -865,7 +862,6 @@ function getRunTestsWrapper (runTests, config) {
865862

866863
if (config.isKnownTestsEnabled) {
867864
// by the time we reach `this.on('test')`, it is too late. We need to add retries here
868-
// eslint-disable-next-line unicorn/no-array-for-each
869865
suite.tests.forEach((test) => {
870866
if (!test.isPending() && isNewTest(test, config.knownTests)) {
871867
test._ddIsNew = true

packages/datadog-instrumentations/src/vitest.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -770,10 +770,8 @@ function threadHandler (thread) {
770770
function wrapTinyPoolRun (TinyPool) {
771771
shimmer.wrap(TinyPool.prototype, 'run', run => async function () {
772772
// We have to do this before and after because the threads list gets recycled, that is, the processes are re-created
773-
// eslint-disable-next-line unicorn/no-array-for-each
774773
this.threads.forEach(threadHandler)
775774
const runResult = await run.apply(this, arguments)
776-
// eslint-disable-next-line unicorn/no-array-for-each
777775
this.threads.forEach(threadHandler)
778776
return runResult
779777
})

packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class RunInChildContextPlugin extends BaseContextPlugin {
8585
static spanName = 'aws.durable.child_context'
8686

8787
bindStart (ctx) {
88-
if (SUPPRESSED_CHILD_CONTEXT_SUBTYPES.has(getRunInChildContextSubType(ctx))) {
88+
if (SUPPRESSED_CHILD_CONTEXT_SUBTYPES.has(getRunInChildContextSubtype(ctx))) {
8989
// Pass the active store through unchanged so any nested spans
9090
// remain parented to the surrounding map/parallel span
9191
ctx.suppressed = true
@@ -96,7 +96,7 @@ class RunInChildContextPlugin extends BaseContextPlugin {
9696
}
9797

9898
// runInChildContext has two overloads: `(name, fn, options)` and `(fn, options)`.
99-
function getRunInChildContextSubType (ctx) {
99+
function getRunInChildContextSubtype (ctx) {
100100
const args = ctx.arguments || []
101101
const opts = typeof args[0] === 'function' ? args[1] : args[2]
102102
return opts?.subType

0 commit comments

Comments
 (0)