Assist_Design/eslint.config.mjs

178 lines
4.7 KiB
JavaScript
Raw Normal View History

2025-08-27 10:54:05 +09:00
/* eslint-env node */
import process from "node:process";
import path from "node:path";
import { fileURLToPath } from "node:url";
2025-08-22 17:02:49 +09:00
import js from "@eslint/js";
import tseslint from "typescript-eslint";
import prettier from "eslint-plugin-prettier";
import globals from "globals";
2025-08-22 17:02:49 +09:00
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// Dynamically import Next.js ESLint configs only when needed
async function getNextConfigs() {
try {
const { FlatCompat } = await import("@eslint/eslintrc");
const compat = new FlatCompat({ baseDirectory: path.join(__dirname, "apps/portal") });
return {
coreWebVitals: compat.extends("next/core-web-vitals"),
typescript: compat.extends("next/typescript"),
};
} catch {
return { coreWebVitals: [], typescript: [] };
}
}
const nextConfigs = await getNextConfigs();
2025-08-22 17:02:49 +09:00
export default [
// Global ignores
{
ignores: [
"**/node_modules/**",
"**/dist/**",
"**/.next/**",
"**/build/**",
"**/coverage/**",
"**/next-env.d.ts",
"**/prisma/**",
2025-08-22 17:02:49 +09:00
],
},
// Base JS recommendations
2025-08-22 17:02:49 +09:00
js.configs.recommended,
// Prettier integration
2025-08-22 17:02:49 +09:00
{
plugins: { prettier },
rules: { "prettier/prettier": "warn" },
2025-08-22 17:02:49 +09:00
},
// TypeScript type-checked rules for all TS files
...tseslint.configs.recommendedTypeChecked.map((config) => ({
2025-08-22 17:02:49 +09:00
...config,
files: ["**/*.ts", "**/*.tsx"],
languageOptions: {
...(config.languageOptions || {}),
globals: { ...globals.node },
},
2025-08-22 17:02:49 +09:00
})),
// Backend & domain packages
2025-08-22 17:02:49 +09:00
{
files: ["apps/bff/**/*.ts", "packages/domain/**/*.ts"],
2025-08-22 17:02:49 +09:00
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: process.cwd(),
},
},
rules: {
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }],
2025-08-22 17:02:49 +09:00
"no-console": ["warn", { allow: ["warn", "error"] }],
},
},
// Strict rules for shared packages
2025-08-22 17:02:49 +09:00
{
files: ["packages/**/*.ts"],
2025-08-22 17:02:49 +09:00
rules: {
"@typescript-eslint/no-redundant-type-constituents": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-unsafe-return": "error",
"@typescript-eslint/no-unsafe-call": "error",
"@typescript-eslint/no-unsafe-member-access": "error",
},
},
// Next.js app config (only applies to portal files)
...nextConfigs.coreWebVitals.map((config) => ({
...config,
files: ["apps/portal/**/*.{js,jsx,ts,tsx}"],
})),
...nextConfigs.typescript.map((config) => ({
...config,
files: ["apps/portal/**/*.{ts,tsx}"],
})),
2025-08-22 17:02:49 +09:00
// Portal type-aware rules
2025-08-22 17:02:49 +09:00
{
files: ["apps/portal/**/*.{ts,tsx}"],
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: process.cwd(),
},
},
rules: {
"@next/next/no-html-link-for-pages": "off",
},
2025-08-22 17:02:49 +09:00
},
// Prevent hard navigation in authenticated pages
{
files: ["apps/portal/src/app/(authenticated)/**/*.{ts,tsx}"],
rules: {
"no-restricted-syntax": [
"error",
{
selector: "MemberExpression[object.name='window'][property.name='location']",
message: "Use next/link or useRouter for navigation.",
},
],
},
},
// Exceptions for specific files
{
files: ["apps/portal/src/app/(authenticated)/layout.tsx"],
rules: { "no-restricted-imports": "off" },
},
{
files: ["apps/portal/src/app/(authenticated)/billing/invoices/[id]/page.tsx"],
rules: { "no-restricted-syntax": "off" },
},
// Enforce domain imports architecture
{
files: ["apps/portal/src/**/*.{ts,tsx}", "apps/bff/src/**/*.ts"],
rules: {
"no-restricted-imports": [
"error",
{
patterns: [
{
group: ["@customer-portal/domain/**/src/**"],
message: "Import from @customer-portal/domain/<module> instead of internals.",
},
],
},
],
2025-08-22 17:02:49 +09:00
},
},
// BFF strict type safety
2025-08-22 17:02:49 +09:00
{
files: ["apps/bff/**/*.ts"],
rules: {
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-unsafe-assignment": "error",
"@typescript-eslint/no-unsafe-member-access": "error",
"@typescript-eslint/no-unsafe-call": "error",
"@typescript-eslint/no-unsafe-return": "error",
"@typescript-eslint/no-unsafe-argument": "error",
"@typescript-eslint/require-await": "error",
"@typescript-eslint/no-floating-promises": "error",
},
},
// Node globals for config files
{
files: ["*.config.mjs", "apps/portal/next.config.mjs"],
languageOptions: {
globals: { ...globals.node },
2025-08-22 17:02:49 +09:00
},
},
];