diff --git a/eslint.config.mjs b/eslint.config.mjs index 40645ae3d9e481..3efba73e44d17d 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -15,6 +15,8 @@ import pluginQuery from '@tanstack/eslint-plugin-query'; import {globalIgnores} from 'eslint/config'; import prettier from 'eslint-config-prettier'; // @ts-expect-error TS(7016): Could not find a declaration file +import boundaries from 'eslint-plugin-boundaries'; +// @ts-expect-error TS(7016): Could not find a declaration file import importPlugin from 'eslint-plugin-import'; import jest from 'eslint-plugin-jest'; import jestDom from 'eslint-plugin-jest-dom'; @@ -976,4 +978,198 @@ export default typescript.config([ 'no-restricted-imports': 'off', }, }, + { + name: 'plugin/boundaries', + plugins: { + boundaries, + }, + settings: { + // order matters here because of nested directories + 'boundaries/elements': [ + // --- stories --- + { + type: 'story-files', + pattern: 'static/**/*.stories.{ts,tsx}', + mode: 'full', + }, + { + type: 'story-book', + pattern: 'static/app/stories', + }, + // --- tests --- + { + type: 'test-sentry', + pattern: [ + 'static/app/**/*.spec.{ts,js,tsx,jsx}', + 'tests/js/sentry-test/**/*.*', + 'static/app/**/*{t,T}estUtils*.{js,mjs,ts,tsx}', + ], + mode: 'full', + }, + { + type: 'test-getsentry', + pattern: [ + 'static/gsApp/**/*.spec.{ts,js,tsx,jsx}', + 'tests/js/getsentry-test/**/*.*', + ], + mode: 'full', + }, + { + type: 'test-gsAdmin', + pattern: ['static/gsAdmin/**/*.spec.{ts,js,tsx,jsx}'], + mode: 'full', + }, + { + type: 'test', + pattern: 'tests/js', + }, + // --- specifics --- + { + type: 'devtoolbar', + pattern: 'sentry/components/devtoolbar', + }, + { + type: 'core-button', + pattern: 'static/app/components/core/button', + }, + { + type: 'core', + pattern: 'static/app/components/core', + }, + // --- sentry --- + { + type: 'sentry-images', + pattern: 'static/images', + }, + { + type: 'sentry-locale', + pattern: '(static/app/locale.tsx|src/sentry/locale/**/*.*)', + mode: 'full', + }, + { + type: 'sentry-logos', + pattern: 'src/sentry/static/sentry/images/logos', + }, + { + type: 'sentry-fonts', + pattern: 'static/fonts', + }, + { + type: 'sentry-fixture', + pattern: 'tests/js/fixtures', + }, + { + type: 'sentry', + pattern: 'static/app', + }, + // --- getsentry --- + { + type: 'getsentry', + pattern: 'static/gsApp', + }, + // --- admin --- + { + type: 'gsAdmin', + pattern: 'static/gsAdmin', + }, + // --- configs --- + { + type: 'configs', + pattern: '(package.json|config/**/*.*|*.config.{mjs,js,ts})', + mode: 'full', + }, + { + type: 'build-utils', + pattern: 'build-utils', + }, + { + type: 'scripts', + pattern: 'scripts', + }, + ], + }, + rules: { + ...boundaries.configs.strict.rules, + 'boundaries/no-ignored': 'off', + 'boundaries/no-private': 'off', + 'boundaries/element-types': [ + 'warn', + { + default: 'disallow', + message: '${file.type} is not allowed to import ${dependency.type}', + rules: [ + { + from: ['sentry*'], + allow: ['core*', 'sentry*'], + }, + { + from: ['getsentry*'], + allow: ['core*', 'getsentry*', 'sentry*'], + }, + { + from: ['gsAdmin*'], + disallow: ['sentry-locale'], + allow: ['core*', 'gsAdmin*', 'sentry*', 'getsentry*'], + }, + { + from: ['devtoolbar'], + allow: ['devtoolbar', 'sentry*'], + }, + { + from: ['test-sentry'], + allow: ['test-sentry', 'test', 'core*', 'sentry*'], + }, + { + // todo does test-gesentry need test-sentry? + from: ['test-getsentry'], + allow: [ + 'test-getsentry', + 'test-sentry', + 'test', + 'core*', + 'getsentry*', + 'sentry*', + ], + }, + { + from: ['test-gsAdmin'], + allow: [ + 'test-gsAdmin', + 'test-getsentry', + 'test-sentry', + 'test', + 'core*', + 'gsAdmin*', + 'sentry*', + 'getsentry*', + ], + }, + { + from: ['test'], + allow: ['test', 'test-sentry', 'sentry*'], + }, + { + from: ['configs'], + allow: ['configs', 'build-utils'], + }, + // --- stories --- + { + from: ['story-files', 'story-book'], + allow: ['core*', 'sentry*', 'story-book'], + }, + // --- core --- + { + from: ['core-button'], + allow: ['core*'], + }, + // todo: sentry* shouldn't be allowed + { + from: ['core'], + allow: ['core*', 'sentry*'], + }, + ], + }, + ], + }, + }, ]); diff --git a/package.json b/package.json index 9cc58e5928e818..66b32e99201ed0 100644 --- a/package.json +++ b/package.json @@ -200,6 +200,7 @@ "eslint": "^9.22.0", "eslint-config-prettier": "^10.1.2", "eslint-import-resolver-typescript": "^3.8.3", + "eslint-plugin-boundaries": "^5.0.1", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jest": "^28.11.0", "eslint-plugin-jest-dom": "^5.5.0", diff --git a/static/app/views/explore/spans/spansTab.tsx b/static/app/views/explore/spans/spansTab.tsx index cf90057647f7d7..49767688c70222 100644 --- a/static/app/views/explore/spans/spansTab.tsx +++ b/static/app/views/explore/spans/spansTab.tsx @@ -67,7 +67,7 @@ import { } from 'sentry/views/explore/utils'; import {Onboarding} from 'sentry/views/performance/onboarding'; -// eslint-disable-next-line no-restricted-imports +// eslint-disable-next-line no-restricted-imports,boundaries/element-types import QuotaExceededAlert from 'getsentry/components/performance/quotaExceededAlert'; interface SpansTabOnboardingProps { diff --git a/yarn.lock b/yarn.lock index 6b68471cee1c44..a4cf800dea7b4a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7037,7 +7037,7 @@ eslint-config-prettier@^10.1.2: resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.1.2.tgz#31a4b393c40c4180202c27e829af43323bf85276" integrity sha512-Epgp/EofAUeEpIdZkW60MHKvPyru1ruQJxPL+WIycnaPApuseK0Zpkrh/FwL9oIpQvIhJwV7ptOy0DWUjTlCiA== -eslint-import-resolver-node@^0.3.9: +eslint-import-resolver-node@0.3.9, eslint-import-resolver-node@^0.3.9: version "0.3.9" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== @@ -7059,13 +7059,23 @@ eslint-import-resolver-typescript@^3.8.3: stable-hash "^0.0.4" tinyglobby "^0.2.12" -eslint-module-utils@^2.12.0: +eslint-module-utils@2.12.0, eslint-module-utils@^2.12.0: version "2.12.0" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz#fe4cfb948d61f49203d7b08871982b65b9af0b0b" integrity sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg== dependencies: debug "^3.2.7" +eslint-plugin-boundaries@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-boundaries/-/eslint-plugin-boundaries-5.0.1.tgz#7603c7d57c4d6ac8a7f24db4ff810dba03ddb217" + integrity sha512-QBw1TgoA3JnD+AQ8EHqZL8LtiFVREnFmD2BnHzVl38UKtRTds8rawIg03ZLwFs/90yKSh+DVVXRpvVK631Z/0w== + dependencies: + chalk "4.1.2" + eslint-import-resolver-node "0.3.9" + eslint-module-utils "2.12.0" + micromatch "4.0.8" + eslint-plugin-import@^2.31.0: version "2.31.0" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz#310ce7e720ca1d9c0bb3f69adfd1c6bdd7d9e0e7" @@ -10274,7 +10284,7 @@ micromark@^4.0.0: micromark-util-symbol "^2.0.0" micromark-util-types "^2.0.0" -micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.8: +micromatch@4.0.8, micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==