110 lines
3.2 KiB
JavaScript
110 lines
3.2 KiB
JavaScript
import { defineConfig, globalIgnores } from "eslint/config";
|
|
import nextVitals from "eslint-config-next/core-web-vitals";
|
|
import nextTs from "eslint-config-next/typescript";
|
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
import { dirname, join } from "node:path";
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
|
const eslintConfig = defineConfig([
|
|
...nextVitals,
|
|
...nextTs,
|
|
{
|
|
rules: {
|
|
"react-hooks/incompatible-library": "off",
|
|
"@typescript-eslint/no-unused-vars": [
|
|
"warn",
|
|
{
|
|
argsIgnorePattern: "^_",
|
|
varsIgnorePattern: "^_",
|
|
caughtErrorsIgnorePattern: "^_",
|
|
},
|
|
],
|
|
// 禁止硬编码 hex 颜色字面量(白名单:tokens 定义文件、邮件、manifest)
|
|
// 白名单文件内的 #hex 需在所在行上方加 // eslint-disable-next-line no-restricted-syntax 注释豁免
|
|
"no-restricted-syntax": [
|
|
"error",
|
|
{
|
|
selector: "Literal[value=/#[0-9a-fA-F]{3,8}/]",
|
|
message:
|
|
"禁止硬编码 hex 颜色,使用设计令牌 hsl(var(--*)) 或 Tailwind 类 bg-*",
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
files: ["tests/**/*.ts"],
|
|
languageOptions: {
|
|
globals: {
|
|
describe: "readonly",
|
|
it: "readonly",
|
|
test: "readonly",
|
|
expect: "readonly",
|
|
beforeAll: "readonly",
|
|
afterAll: "readonly",
|
|
beforeEach: "readonly",
|
|
afterEach: "readonly",
|
|
vi: "readonly",
|
|
},
|
|
},
|
|
},
|
|
// 自定义规则:检测硬编码字体家族字面量
|
|
{
|
|
plugins: {
|
|
"design-tokens": {
|
|
rules: {
|
|
"no-hardcoded-fonts": await import(
|
|
pathToFileURL(join(__dirname, "eslint-rules/no-hardcoded-design-tokens.js")).href
|
|
).then((m) => m.default ?? m),
|
|
},
|
|
},
|
|
},
|
|
rules: {
|
|
"design-tokens/no-hardcoded-fonts": "error",
|
|
},
|
|
},
|
|
// 缓存策略规则:禁止在 actions / route.ts 中直接调用 revalidatePath/revalidateTag
|
|
{
|
|
files: ["src/modules/**/actions*.ts", "src/app/api/**/route.ts", "src/i18n/actions*.ts"],
|
|
rules: {
|
|
"no-restricted-syntax": [
|
|
"error",
|
|
{
|
|
selector: "CallExpression[callee.name='revalidatePath']",
|
|
message:
|
|
"使用 invalidateFor() 替代直接 revalidatePath(),参见 docs/architecture/004 缓存章节",
|
|
},
|
|
{
|
|
selector: "CallExpression[callee.name='revalidateTag']",
|
|
message:
|
|
"使用 invalidateFor() 替代直接 revalidateTag(),参见 docs/architecture/004 缓存章节",
|
|
},
|
|
],
|
|
},
|
|
},
|
|
// 豁免:shared/lib/cache/ 内部允许调用 revalidatePath/revalidateTag(invalidate.ts 内部实现)
|
|
{
|
|
files: ["src/shared/lib/cache/**/*.ts"],
|
|
rules: {
|
|
"no-restricted-syntax": "off",
|
|
},
|
|
},
|
|
// Override default ignores of eslint-config-next.
|
|
globalIgnores([
|
|
// Default ignores of eslint-config-next:
|
|
".next/**",
|
|
"out/**",
|
|
"build/**",
|
|
"next-env.d.ts",
|
|
"docs/scripts/**",
|
|
"playwright-report/**",
|
|
"test-results/**",
|
|
// Debug scripts using CommonJS
|
|
"tests/webapp/debug_drizzle.js",
|
|
// Migration/maintenance scripts using CommonJS require()
|
|
"scripts/**/*.js",
|
|
]),
|
|
]);
|
|
|
|
export default eslintConfig;
|