@yasainet/eslint 0.0.49 → 0.0.51

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/README.md CHANGED
@@ -25,9 +25,9 @@ Each entry point enforces a feature-based architecture with the following conven
25
25
  ```text
26
26
  {featureRoot}/
27
27
  ├── {feature}/
28
- │ ├── actions/ # *.action.ts — entry points (handleXxx)
28
+ │ ├── interactors/ # *.interactor.ts — entry points
29
29
  │ ├── services/ # *.service.ts — business logic
30
- │ ├── repositories/ # *.repo.ts — data access
30
+ │ ├── queries/ # *.query.ts — data access
31
31
  │ ├── types/ # *.type.ts
32
32
  │ ├── schemas/ # *.schema.ts
33
33
  │ ├── utils/ # *.util.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yasainet/eslint",
3
- "version": "0.0.49",
3
+ "version": "0.0.51",
4
4
  "description": "ESLint",
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,46 +1,46 @@
1
1
  const LAYER_PATTERNS = {
2
- repositories: [
2
+ queries: [
3
3
  {
4
4
  group: ["*/services/*", "*/services"],
5
- message: "repositories cannot import services (layer violation)",
5
+ message: "queries cannot import services (layer violation)",
6
6
  },
7
7
  {
8
- group: ["*/actions/*", "*/actions"],
9
- message: "repositories cannot import actions (layer violation)",
8
+ group: ["*/interactors/*", "*/interactors"],
9
+ message: "queries cannot import interactors (layer violation)",
10
10
  },
11
11
  {
12
12
  group: ["*/hooks/*", "*/hooks"],
13
- message: "repositories cannot import hooks (layer violation)",
13
+ message: "queries cannot import hooks (layer violation)",
14
14
  },
15
15
  ],
16
16
  services: [
17
17
  {
18
- group: ["*/actions/*", "*/actions"],
19
- message: "services cannot import actions (layer violation)",
18
+ group: ["*/interactors/*", "*/interactors"],
19
+ message: "services cannot import interactors (layer violation)",
20
20
  },
21
21
  {
22
22
  group: ["*/hooks/*", "*/hooks"],
23
23
  message: "services cannot import hooks (layer violation)",
24
24
  },
25
25
  ],
26
- actions: [
26
+ interactors: [
27
27
  {
28
- group: ["*/repositories/*", "*/repositories"],
29
- message: "actions cannot import repositories (layer violation)",
28
+ group: ["*/queries/*", "*/queries"],
29
+ message: "interactors cannot import queries (layer violation)",
30
30
  },
31
31
  {
32
32
  group: ["*/hooks/*", "*/hooks"],
33
- message: "actions cannot import hooks (layer violation)",
33
+ message: "interactors cannot import hooks (layer violation)",
34
34
  },
35
35
  ],
36
36
  };
37
37
 
38
38
  const LATERAL_PATTERNS = {
39
- repositories: [
39
+ queries: [
40
40
  {
41
- group: ["@/features/*/repositories/*", "@/features/*/repositories"],
41
+ group: ["@/features/*/queries/*", "@/features/*/queries"],
42
42
  message:
43
- "repositories cannot import other feature's repositories (lateral violation)",
43
+ "queries cannot import other feature's queries (lateral violation)",
44
44
  },
45
45
  ],
46
46
  services: [
@@ -50,11 +50,11 @@ const LATERAL_PATTERNS = {
50
50
  "services cannot import other feature's services (lateral violation)",
51
51
  },
52
52
  ],
53
- actions: [
53
+ interactors: [
54
54
  {
55
- group: ["@/features/*/actions/*", "@/features/*/actions"],
55
+ group: ["@/features/*/interactors/*", "@/features/*/interactors"],
56
56
  message:
57
- "actions cannot import other feature's actions (lateral violation)",
57
+ "interactors cannot import other feature's interactors (lateral violation)",
58
58
  },
59
59
  ],
60
60
  };
@@ -64,21 +64,21 @@ const CARDINALITY_PATTERNS = {
64
64
  {
65
65
  group: ["**/services/client.service*", "**/services/admin.service*"],
66
66
  message:
67
- "server.action can only import server.service (cardinality violation)",
67
+ "server.interactor can only import server.service (cardinality violation)",
68
68
  },
69
69
  ],
70
70
  client: [
71
71
  {
72
72
  group: ["**/services/server.service*", "**/services/admin.service*"],
73
73
  message:
74
- "client.action can only import client.service (cardinality violation)",
74
+ "client.interactor can only import client.service (cardinality violation)",
75
75
  },
76
76
  ],
77
77
  admin: [
78
78
  {
79
79
  group: ["**/services/server.service*", "**/services/client.service*"],
80
80
  message:
81
- "admin.action can only import admin.service (cardinality violation)",
81
+ "admin.interactor can only import admin.service (cardinality violation)",
82
82
  },
83
83
  ],
84
84
  };
@@ -90,7 +90,7 @@ function prefixLibPatterns(prefix, mapping) {
90
90
  .filter((p) => p !== prefix)
91
91
  .map((p) => ({
92
92
  group: [`**/lib/${mapping[p]}`, `**/lib/${mapping[p]}/*`],
93
- message: `${prefix}.repo.ts can only import from lib/${allowedLib}. Use the correct repository file for this lib.`,
93
+ message: `${prefix}.query.ts can only import from lib/${allowedLib}. Use the correct query file for this lib.`,
94
94
  }));
95
95
  }
96
96
 
@@ -98,7 +98,7 @@ const LIB_BOUNDARY_PATTERNS = [
98
98
  {
99
99
  group: ["@/lib/*", "@/lib/**"],
100
100
  message:
101
- "lib/* can only be imported from repositories (lib-boundary violation)",
101
+ "lib/* can only be imported from queries (lib-boundary violation)",
102
102
  },
103
103
  ];
104
104
 
@@ -113,40 +113,40 @@ const MAPPING_PATTERNS = [
113
113
 
114
114
  const PAGE_BOUNDARY_PATTERNS = [
115
115
  {
116
- group: ["*/repositories/*", "*/repositories"],
116
+ group: ["*/queries/*", "*/queries"],
117
117
  message:
