@yasainet/eslint 0.0.38 → 0.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/common/imports.mjs +76 -4
- package/src/common/layers.mjs +13 -1
- package/src/next/index.mjs +2 -1
package/package.json
CHANGED
package/src/common/imports.mjs
CHANGED
|
@@ -102,6 +102,28 @@ const LIB_BOUNDARY_PATTERNS = [
|
|
|
102
102
|
},
|
|
103
103
|
];
|
|
104
104
|
|
|
105
|
+
const MAPPING_PATTERNS = [
|
|
106
|
+
{
|
|
107
|
+
group: ["@/utils/mapping.util"],
|
|
108
|
+
importNames: ["mapSnakeToCamel", "mapCamelToSnake"],
|
|
109
|
+
message:
|
|
110
|
+
"Mapping functions are only allowed in services. Snake/camel conversion belongs at the service boundary.",
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
const PAGE_BOUNDARY_PATTERNS = [
|
|
115
|
+
{
|
|
116
|
+
group: ["*/repositories/*", "*/repositories"],
|
|
117
|
+
message:
|
|
118
|
+
"page.tsx can only import actions, not repositories (page-boundary violation)",
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
group: ["*/services/*", "*/services"],
|
|
122
|
+
message:
|
|
123
|
+
"page.tsx can only import actions, not services (page-boundary violation)",
|
|
124
|
+
},
|
|
125
|
+
];
|
|
126
|
+
|
|
105
127
|
function makeConfig(name, files, ...patternArrays) {
|
|
106
128
|
const patterns = patternArrays.flat();
|
|
107
129
|
if (patterns.length === 0) return null;
|
|
@@ -114,7 +136,21 @@ function makeConfig(name, files, ...patternArrays) {
|
|
|
114
136
|
};
|
|
115
137
|
}
|
|
116
138
|
|
|
117
|
-
/** Next.js-only: restrict
|
|
139
|
+
/** Next.js-only: restrict page.tsx to only import actions. */
|
|
140
|
+
export const pageBoundaryConfigs = [
|
|
141
|
+
{
|
|
142
|
+
name: "imports/page-boundary",
|
|
143
|
+
files: ["src/app/**/page.tsx"],
|
|
144
|
+
rules: {
|
|
145
|
+
"no-restricted-imports": ["error", { patterns: PAGE_BOUNDARY_PATTERNS }],
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
];
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Next.js-only: restrict @/lib imports and mapping imports outside features.
|
|
152
|
+
* Per-feature subdir rules live in createImportsConfigs to avoid clobbering each other.
|
|
153
|
+
*/
|
|
118
154
|
export const libBoundaryConfigs = [
|
|
119
155
|
{
|
|
120
156
|
name: "imports/lib-boundary",
|
|
@@ -124,11 +160,13 @@ export const libBoundaryConfigs = [
|
|
|
124
160
|
"src/proxy.ts",
|
|
125
161
|
"src/app/sitemap.ts",
|
|
126
162
|
"src/app/**/route.ts",
|
|
127
|
-
"src/features
|
|
128
|
-
"src/features/**/types/**",
|
|
163
|
+
"src/features/**",
|
|
129
164
|
],
|
|
130
165
|
rules: {
|
|
131
|
-
"no-restricted-imports": [
|
|
166
|
+
"no-restricted-imports": [
|
|
167
|
+
"error",
|
|
168
|
+
{ patterns: [...LIB_BOUNDARY_PATTERNS, ...MAPPING_PATTERNS] },
|
|
169
|
+
],
|
|
132
170
|
},
|
|
133
171
|
},
|
|
134
172
|
];
|
|
@@ -168,6 +206,7 @@ export function createImportsConfigs(
|
|
|
168
206
|
[`${featureRoot}/**/repositories/*.ts`],
|
|
169
207
|
LAYER_PATTERNS.repositories,
|
|
170
208
|
LATERAL_PATTERNS.repositories,
|
|
209
|
+
MAPPING_PATTERNS,
|
|
171
210
|
),
|
|
172
211
|
);
|
|
173
212
|
|
|
@@ -181,6 +220,7 @@ export function createImportsConfigs(
|
|
|
181
220
|
LAYER_PATTERNS.repositories,
|
|
182
221
|
LATERAL_PATTERNS.repositories,
|
|
183
222
|
patterns,
|
|
223
|
+
MAPPING_PATTERNS,
|
|
184
224
|
),
|
|
185
225
|
);
|
|
186
226
|
}
|
|
@@ -202,6 +242,7 @@ export function createImportsConfigs(
|
|
|
202
242
|
LAYER_PATTERNS.actions,
|
|
203
243
|
LATERAL_PATTERNS.actions,
|
|
204
244
|
LIB_BOUNDARY_PATTERNS,
|
|
245
|
+
MAPPING_PATTERNS,
|
|
205
246
|
),
|
|
206
247
|
);
|
|
207
248
|
|
|
@@ -210,9 +251,39 @@ export function createImportsConfigs(
|
|
|
210
251
|
"utils",
|
|
211
252
|
[`${featureRoot}/**/utils/*.ts`],
|
|
212
253
|
LIB_BOUNDARY_PATTERNS,
|
|
254
|
+
MAPPING_PATTERNS,
|
|
213
255
|
),
|
|
214
256
|
);
|
|
215
257
|
|
|
258
|
+
// Catch-all for feature subdirs without a per-layer config
|
|
259
|
+
// (constants, hooks, schemas). lib-boundary + mapping ban.
|
|
260
|
+
configs.push({
|
|
261
|
+
name: "imports/feature-other",
|
|
262
|
+
files: [`${featureRoot}/**/*.ts`],
|
|
263
|
+
ignores: [
|
|
264
|
+
`${featureRoot}/**/services/*.ts`,
|
|
265
|
+
`${featureRoot}/**/repositories/*.ts`,
|
|
266
|
+
`${featureRoot}/**/actions/*.ts`,
|
|
267
|
+
`${featureRoot}/**/utils/*.ts`,
|
|
268
|
+
`${featureRoot}/**/types/*.ts`,
|
|
269
|
+
],
|
|
270
|
+
rules: {
|
|
271
|
+
"no-restricted-imports": [
|
|
272
|
+
"error",
|
|
273
|
+
{ patterns: [...LIB_BOUNDARY_PATTERNS, ...MAPPING_PATTERNS] },
|
|
274
|
+
],
|
|
275
|
+
},
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// Types: mapping ban only. lib is allowed (Database/Tables type imports).
|
|
279
|
+
configs.push({
|
|
280
|
+
name: "imports/feature-types",
|
|
281
|
+
files: [`${featureRoot}/**/types/*.ts`],
|
|
282
|
+
rules: {
|
|
283
|
+
"no-restricted-imports": ["error", { patterns: MAPPING_PATTERNS }],
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
|
|
216
287
|
for (const prefix of ["server", "client", "admin"]) {
|
|
217
288
|
configs.push(
|
|
218
289
|
makeConfig(
|
|
@@ -222,6 +293,7 @@ export function createImportsConfigs(
|
|
|
222
293
|
LATERAL_PATTERNS.actions,
|
|
223
294
|
CARDINALITY_PATTERNS[prefix],
|
|
224
295
|
LIB_BOUNDARY_PATTERNS,
|
|
296
|
+
MAPPING_PATTERNS,
|
|
225
297
|
),
|
|
226
298
|
);
|
|
227
299
|
}
|
package/src/common/layers.mjs
CHANGED
|
@@ -39,7 +39,7 @@ export function createLayersConfigs(featureRoot) {
|
|
|
39
39
|
],
|
|
40
40
|
},
|
|
41
41
|
},
|
|
42
|
-
// Services: try-catch + logger
|
|
42
|
+
// Services: try-catch + logger + dead error fallbacks
|
|
43
43
|
{
|
|
44
44
|
name: "layers/services",
|
|
45
45
|
files: [`${featureRoot}/**/services/*.ts`],
|
|
@@ -52,6 +52,18 @@ export function createLayersConfigs(featureRoot) {
|
|
|
52
52
|
"try-catch is not allowed in services. Error handling belongs in actions.",
|
|
53
53
|
},
|
|
54
54
|
{ selector: loggerSelector, message: loggerMessage },
|
|
55
|
+
{
|
|
56
|
+
selector:
|
|
57
|
+
"LogicalExpression[operator='??'][left.type='ChainExpression'][left.expression.property.name='message'][right.type='Literal']",
|
|
58
|
+
message:
|
|
59
|
+
"Dead fallback for error message. If you reached this branch the error is known — return the error directly. Unhandled exceptions belong in actions.",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
selector:
|
|
63
|
+
"LogicalExpression[operator='??'][left.type='MemberExpression'][left.property.name='error'][right.type='ObjectExpression']",
|
|
64
|
+
message:
|
|
65
|
+
"Dead fallback for nullable error. Check `if (error)` and return the error directly. Unhandled exceptions belong in actions.",
|
|
66
|
+
},
|
|
55
67
|
],
|
|
56
68
|
},
|
|
57
69
|
},
|
package/src/next/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createEntryPointConfigs } from "../common/entry-points.mjs";
|
|
2
2
|
import { createCommonConfigs } from "../common/index.mjs";
|
|
3
|
-
import { libBoundaryConfigs } from "../common/imports.mjs";
|
|
3
|
+
import { libBoundaryConfigs, pageBoundaryConfigs } from "../common/imports.mjs";
|
|
4
4
|
|
|
5
5
|
import { directivesConfigs } from "./directives.mjs";
|
|
6
6
|
import { importPathStyleConfigs } from "./imports.mjs";
|
|
@@ -14,6 +14,7 @@ const nextEntryPointConfigs = createEntryPointConfigs(
|
|
|
14
14
|
export const eslintConfig = [
|
|
15
15
|
...createCommonConfigs("src/features"),
|
|
16
16
|
...libBoundaryConfigs,
|
|
17
|
+
...pageBoundaryConfigs,
|
|
17
18
|
...namingConfigs,
|
|
18
19
|
...directivesConfigs,
|
|
19
20
|
...importPathStyleConfigs,
|