import js from "@eslint/js"; import eslintConfigPrettier from "eslint-config-prettier"; import tseslint from "typescript-eslint"; import turboPlugin from "eslint-plugin-turbo"; import boundaries from "eslint-plugin-boundaries"; import globals from "globals"; import conformancePlugin from "./plugin.js"; import path from "node:path"; import { fileURLToPath } from "node:url"; // const __dirname = path.dirname(fileURLToPath(import.meta.url)); const repoRoot = path.resolve(__dirname, "..", ".."); export default [ { ignores: [ "dist/**", "node_modules/**", ".next/**", ".turbo/**", "storybook-static/**", ], }, js.configs.recommended, { files: ["**/*.{mjs,cjs,js}", "**/*.config.{ts,tsx}"], languageOptions: { globals: { ...globals.node }, }, }, ...tseslint.configs.recommended, eslintConfigPrettier, { plugins: { turbo: turboPlugin }, rules: { "turbo/no-undeclared-env-vars": "warn", }, }, { plugins: { conformance: conformancePlugin }, rules: { // Structural conformance rules (milestone iii.a). // All 5 features now have manifests; promoted to ERROR. "conformance/feature-must-have-manifest": ["error", { repoRoot }], "conformance/usecase-must-have-test-file": "error", "conformance/required-cores-installed": ["error", { repoRoot }], "conformance/no-undeclared-event-publish": ["warn", { repoRoot }], "conformance/no-undeclared-audit": ["warn", { repoRoot }], "conformance/usecase-must-be-wired": ["error", { repoRoot }], "conformance/component-must-have-story": "warn", "conformance/component-must-have-test": "warn", "conformance/atomic-tier-import-direction": "warn", }, }, { rules: { // Honour the leading-underscore convention for intentionally-unused params/vars. "@typescript-eslint/no-unused-vars": [ "error", { argsIgnorePattern: "^_", varsIgnorePattern: "^_", caughtErrorsIgnorePattern: "^_", }, ], }, }, { plugins: { boundaries }, settings: { "boundaries/elements": [ { type: "app", pattern: "apps/*" }, { type: "tooling", pattern: "packages/core-eslint" }, { type: "tooling", pattern: "packages/core-typescript" }, { type: "tooling", pattern: "packages/core-testing" }, { type: "core-composition", pattern: "packages/core-api" }, { type: "core-composition", pattern: "packages/core-cms" }, { type: "core", pattern: "packages/core-*" }, { type: "feature", pattern: "packages/!(core-*)" }, ], }, rules: { "boundaries/element-types": [ 2, { default: "disallow", rules: [ { from: "app", allow: ["app", "core", "core-composition", "feature", "tooling"], }, { from: "feature", allow: ["core", "tooling"] }, { from: "core", allow: ["core", "tooling"] }, { from: "core-composition", allow: ["core", "feature", "tooling"] }, { from: "tooling", allow: ["tooling"] }, ], }, ], }, }, // Block direct @sentry/* imports outside the allowlisted instrumentation paths. { files: ["**/*.{ts,tsx,mjs,cjs,js}"], rules: { "no-restricted-imports": [ "error", { patterns: [ { group: ["@sentry/*"], message: "Import from @repo/core-shared/instrumentation instead — feature packages must not depend on Sentry directly.", }, ], }, ], }, }, // Allowlist — the only paths permitted to import @sentry/*. // Per ADR-017, server-side Sentry SDK usage is limited to the OTel bridge // and browser/client init files. Patterns are double-star prefixed so they // match whether eslint runs from the repo root or from inside a sub-package. { files: [ // OTel bridge — the only server-side file that may import @sentry/opentelemetry "**/instrumentation/otel/sentry-bridge.{ts,js}", "**/instrumentation/otel/sentry-bridge.test.{ts,js}", // OTel DI binder — may import @sentry/opentelemetry via sentry-bridge "**/instrumentation/di/bind-otel-instrumentation.{ts,js}", "**/instrumentation/di/bind-otel-instrumentation.test.{ts,js}", // Browser-side Sentry init helpers (server-only migration — browser keeps Sentry SDK directly) "**/instrumentation/sentry/init-client.{ts,js}", "**/instrumentation/sentry/init-client.test.{ts,js}", "**/instrumentation/sentry/init-client-react.{ts,js}", "**/instrumentation/sentry/init-client-react.test.{ts,js}", // Server-side Sentry SDK init still used by apps (calls Sentry.init with DSN) "**/instrumentation/sentry/init-server.{ts,js}", "**/instrumentation/sentry/init-server.test.{ts,js}", "**/instrumentation/sentry/init-server-node.{ts,js}", "**/instrumentation/sentry/init-server-node.test.{ts,js}", // Test guard — mocks Sentry + OTel SDKs to prevent real init in test processes "**/setup/no-instrumentation.{ts,js}", "**/setup/no-instrumentation.test.{ts,js}", // Legacy alias for one release cycle "**/setup/no-sentry.{ts,js}", "**/setup/no-sentry.test.{ts,js}", // App-level instrumentation entry points and build config "**/instrumentation.{ts,js,mjs}", "**/instrumentation-client.{ts,js,mjs}", "**/next.config.{mjs,ts,js}", "**/vite.config.{ts,mjs,js}", "**/sentry.*.config.{ts,mjs,js}", ], rules: { "no-restricted-imports": "off", }, }, // OTel SDK packages (@opentelemetry/sdk-*, @opentelemetry/resources, // @opentelemetry/semantic-conventions, @opentelemetry/instrumentation-*, // @sentry/opentelemetry) are restricted to core-shared/instrumentation/otel/ // and app-level init paths. // The vendor-neutral API packages (@opentelemetry/api, @opentelemetry/api-logs) // are unrestricted within core-shared/instrumentation/ — features use them for // advanced tracing without coupling to the SDK. { files: [ "**/instrumentation/otel/**/*.{ts,tsx,mjs,cjs,js}", // App-level init and build config also allowed to import OTel SDK packages "**/instrumentation.{ts,js,mjs}", "**/next.config.{mjs,ts,js}", "**/vite.config.{ts,mjs,js}", ], rules: { "no-restricted-imports": "off", }, }, // E1 — Event handlers must not be re-exported. Wire them only inside the // consumer feature's bind-production / bind-dev-seed (spec § 2.2 Rule E1). // J — Direct `payload.jobs.*` access is forbidden outside the integration // layer. Use IJobQueue (from @repo/core-shared/jobs) instead. // Events + jobs rules are added here when @repo/core-events is scaffolded // via `pnpm turbo gen core-package events`. // // R2 / R1 (ADR-016) — realtime-specific ESLint rules (no-direct-socket-io, // no-realtime-handler-reexport) are added here when @repo/core-realtime is // scaffolded via `pnpm turbo gen core-package realtime`. // ];