118
- "page.tsx can only import actions, not repositories (page-boundary violation)",
118
+ "page.tsx can only import interactors, not queries (page-boundary violation)",
119
119
  },
120
120
  {
121
121
  group: ["*/services/*", "*/services"],
122
122
  message:
123
- "page.tsx can only import actions, not services (page-boundary violation)",
123
+ "page.tsx can only import interactors, not services (page-boundary violation)",
124
124
  },
125
125
  ];
126
126
 
127
127
  const HOOKS_BOUNDARY_PATTERNS = [
128
128
  {
129
- group: ["*/repositories/*", "*/repositories"],
129
+ group: ["*/queries/*", "*/queries"],
130
130
  message:
131
- "hooks can only import actions, not repositories (hooks-boundary violation)",
131
+ "hooks can only import interactors, not queries (hooks-boundary violation)",
132
132
  },
133
133
  {
134
134
  group: ["*/services/*", "*/services"],
135
135
  message:
136
- "hooks can only import actions, not services (hooks-boundary violation)",
136
+ "hooks can only import interactors, not services (hooks-boundary violation)",
137
137
  },
138
138
  ];
139
139
 
140
140
  const COMPONENTS_BOUNDARY_PATTERNS = [
141
141
  {
142
- group: ["*/repositories/*", "*/repositories"],
142
+ group: ["*/queries/*", "*/queries"],
143
143
  message:
144
- "components can only import actions or hooks, not repositories (components-boundary violation)",
144
+ "components can only import interactors or hooks, not queries (components-boundary violation)",
145
145
  },
146
146
  {
147
147
  group: ["*/services/*", "*/services"],
148
148
  message:
149
- "components can only import actions or hooks, not services (components-boundary violation)",
149
+ "components can only import interactors or hooks, not services (components-boundary violation)",
150
150
  },
151
151
  ];
