From fb90ce71262e5b9940d18bfef5acf12c63dab6a2 Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Wed, 30 Jul 2025 22:08:52 +0300 Subject: [PATCH] chore: add eslint rule for implicit dependencies npm hoists transitive dependencies to the top level node_modules, from where they are easy to inadvertedly use. Also we may accidentally remove dependencies that are actually used via this implicit mechanism. This adds an ESLint rule to catch implicit deps. --- eslint.config.js | 27 ++++++++++++++++++++++++--- package.json | 1 + 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index 201ce9d58..7a8969769 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -5,6 +5,7 @@ const tseslint = require('typescript-eslint') const prettier = require('eslint-config-prettier/flat') const react = require('eslint-plugin-react') const chai = require('eslint-plugin-chai-friendly') +const importPlugin = require('eslint-plugin-import') module.exports = defineConfig([ globalIgnores(['**/public', '**/dist']), @@ -13,9 +14,15 @@ module.exports = defineConfig([ { files: ['**/*.ts'], extends: [common('@typescript-eslint/'), tseslint.configs.recommended], + plugins: { + import: importPlugin + }, languageOptions: { parser: tseslint.parser, globals: globals.node + }, + rules: { + 'import/no-extraneous-dependencies': 'error' } }, @@ -23,8 +30,14 @@ module.exports = defineConfig([ { files: ['**/*.js'], extends: [common(), js.configs.recommended], + plugins: { + import: importPlugin + }, languageOptions: { globals: globals.node + }, + rules: { + 'import/no-extraneous-dependencies': 'error' } }, @@ -34,10 +47,14 @@ module.exports = defineConfig([ '{src,packages/*/src}/**/*.test.{ts,js}', '{test,packages/*/test}/**/*.{js,ts}' ], - plugins: { chai }, + plugins: { + chai, + import: importPlugin + }, rules: { 'no-unused-expressions': 'off', // disable original rule - 'chai/no-unused-expressions': 'error' + 'chai/no-unused-expressions': 'error', + 'import/no-extraneous-dependencies': ['error', { devDependencies: true }] }, languageOptions: { parser: tseslint.parser, @@ -54,6 +71,9 @@ module.exports = defineConfig([ }, files: ['packages/server-admin-ui/src/**/*.js'], extends: [common(), react.configs.flat.recommended], + plugins: { + import: importPlugin + }, languageOptions: { parserOptions: { ecmaFeatures: { @@ -67,7 +87,8 @@ module.exports = defineConfig([ rules: { 'react/prop-types': 'off', 'react/no-string-refs': 'off', - 'react/no-direct-mutation-state': 'off' + 'react/no-direct-mutation-state': 'off', + 'import/no-extraneous-dependencies': 'error' } }, diff --git a/package.json b/package.json index 9e902f01d..dc4dab982 100644 --- a/package.json +++ b/package.json @@ -158,6 +158,7 @@ "eslint": "^9.24.0", "eslint-config-prettier": "^10.1.2", "eslint-plugin-chai-friendly": "^1.0.1", + "eslint-plugin-import": "^2.32.0", "eslint-plugin-prefer-arrow": "^1.2.3", "eslint-plugin-react": "^7.37.5", "globals": "^16.0.0",