-
Notifications
You must be signed in to change notification settings - Fork 112
Expand file tree
/
Copy patheslint.config.mjs
More file actions
148 lines (145 loc) · 4.78 KB
/
Copy patheslint.config.mjs
File metadata and controls
148 lines (145 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format
import storybook from "eslint-plugin-storybook";
import unusedImports from "eslint-plugin-unused-imports";
import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";
const eslintConfig = defineConfig([
...nextVitals,
...nextTs,
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
".next/**",
"out/**",
"build/**",
"next-env.d.ts",
// next/jest configs must use CommonJS `require`
"jest.config.js",
"jest.integration.config.js",
"jest.setup.js",
]),
...storybook.configs["flat/recommended"],
{
// Security-sensitive rules
rules: {
"no-console": ["warn", { allow: ["warn", "error"] }],
"no-eval": "error",
"react/no-danger": "error",
"@typescript-eslint/no-explicit-any": "error",
},
},
{
// Exclude test files from no-console
files: ["**/*.test.{ts,tsx,js,jsx}", "**/*.spec.{ts,tsx,js,jsx}", "**/__tests__/**", "**/__mocks__/**"],
rules: {
"no-console": "off",
},
},
{
files: ["app/**/*.ts", "app/**/*.tsx"],
rules: {
"no-magic-numbers": ["warn", {
ignore: [0, 1, 2, 3, 5, 8, -1, 100, 1000, 1024, 60, 24, 7, 12, 200, 201, 204, 301, 302, 400, 401, 403, 404, 429, 500, 502, 503],
ignoreArrayIndexes: true,
ignoreDefaultValues: true,
}],
},
},
{
files: ["app/hooks/**/*.ts", "app/hooks/**/*.tsx", "app/lib/**/*.ts", "app/lib/**/*.tsx"],
rules: {
"no-restricted-syntax": [
"error",
{
selector: "ExportNamedDeclaration > FunctionDeclaration[id.name=/^mock/]",
message: "Functions starting with 'mock' must not be exported from production source files. Move them to __tests__/mocks/ or __mocks__/.",
},
{
selector: "ExportNamedDeclaration > VariableDeclaration > VariableDeclarator[id.name=/^mock/]",
message: "Variables/constants starting with 'mock' must not be exported from production source files. Move them to __tests__/mocks/ or __mocks__/.",
},
],
},
},
{
files: ["app/store/**/*.ts", "app/store/**/*.tsx"],
rules: {
"no-restricted-imports": [
"error",
{
patterns: [
{
group: ["**/mockApi*", "**/mockApi/**"],
message: "Store files must not import from mockApi directly. Use the ./api barrel export instead.",
},
],
},
],
},
},
{
// Build-time guard: no API route file may import from mockApi (in any location).
// This prevents mock data from accidentally shipping to production.
files: ["app/api/**/*.ts", "app/api/**/*.tsx"],
rules: {
"no-restricted-imports": [
"error",
{
patterns: [
{
group: ["**/mockApi*", "**/mockApi/**", "**/__mocks__/**"],
message:
"API routes must not import from mockApi or __mocks__. Replace with a real database query.",
},
],
},
],
},
},
{
// Build-time guard: no app page or component may import from mockApi.
// This prevents mock data from accidentally shipping to production.
files: ["app/**/*.ts", "app/**/*.tsx", "components/**/*.ts", "components/**/*.tsx"],
rules: {
"no-restricted-imports": [
"error",
{
patterns: [
{
group: ["**/mockApi*", "**/mockApi/**"],
message:
"App pages and components must not import from mockApi. Replace with real API calls.",
},
],
},
],
},
},
{
// Global stylistic and cleanup rules
files: ["**/*.{ts,tsx,js,jsx}"],
plugins: {
"unused-imports": unusedImports,
},
rules: {
// Remove unused imports via plugin
"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": [
"warn",
{ "vars": "all", "varsIgnorePattern": "^_", "args": "after-used", "argsIgnorePattern": "^_" }
],
// Enforce TypeScript naming conventions
"@typescript-eslint/naming-convention": [
"error",
{ "selector": "default", "format": ["camelCase"] },
{ "selector": "import", "format": ["camelCase", "PascalCase"] },
{ "selector": "objectLiteralProperty", "format": null },
{ "selector": "variableLike", "format": ["camelCase", "UPPER_CASE"] },
{ "selector": "typeLike", "format": ["PascalCase"] },
{ "selector": "function", "format": ["camelCase", "PascalCase"] }
],
},
},
]);
export default eslintConfig;