152
152
 
@@ -162,7 +162,7 @@ function makeConfig(name, files, ...patternArrays) {
162
162
  };
163
163
  }
164
164
 
165
- /** Next.js-only: restrict page.tsx to only import actions. */
165
+ /** Next.js-only: restrict page.tsx to only import interactors. */
166
166
  export const pageBoundaryConfigs = [
167
167
  {
168
168
  name: "imports/page-boundary",
@@ -173,7 +173,7 @@ export const pageBoundaryConfigs = [
173
173
  },
174
174
  ];
175
175
 
176
- /** Next.js-only: restrict hooks to only import actions (not repositories or services). */
176
+ /** Next.js-only: restrict hooks to only import interactors (not queries or services). */
177
177
  export const hooksBoundaryConfigs = [
178
178
  {
179
179
  name: "imports/hooks-boundary",
@@ -184,7 +184,7 @@ export const hooksBoundaryConfigs = [
184
184
  },
185
185
  ];
186
186
 
187
- /** Next.js-only: restrict components to only import actions or hooks (not repositories or services). */
187
+ /** Next.js-only: restrict components to only import interactors or hooks (not queries or services). */
188
188
  export const componentsBoundaryConfigs = [
189
189
  {
190
190
  name: "imports/components-boundary",
@@ -253,10 +253,10 @@ export function createImportsConfigs(
253
253
 
254
254
  configs.push(
255
255
  makeConfig(
256
- "repositories",
257
- [`${featureRoot}/**/repositories/*.ts`],
258
- LAYER_PATTERNS.repositories,
259
- LATERAL_PATTERNS.repositories,
256
+ "queries",
257
+ [`${featureRoot}/**/queries/*.ts`],
258
+ LAYER_PATTERNS.queries,
259
+ LATERAL_PATTERNS.queries,
260
260
  MAPPING_PATTERNS,
261
261
  ),
262
262
  );
@@ -266,10 +266,10 @@ export function createImportsConfigs(
266
266
  if (patterns.length === 0) continue;
267
267
  configs.push(
268
268
  makeConfig(
269
- `repositories/${prefix}`,
270
- [`${featureRoot}/**/repositories/${prefix}.repo.ts`],
271
- LAYER_PATTERNS.repositories,
272
- LATERAL_PATTERNS.repositories,
269
+ `queries/${prefix}`,
270
+ [`${featureRoot}/**/queries/${prefix}.query.ts`],
271
+ LAYER_PATTERNS.queries,
272
+ LATERAL_PATTERNS.queries,
273
273
  patterns,
274
274
  MAPPING_PATTERNS,
275
275
  ),
@@ -288,10 +288,10 @@ export function createImportsConfigs(
288
288
 
289
289
  configs.push(
290
290
  makeConfig(
291
- "actions",
292
- [`${featureRoot}/**/actions/*.ts`],
293
- LAYER_PATTERNS.actions,
294
- LATERAL_PATTERNS.actions,
291
+ "interactors",
292
+ [`${featureRoot}/**/interactors/*.ts`],
293
+ LAYER_PATTERNS.interactors,
294
+ LATERAL_PATTERNS.interactors,
295
295
  LIB_BOUNDARY_PATTERNS,
296
296
  MAPPING_PATTERNS,
297
297
  ),
@@ -313,8 +313,8 @@ export function createImportsConfigs(
313
313
  files: [`${featureRoot}/**/*.ts`],
314
314
  ignores: [
315
315
  `${featureRoot}/**/services/*.ts`,
316
- `${featureRoot}/**/repositories/*.ts`,
317
- `${featureRoot}/**/actions/*.ts`,
316
+ `${featureRoot}/**/queries/*.ts`,
317
+ `${featureRoot}/**/interactors/*.ts`,
318
318
  `${featureRoot}/**/utils/*.ts`,
319
319
  `${featureRoot}/**/types/*.ts`,
320
320
  ],
@@ -338,10 +338,10 @@ export function createImportsConfigs(
338
338
  for (const prefix of ["server", "client", "admin"]) {
339
339
  configs.push(
340
340
  makeConfig(
341
- `actions/${prefix}`,
342
- [`${featureRoot}/**/actions/${prefix}.action.ts`],
343
- LAYER_PATTERNS.actions,
344
- LATERAL_PATTERNS.actions,
341
+ `interactors/${prefix}`,
342
+ [`${featureRoot}/**/interactors/${prefix}.interactor.ts`],
343
+ LAYER_PATTERNS.interactors,
344
+ LATERAL_PATTERNS.interactors,
345
345
  CARDINALITY_PATTERNS[prefix],
346
346
  LIB_BOUNDARY_PATTERNS,
347
347
  MAPPING_PATTERNS,
@@ -8,7 +8,7 @@ export function createJsdocConfigs(featureRoot) {
8
8
  {
9
9
  name: "jsdoc",
10
10
  files: [
11
- ...featuresGlob(featureRoot, "**/repositories/*.ts"),
11
+ ...featuresGlob(featureRoot, "**/queries/*.ts"),
12
12
  ...featuresGlob(featureRoot, "**/services*/*.ts"),
13
13
  ...featuresGlob(featureRoot, "**/utils*/*.ts"),
14
14
  ],
@@ -4,14 +4,14 @@ import { localPlugin } from "./local-plugins/index.mjs";
4
4
  export function createLayersConfigs(featureRoot) {
5
5
  const loggerSelector = "CallExpression[callee.object.name='logger']";
6
6
  const loggerMessage =
7
- "logger is not allowed outside actions. Logging belongs in actions.";
7
+ "logger is not allowed outside interactors. Logging belongs in interactors.";
8
8
 
9
9
  return [
10
- // Logger/console: all features except actions
10
+ // Logger/console: all features except interactors
11
11
  {
12
12
  name: "layers/logger",
13
13
  files: [`${featureRoot}/**/*.ts`],
14
- ignores: [`${featureRoot}/**/actions/*.ts`],
14
+ ignores: [`${featureRoot}/**/interactors/*.ts`],
15
15
  rules: {
16
16
  "no-console": "error",
17
17
  "no-restricted-syntax": [
@@ -20,64 +20,64 @@ export function createLayersConfigs(featureRoot) {
20
20
  ],
21
21
  },
22
22
  },
23
- // Repositories: try-catch + if + loops + logger
23
+ // Queries: try-catch + if + loops + logger
24
24
  {
25
- name: "layers/repositories",
26
- files: [`${featureRoot}/**/repositories/*.ts`],
25
+ name: "layers/queries",
26
+ files: [`${featureRoot}/**/queries/*.ts`],
27
27
  rules: {
28
28
  "no-restricted-syntax": [
29
29
  "error",
30
30
  {
31
31
  selector: "TryStatement",
32
32
  message:
33
- "try-catch is not allowed in repositories. Error handling belongs in actions.",
33
+ "try-catch is not allowed in queries. Error handling belongs in interactors.",
34
34
  },
35
35
  {
36
36
  selector: "IfStatement",
37
37
  message:
38
- "if statements are not allowed in repositories. Conditional logic belongs in services.",
38
+ "if statements are not allowed in queries. Conditional logic belongs in services.",
39
39
  },
40
40
  {
41
41
  selector: "ForStatement",
42
42
  message:
43
- "Loops are not allowed in repositories. Repositories should be thin CRUD wrappers — iteration belongs in services.",
43
+ "Loops are not allowed in queries. Queries should be thin CRUD wrappers — iteration belongs in services.",
44
44
  },
45
45
  {
46
46
  selector: "ForOfStatement",
47
47
  message:
48
- "Loops are not allowed in repositories. Repositories should be thin CRUD wrappers — iteration belongs in services.",
48
+ "Loops are not allowed in queries. Queries should be thin CRUD wrappers — iteration belongs in services.",
49
49
  },
50
50
  {
51
51
  selector: "ForInStatement",
52
52
  message:
53
- "Loops are not allowed in repositories. Repositories should be thin CRUD wrappers — iteration belongs in services.",
53
+ "Loops are not allowed in queries. Queries should be thin CRUD wrappers — iteration belongs in services.",
54
54
  },
55
55
  {
56
56
  selector: "WhileStatement",
57
57
  message:
58
- "Loops are not allowed in repositories. Repositories should be thin CRUD wrappers — iteration belongs in services.",
58
+ "Loops are not allowed in queries. Queries should be thin CRUD wrappers — iteration belongs in services.",
59
59
  },
60
60
  {
61
61
  selector: "DoWhileStatement",
62
62
  message:
63
- "Loops are not allowed in repositories. Repositories should be thin CRUD wrappers — iteration belongs in services.",
63
+ "Loops are not allowed in queries. Queries should be thin CRUD wrappers — iteration belongs in services.",
64
64
  },
65
65
  {
66
66
  selector: "ThrowStatement",
67
67
  message:
68
- "throw is not allowed in repositories. Repositories must return Supabase's { data, error } shape as-is. Error handling belongs in actions.",
68
+ "throw is not allowed in queries. Queries must return Supabase's { data, error } shape as-is. Error handling belongs in interactors.",
69
69
  },
70
70
  { selector: loggerSelector, message: loggerMessage },
71
71
  ],
72
72
  },
73
73
  },
74
- // Boundary type safety: repositories & services must not leak `any`
74
+ // Boundary type safety: queries & services must not leak `any`
75
75
  // into their public API. Uses type-aware inspection of the inferred
76
76
  // return type so unannotated functions are still checked.
77
77
  {
78
78
  name: "layers/no-any-return",
79
79
  files: [
80
- `${featureRoot}/**/repositories/*.ts`,
80
+ `${featureRoot}/**/queries/*.ts`,
81
81
  `${featureRoot}/**/services/*.ts`,
82
82
  ],
83
83
  plugins: { local: localPlugin },
@@ -95,20 +95,20 @@ export function createLayersConfigs(featureRoot) {
95
95
  {
96
96
  selector: "TryStatement",
97
97
  message:
98
- "try-catch is not allowed in services. Error handling belongs in actions.",
98
+ "try-catch is not allowed in services. Error handling belongs in interactors.",
99
99
  },
100
100
  { selector: loggerSelector, message: loggerMessage },
101
101
  {
102
102
  selector:
103
103
  "LogicalExpression[operator='??'][left.type='ChainExpression'][left.expression.property.name='message'][right.type='Literal']",
104
104
  message:
105
- "Dead fallback for error message. If you reached this branch the error is known — return the error directly. Unhandled exceptions belong in actions.",
105
+ "Dead fallback for error message. If you reached this branch the error is known — return the error directly. Unhandled exceptions belong in interactors.",
106
106
  },
107
107
  {
108
108
  selector:
109
109
  "LogicalExpression[operator='??'][left.type='MemberExpression'][left.property.name='error'][right.type='ObjectExpression']",
110
110
  message:
111
- "Dead fallback for nullable error. Check `if (error)` and return the error directly. Unhandled exceptions belong in actions.",
111
+ "Dead fallback for nullable error. Check `if (error)` and return the error directly. Unhandled exceptions belong in interactors.",
112
112
  },
113
113
  ],
114
114
  },
@@ -1,4 +1,3 @@
1
- import { actionHandleServiceRule } from "./action-handle-service.mjs";
2
1
  import { featureNameRule } from "./feature-name.mjs";
3
2
  import { importPathStyleRule } from "./import-path-style.mjs";
4
3
  import { namespaceImportNameRule } from "./namespace-import-name.mjs";
@@ -8,7 +7,6 @@ import { schemaNamingRule } from "./schema-naming.mjs";
8
7
  /** Single plugin object to avoid ESLint "Cannot redefine plugin" errors. */
9
8
  export const localPlugin = {
10
9
  rules: {
11
- "action-handle-service": actionHandleServiceRule,
12
10
  "feature-name": featureNameRule,
13
11
  "import-path-style": importPathStyleRule,
14
12
  "namespace-import-name": namespaceImportNameRule,
@@ -7,10 +7,10 @@
7
7
 
8
8
  /** @type {Record<string, string>} */
9
9
  const LAYER_MAP = {
10
- repo: "Repository",
10
+ query: "Query",
11
11
  service: "Service",
12
12
  domain: "Domain",
13
- action: "Action",
13
+ interactor: "Interactor",
14
14
  util: "Util",
15
15
  type: "Type",
16
16
  schema: "Schema",
@@ -4,7 +4,7 @@ import ts from "typescript";
4
4
  * Exported function の return type が any を含んでいる場合に error:
5
5
  *
6
6
  * - typescript-eslint の type checker を使って inferred type まで見る
7
- * - repositories / services の API 境界を any 汚染から守ることで、domain shape が型で保証される
7
+ * - queries / services の API 境界を any 汚染から守ることで、domain shape が型で保証される
8
8
  * - Promise<any>, Promise<{ data: any }>, Array<any> など nested も展開して検査する
9
9
  */
10
10
  export const noAnyReturnRule = {
@@ -52,10 +52,10 @@ export function createNamingConfigs(featureRoot, prefixLibMapping) {
52
52
  const servicePattern = prefixPattern
53
53
  ? `${prefixPattern}.service`
54
54
  : "*.service";
55
- const repoPattern = prefixPattern ? `${prefixPattern}.repo` : "*.repo";
56
- const actionPattern = prefixPattern
57
- ? `${prefixPattern}.action`
58
- : "*.action";
55
+ const queryPattern = prefixPattern ? `${prefixPattern}.query` : "*.query";
56
+ const interactorPattern = prefixPattern
57
+ ? `${prefixPattern}.interactor`
58
+ : "*.interactor";
59
59
 
60
60
  const configs = [];
61
61
 
@@ -91,14 +91,14 @@ export function createNamingConfigs(featureRoot, prefixLibMapping) {
91
91
  },
92
92
  },
93
93
  {
94
- name: "naming/repositories",
95
- files: featuresGlob(featureRoot, "**/repositories/*.ts"),
96
- ignores: featuresGlob(featureRoot, "shared/repositories/*.ts"),
94
+ name: "naming/queries",
95
+ files: featuresGlob(featureRoot, "**/queries/*.ts"),
96
+ ignores: featuresGlob(featureRoot, "shared/queries/*.ts"),
97
97
  plugins: { "check-file": checkFile },
98
98
  rules: {
99
99
  "check-file/filename-naming-convention": [
100
100
  "error",
101
- { "**/*.ts": repoPattern },
101
+ { "**/*.ts": queryPattern },
102
102
  ],
103
103
  },
104
104
  },
@@ -117,13 +117,13 @@ export function createNamingConfigs(featureRoot, prefixLibMapping) {
117
117
  },
118
118
  },
119
119
  {
120
- name: "naming/repositories-shared",
121
- files: featuresGlob(featureRoot, "shared/repositories/*.ts"),
120
+ name: "naming/queries-shared",
121
+ files: featuresGlob(featureRoot, "shared/queries/*.ts"),
122
122
  plugins: { "check-file": checkFile },
123
123
  rules: {
124
124
  "check-file/filename-naming-convention": [
125
125
  "error",
126
- { "**/*.ts": `${sharedPrefixPattern}.repo` },
126
+ { "**/*.ts": `${sharedPrefixPattern}.query` },
127
127
  ],
128
128
  },
129
129
  },
@@ -237,53 +237,30 @@ export function createNamingConfigs(featureRoot, prefixLibMapping) {
237
237
  );
238
238
 
239
239
  configs.push({
240
- name: "naming/actions",
241
- files: featuresGlob(featureRoot, "**/actions/*.ts"),
242
- ignores: featuresGlob(featureRoot, "shared/actions/*.ts"),
240
+ name: "naming/interactors",
241
+ files: featuresGlob(featureRoot, "**/interactors/*.ts"),
242
+ ignores: featuresGlob(featureRoot, "shared/interactors/*.ts"),
243
243
  plugins: { "check-file": checkFile },
244
244
  rules: {
245
245
  "check-file/filename-naming-convention": [
246
246
  "error",
247
- { "**/*.ts": actionPattern },
247
+ { "**/*.ts": interactorPattern },
248
248
  ],
249
249
  },
250
250
  });
251
251
 
252
252
  configs.push(
253
253
  {
254
- name: "naming/actions-shared",
255
- files: featuresGlob(featureRoot, "shared/actions/*.ts"),
254
+ name: "naming/interactors-shared",
255
+ files: featuresGlob(featureRoot, "shared/interactors/*.ts"),
256
256
  plugins: { "check-file": checkFile },
257
257
  rules: {
258
258
  "check-file/filename-naming-convention": [
259
259
  "error",
260
- { "**/*.ts": `${sharedPrefixPattern}.action` },
260
+ { "**/*.ts": `${sharedPrefixPattern}.interactor` },
261
261
  ],
262
262
  },
263
263
  },
264
- {
265
- name: "naming/actions-export",
266
- files: featuresGlob(featureRoot, "**/actions/*.ts"),
267
- rules: {
268
- "no-restricted-syntax": [
269
- "error",
270
- {
271
- selector:
272
- "ExportNamedDeclaration > FunctionDeclaration[id.name!=/^handle[A-Z]/]",
273
- message:
274
- "Exported functions in actions must start with 'handle' (e.g., handleGetComics).",
275
- },
276
- ],
277
- },
278
- },
279
- {
280
- name: "naming/actions-handle-service",
281
- files: featuresGlob(featureRoot, "**/actions/*.ts"),
282
- plugins: { local: localPlugin },
283
- rules: {
284
- "local/action-handle-service": "error",
285
- },
286
- },
287
264
  {
288
265
  name: "naming/features-ts-only",
289
266
  files: featuresGlob(featureRoot, "**/*.tsx"),
@@ -10,7 +10,7 @@ export const denoImportsConfigs = [
10
10
  files: [`${FUNCTIONS_ROOT}/**/*.ts`],
11
11
  ignores: [
12
12
  `${FUNCTIONS_ROOT}/_lib/**`,
13
- `${FEATURE_ROOT}/**/repositories/**`,
13
+ `${FEATURE_ROOT}/**/queries/**`,
14
14
  `${FEATURE_ROOT}/**/types/**`,
15
15
  ],
16
16
  rules: {
@@ -21,7 +21,7 @@ export const denoImportsConfigs = [
21
21
  {
22
22
  group: ["*/_lib/*", "*/_lib/**"],
23
23
  message:
24
- "_lib/ can only be imported from repositories (lib-boundary violation)",
24
+ "_lib/ can only be imported from queries (lib-boundary violation)",
25
25
  },
26
26
  ],
27
27
  },
@@ -40,17 +40,17 @@ export const denoImportsConfigs = [
40
40
  {
41
41
  group: ["**/services/*", "**/services"],
42
42
  message:
43
- "Entry points must not import services directly. Import from actions instead.",
43
+ "Entry points must not import services directly. Import from interactors instead.",
44
44
  },
45
45
  {
46
- group: ["**/repositories/*", "**/repositories"],
46
+ group: ["**/queries/*", "**/queries"],
47
47
  message:
48
- "Entry points must not import repositories directly. Import from actions instead.",
48
+ "Entry points must not import queries directly. Import from interactors instead.",
49
49
  },
50
50
  {
51
51
  group: ["*/_lib/*", "*/_lib/**"],
52
52
  message:
53
- "Entry points must not import _lib/ directly. Import from actions instead.",
53
+ "Entry points must not import _lib/ directly. Import from interactors instead.",
54
54
  },
55
55
  ],
56
56
  },
@@ -1,43 +1,45 @@
1
1
  /** Enforce "use server" / "use client" directives per file convention. */
2
2
  export const directivesConfigs = [
3
3
  {
4
- name: "directives/server-action",
5
- files: ["src/features/**/actions/server.action.ts"],
4
+ name: "directives/server-interactor",
5
+ files: ["src/features/**/interactors/server.interactor.ts"],
6
6
  rules: {
7
7
  "no-restricted-syntax": [
8
8
  "error",
9
9
  {
10
10
  selector:
11
11
  "Program > :first-child:not(ExpressionStatement[expression.value='use server'])",
12
- message: 'server.action.ts must start with "use server" directive.',
12
+ message:
13
+ 'server.interactor.ts must start with "use server" directive.',
13
14
  },
14
15
  ],
15
16
  },
16
17
  },
17
18
  {
18
- name: "directives/admin-action",
19
- files: ["src/features/**/actions/admin.action.ts"],
19
+ name: "directives/admin-interactor",
20
+ files: ["src/features/**/interactors/admin.interactor.ts"],
20
21
  rules: {
21
22
  "no-restricted-syntax": [
22
23
  "error",
23
24
  {
24
25
  selector:
25
26
  "Program > :first-child:not(ExpressionStatement[expression.value='use server'])",
26
- message: 'admin.action.ts must start with "use server" directive.',
27
+ message:
28
+ 'admin.interactor.ts must start with "use server" directive.',
27
29
  },
28
30
  ],
29
31
  },
30
32
  },
31
33
  {
32
- name: "directives/client-action",
33
- files: ["src/features/**/actions/client.action.ts"],
34
+ name: "directives/client-interactor",
35
+ files: ["src/features/**/interactors/client.interactor.ts"],
34
36
  rules: {
35
37
  "no-restricted-syntax": [
36
38
  "error",
37
39
  {
38
40
  selector: "ExpressionStatement[expression.value='use server']",
39
41
  message:
40
- 'client.action.ts must NOT have "use server" directive. It uses @/lib/supabase/client.',
42
+ 'client.interactor.ts must NOT have "use server" directive. It uses @/lib/supabase/client.',
41
43
  },
42
44
  ],
43
45
  },
@@ -1,58 +0,0 @@
1
- /** In *.action.ts, handleXxx must call the service method *.xxx(). */
2
- export const actionHandleServiceRule = {
3
- meta: {
4
- type: "problem",
5
- messages: {
6
- missingCall:
7
- "handleXxx must call the corresponding service method '*.{{ expected }}()'.",
8
- },
9
- schema: [],
10
- },
11
- create(context) {
12
- return {
13
- "ExportNamedDeclaration > FunctionDeclaration[id.name=/^handle[A-Z]/]"(
14
- node,
15
- ) {
16
- const name = node.id.name;
17
- const suffix = name.slice("handle".length);
18
- const expected = suffix[0].toLowerCase() + suffix.slice(1);
19
-
20
- let found = false;
21
-
22
- function walk(n) {
23
- if (found || !n || typeof n !== "object") return;
24
-
25
- if (
26
- n.type === "CallExpression" &&
27
- n.callee.type === "MemberExpression" &&
28
- !n.callee.computed &&
29
- n.callee.property.name === expected
30
- ) {
31
- found = true;
32
- return;
33
- }
34
-
35
- for (const key of Object.keys(n)) {
36
- if (key === "parent") continue;
37
- const child = n[key];
38
- if (Array.isArray(child)) {
39
- for (const item of child) walk(item);
40
- } else if (child && typeof child.type === "string") {
41
- walk(child);
42
- }
43
- }
44
- }
45
-
46
- walk(node.body);
47
-
48
- if (!found) {
49
- context.report({
50
- node: node.id,
51
- messageId: "missingCall",
52
- data: { expected },
53
- });
54
- }
55
- },
56
- };
57
- },
58
- };