eslint.config.mjs
Rama dev · réplica de lectura del repositorio original.
import eslintReact from '@eslint-react/eslint-plugin'
import astroEslintParser from 'astro-eslint-parser'
import { defineConfig } from 'eslint/config'
import eslintConfigPrettier from 'eslint-config-prettier'
import eslintPluginAstro from 'eslint-plugin-astro'
import muiPathImports from 'eslint-plugin-mui-path-imports'
import noRelativeImportPaths from 'eslint-plugin-no-relative-import-paths'
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
import simpleImportSort from 'eslint-plugin-simple-import-sort'
import unusedImports from 'eslint-plugin-unused-imports'
import path from 'path'
import tseslint from 'typescript-eslint'
import noDirectContextAccess from './eslint-rules/no-direct-context-access.mjs'
import noOpaqueDestructiveFilter from './eslint-rules/no-opaque-destructive-filter.mjs'
import noTransactionEscape from './eslint-rules/no-transaction-escape.mjs'
import noUnknownApiPath from './eslint-rules/no-unknown-api-path.mjs'
import noUntypedLocalPaths from './eslint-rules/no-untyped-local-paths.mjs'
const neverkin = {
rules: {
'no-direct-context-access': noDirectContextAccess,
'no-opaque-destructive-filter': noOpaqueDestructiveFilter,
'no-transaction-escape': noTransactionEscape,
'no-unknown-api-path': noUnknownApiPath,
'no-untyped-local-paths': noUntypedLocalPaths,
},
}
export default defineConfig(
{
ignores: [
'app/calliope-websockets/dist',
'app/rhea-backend/dist',
'app/rhea-backend/prisma',
'app/styx-frontend/build',
'app/orpheus-mcp/dist',
'app/ts-shared/dist',
'library/tiptap-schema/dist',
'app/thetis-landing/dist',
'app/thetis-landing/.astro',
'test/e2e/dist',
'*.gen.ts',
'node_modules',
'.husky',
'app/thetis-landing/src/components/common/BasicScripts.astro',
'app/thetis-landing/src/components/common/ApplyColorMode.astro',
'library/openapi-fetch/src/rhea-api.ts',
'library/**/dist',
],
},
{
extends: [...tseslint.configs.recommended],
files: ['**/*.json'],
rules: {
'@typescript-eslint/no-unused-expressions': 'off',
},
},
{
extends: [tseslint.configs.recommended],
files: ['**/*.{mjs,js,ts,tsx}'],
plugins: {
'simple-import-sort': simpleImportSort,
'unused-imports': unusedImports,
'no-relative-import-paths': noRelativeImportPaths,
'mui-path-imports': muiPathImports,
},
rules: {
'linebreak-style': ['error', 'unix'],
'no-tabs': 'off',
'no-trailing-spaces': 'off',
'no-unused-vars': 'off',
'@typescript-eslint/no-explicit-any': 'error',
'object-curly-spacing': 'off',
'no-case-declarations': 'off',
'space-before-function-paren': 'off',
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
'unused-imports/no-unused-imports': 'error',
'mui-path-imports/mui-path-imports': 'error',
'@typescript-eslint/no-unused-vars': 'off',
'unused-imports/no-unused-vars': [
'warn',
{
vars: 'all',
varsIgnorePattern: '^_',
args: 'after-used',
argsIgnorePattern: '^_',
},
],
},
},
{
// Local paths go through the typed router
files: ['app/styx-frontend/src/**/*.{ts,tsx}'],
ignores: ['app/styx-frontend/src/api/**'],
plugins: { neverkin },
rules: {
'neverkin/no-untyped-local-paths': 'error',
},
},
{
files: ['app/styx-frontend/src/**/*.{ts,tsx}'],
rules: {
'no-relative-import-paths/no-relative-import-paths': [
'error',
{
allowSameFolder: true,
allowedDepth: 2,
rootDir: path.relative(process.cwd(), path.join(import.meta.dirname, 'app/styx-frontend/src')),
prefix: '@',
},
],
},
},
{
// Custom rules for rhea-backend to enforce moonflower patterns
files: ['app/rhea-backend/src/routers/**/*.ts'],
plugins: { neverkin },
rules: {
'neverkin/no-direct-context-access': 'warn',
},
},
{
// A destructive filter that widens to every row is silent data loss.
// Needs type information: the filter's columns are read off the checked type.
files: ['app/rhea-backend/src/**/*.ts'],
plugins: { neverkin },
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
'neverkin/no-opaque-destructive-filter': 'error',
'neverkin/no-transaction-escape': 'error',
'no-restricted-properties': [
'error',
...['$queryRaw', '$queryRawUnsafe', '$queryRawTyped', '$executeRaw', '$executeRawUnsafe'].map(
(property) => ({
property,
message: 'Raw SQL is forbidden. Use the typed Prisma query API.',
}),
),
],
},
},
{
files: ['app/rhea-backend/src/**/*.spec.ts'],
plugins: { neverkin },
rules: {
'neverkin/no-unknown-api-path': 'error',
},
},
{
files: ['**/*.{ts,tsx}'],
rules: {
'no-restricted-imports': [
'error',
{
paths: [
{
name: 'zod',
importNames: ['default'],
message:
"Use `import { z } from 'zod'`. The default import emits `z.z.core.*` into the .d.ts, which ts-morph (Moonflower) resolves to `any`.",
},
],
},
],
},
},
{
ignores: ['app/rhea-backend/**'],
extends: [eslintReact.configs['recommended-typescript']],
rules: {
// 'react-hooks/set-state-in-effect': 'off',
// 'react-hooks/refs': 'off',
// 'react-hooks/immutability': 'off',
// 'react-hooks/preserve-manual-memoization': 'off',
// 'react/prop-types': 'off',
'@eslint-react/no-context-provider': 'off',
'@eslint-react/no-array-index-key': 'off',
'@eslint-react/purity': 'off',
'@eslint-react/use-state': 'off',
'@eslint-react/no-unnecessary-use-prefix': 'off',
'@eslint-react/set-state-in-effect': 'off',
'@eslint-react/naming-convention-ref-name': 'off',
'@eslint-react/no-create-ref': 'off',
},
files: ['**/*.{ts,tsx}'],
settings: {
react: {
version: '19.x',
},
},
},
...eslintPluginAstro.configs['flat/recommended'],
{
files: ['app/thetis-landing/**/*.astro'],
ignores: [
'app/thetis-landing/src/components/common/BasicScripts.astro',
'app/thetis-landing/src/components/common/Image.astro',
],
languageOptions: {
parser: astroEslintParser,
parserOptions: {
parser: '@typescript-eslint/parser',
extraFileExtensions: ['.astro'],
},
},
},
eslintConfigPrettier,
eslintPluginPrettierRecommended,
{
files: ['**/*.astro/*.js', '**/*.astro/*.ts'],
rules: {
'prettier/prettier': 'off',
},
},
)