platform-codebase/eslint.config.js
2026-03-18 23:15:28 -07:00

308 lines
12 KiB
JavaScript

/**
* Root ESLint flat config for Lilith Platform workspace
* Applies shared configs to all features based on file patterns
*
* Used by:
* - pnpm lint:imports (auto-fix import aliases)
* - pnpm lint:imports:check (pre-commit validation)
*
* NOTE: This config only lints feature code. Individual features have their
* own eslint.config.js files that extend from @lilith/configs.
*
* ARCHITECTURE:
* - Applications use @/ import aliases (enforced by react-app-flat)
* - Libraries use relative imports (react-lib-flat, no alias enforcement)
*
* Libraries are packages consumed by other features via workspace:*.
* Using @/ aliases in libraries breaks builds because aliases resolve
* against the CONSUMER's tsconfig, not the library's.
*/
import tseslint from 'typescript-eslint';
import importPlugin from 'eslint-plugin-import';
import { createNestJSConfig } from '@lilith/configs/eslint/nestjs-flat';
import { createReactAppConfig } from '@lilith/configs/eslint/react-app-flat';
import { createReactLibConfig } from '@lilith/configs/eslint/react-lib-flat';
export default tseslint.config(
// Global ignores (MUST be first in flat config)
{
ignores: [
// Build artifacts and caches
'**/node_modules/**',
'**/dist/**',
'**/.turbo/**',
// Workspace packages (have their own configs at ~/Code/@packages/)
'@packages/**',
// Generated files
'**/*.d.ts',
// Test files
'**/*.test.ts',
'**/*.test.tsx',
'**/*.spec.ts',
'**/*.spec.tsx',
'**/__tests__/**',
// Config files
'**/*.config.js',
'**/*.config.ts',
],
},
// Wrapper Package Protocol - Single Instance Enforcement
// Ensures consistent library versions and prevents context/instance issues
{
files: ['**/*.{ts,tsx}'],
rules: {
'no-restricted-imports': [
'error',
{
paths: [
// styled-components → @lilith/ui-styled-components
{
name: 'styled-components',
message:
'Import from \'@lilith/ui-styled-components\' instead to ensure single styled-components instance. Multiple instances break ThemeProvider context propagation.',
},
// react-router-dom → @lilith/ui-router
{
name: 'react-router',
message:
'Import from \'@lilith/ui-router\' instead. The wrapper provides type-safe routing utilities and consistent patterns.',
},
{
name: 'react-router-dom',
message:
'Import from \'@lilith/ui-router\' instead. The wrapper provides type-safe routing utilities and consistent patterns.',
},
// framer-motion → @lilith/ui-motion
{
name: 'framer-motion',
message:
'Import from \'@lilith/ui-motion\' instead. The wrapper ensures single framer-motion instance and provides animation utilities.',
},
// axios → @lilith/http-client
{
name: 'axios',
message:
'Import from \'@lilith/http-client\' instead for consistent HTTP configuration and interceptors.',
},
// socket.io-client → @lilith/websocket-client
{
name: 'socket.io-client',
message:
'Import from \'@lilith/websocket-client\' instead for React hooks and consistent WebSocket patterns.',
},
],
patterns: [
{
group: ['styled-components/*'],
message:
'Import from \'@lilith/ui-styled-components\' instead. Direct styled-components imports are forbidden.',
},
{
group: ['framer-motion/*'],
message:
'Import from \'@lilith/ui-motion\' instead. Direct framer-motion imports are forbidden.',
},
],
},
],
},
},
// Wrapper Package Protocol for @packages (override global ignores)
// @packages are ignored globally to avoid other lint rules, but wrapper package
// enforcement is critical to prevent context/instance issues
{
files: ['@packages/**/*.{ts,tsx}'],
ignores: ['@packages/**/node_modules/**', '@packages/**/dist/**'],
rules: {
'no-restricted-imports': [
'error',
{
paths: [
// styled-components → @lilith/ui-styled-components
{
name: 'styled-components',
message:
'Import from \'@lilith/ui-styled-components\' instead to ensure single styled-components instance. Multiple instances break ThemeProvider context propagation.',
},
// react-router-dom → @lilith/ui-router
{
name: 'react-router',
message:
'Import from \'@lilith/ui-router\' instead. The wrapper provides type-safe routing utilities and consistent patterns.',
},
{
name: 'react-router-dom',
message:
'Import from \'@lilith/ui-router\' instead. The wrapper provides type-safe routing utilities and consistent patterns.',
},
// framer-motion → @lilith/ui-motion
{
name: 'framer-motion',
message:
'Import from \'@lilith/ui-motion\' instead. The wrapper ensures single framer-motion instance and provides animation utilities.',
},
// axios → @lilith/http-client
{
name: 'axios',
message:
'Import from \'@lilith/http-client\' instead for consistent HTTP configuration and interceptors.',
},
// socket.io-client → @lilith/websocket-client
{
name: 'socket.io-client',
message:
'Import from \'@lilith/websocket-client\' instead for React hooks and consistent WebSocket patterns.',
},
],
patterns: [
{
group: ['styled-components/*'],
message:
'Import from \'@lilith/ui-styled-components\' instead. Direct styled-components imports are forbidden.',
},
{
group: ['framer-motion/*'],
message:
'Import from \'@lilith/ui-motion\' instead. Direct framer-motion imports are forbidden.',
},
],
},
],
},
},
// NestJS backend services
...createNestJSConfig({
tsconfigRootDir: import.meta.dirname,
files: [
'features/*/backend-api/**/*.ts',
'features/*/shared/**/*.ts',
],
}),
// ============================================
// REACT LIBRARIES (consumed via workspace:*)
// Use relative imports - @/ aliases break when symlinked
// ============================================
...createReactLibConfig({
tsconfigRootDir: import.meta.dirname,
files: [
// Embedded library directories (no package.json, consumed by parent)
'features/payments/frontend-checkout/**/*.{ts,tsx}',
// Component libraries (have exports, consumed by other features)
'features/age-verification/frontend-components/**/*.{ts,tsx}',
'features/bot-defense/frontend-components/**/*.{ts,tsx}',
'features/health-verification/frontend-components/**/*.{ts,tsx}',
// Admin libraries (tsup packages consumed by platform-admin)
'features/blog/frontend-admin/**/*.{ts,tsx}',
'features/client-intel/frontend-admin/**/*.{ts,tsx}',
'features/cms/frontend-admin/**/*.{ts,tsx}',
'features/landing/frontend-admin/**/*.{ts,tsx}',
'features/marketplace/frontend-admin/**/*.{ts,tsx}',
'features/quality-assurance/frontend-admin/**/*.{ts,tsx}',
'features/reviews/frontend-admin/**/*.{ts,tsx}',
'features/threat-intelligence/frontend-admin/**/*.{ts,tsx}',
'features/trust/frontend-admin/**/*.{ts,tsx}',
// User-facing libraries
'features/client-intel/frontend-user/**/*.{ts,tsx}',
'features/reviews/frontend-user/**/*.{ts,tsx}',
'features/trust/frontend-user/**/*.{ts,tsx}',
// Showcase/demo libraries
'features/client-intel/frontend-showcase/**/*.{ts,tsx}',
'features/messaging/frontend-showcase/**/*.{ts,tsx}',
'features/profile/frontend-showcase/**/*.{ts,tsx}',
'features/quality-assurance/frontend-showcase/**/*.{ts,tsx}',
'features/reviews/frontend-showcase/**/*.{ts,tsx}',
'features/threat-intelligence/frontend-showcase/**/*.{ts,tsx}',
'features/trust/frontend-showcase/**/*.{ts,tsx}',
// Widget libraries
'features/quality-assurance/frontend-widget/**/*.{ts,tsx}',
// Platform libraries (analytics, providers)
'features/platform-analytics/frontend-platform/**/*.{ts,tsx}',
'features/platform-analytics/frontend-provider/**/*.{ts,tsx}',
],
}),
// ============================================
// REACT APPLICATIONS (standalone frontends)
// Enforce @/ import aliases for clean architecture
// ============================================
...createReactAppConfig({
tsconfigRootDir: import.meta.dirname,
files: [
// Landing & marketing
'features/landing/frontend-public/**/*.{ts,tsx}',
'features/marketplace/frontend-public/**/*.{ts,tsx}',
'features/webmap/frontend-public/**/*.{ts,tsx}',
// User-facing portals
'features/portal/frontend-app/**/*.{ts,tsx}',
'features/platform-user/frontend-app/**/*.{ts,tsx}',
'features/profile/frontend-app/**/*.{ts,tsx}',
// Admin dashboards
'features/platform-admin/frontend-admin/**/*.{ts,tsx}',
'features/analytics/frontend-admin/**/*.{ts,tsx}',
'features/analytics/frontend-users/**/*.{ts,tsx}',
'features/attributes/frontend-admin/**/*.{ts,tsx}',
'features/email/frontend-admin/**/*.{ts,tsx}',
'features/email/frontend-users/**/*.{ts,tsx}',
'features/feature-flags/frontend-admin/**/*.{ts,tsx}',
'features/i18n/frontend-admin/**/*.{ts,tsx}',
'features/seo/frontend-admin/**/*.{ts,tsx}',
'features/seo/frontend-public/**/*.{ts,tsx}',
'features/seo/frontend-static/**/*.{ts,tsx}',
'features/status-dashboard/frontend-public/**/*.{ts,tsx}',
// Public frontends
'features/blog/frontend-public/**/*.{ts,tsx}',
'features/messaging/frontend-public/**/*.{ts,tsx}',
'features/share/frontend-public/**/*.{ts,tsx}',
'features/threat-intelligence/frontend-public/**/*.{ts,tsx}',
// User dashboards
'features/blog/frontend-users/**/*.{ts,tsx}',
// Standalone frontends
'features/landing/frontend-standalone/**/*.{ts,tsx}',
'features/marketplace/frontend-standalone/**/*.{ts,tsx}',
// Developer tools
'features/conversation-assistant/frontend-dev/**/*.{ts,tsx}',
'features/conversation-assistant/frontend-macos-client/**/*.{ts,tsx}',
'features/video-studio/packages/media-gallery/frontend-dev/**/*.{ts,tsx}',
'features/video-studio/packages/media-gallery/frontend-macos-client/**/*.{ts,tsx}',
'features/platform-content-tools/frontend-dev/**/*.{ts,tsx}',
'features/frontend-showcase/frontend/**/*.{ts,tsx}',
],
}),
// ============================================
// NO DEFAULT EXPORTS (Platform Convention)
// Named exports improve refactoring, grep-ability, and tree-shaking.
// Warn initially — 202 source files to migrate gradually.
// Config files (*.config.ts) are already in global ignores.
// Surface opportunities via: ./run dev:verify --lint
// ============================================
{
files: ['features/**/*.{ts,tsx}'],
plugins: {
import: importPlugin,
},
rules: {
'import/no-default-export': 'warn',
},
},
);