@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yasainet/eslint",
3
- "version": "0.0.38",
3
+ "version": "0.0.40",
4
4
  "description": "ESLint",
5
5
  "type": "module",
6
6
  "exports": {
@@ -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 @/lib imports to repositories. */
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/**/repositories/**",
128
- "src/features/**/types/**",
163
+ "src/features/**",
129
164
  ],
130
165
  rules: {
131
- "no-restricted-imports": ["error", { patterns: LIB_BOUNDARY_PATTERNS }],
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
  }
@@ -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
  },
@@ -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,