@yasainet/eslint 0.0.73 → 0.0.75

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.
Files changed (76) hide show
  1. package/README.md +9 -152
  2. package/package.json +7 -1
  3. package/src/cli/test-audit.mjs +97 -0
  4. package/src/common/CLAUDE.md +17 -0
  5. package/src/common/{constants.mjs → _internal/constants.mjs} +1 -19
  6. package/src/common/_internal/import-patterns.mjs +16 -0
  7. package/src/common/{plugins.mjs → _internal/plugins.mjs} +0 -1
  8. package/src/common/_internal/selectors.mjs +12 -0
  9. package/src/common/{rules.mjs → base/typescript.mjs} +15 -36
  10. package/src/common/{entry-points.mjs → boundaries/entry-point.mjs} +1 -2
  11. package/src/common/cross-cutting/ban-alias.mjs +22 -0
  12. package/src/common/cross-cutting/feature-default-imports.mjs +26 -0
  13. package/src/common/cross-cutting/feature-name.mjs +15 -0
  14. package/src/common/cross-cutting/features-ts-only.mjs +20 -0
  15. package/src/common/cross-cutting/form-state.mjs +16 -0
  16. package/src/common/{jsdoc.mjs → cross-cutting/jsdoc.mjs} +2 -3
  17. package/src/common/cross-cutting/logger.mjs +21 -0
  18. package/src/common/cross-cutting/namespace-import.mjs +23 -0
  19. package/src/common/cross-cutting/no-any-return.mjs +18 -0
  20. package/src/common/cross-cutting/no-colocated-test.mjs +18 -0
  21. package/src/common/cross-cutting/supabase-columns-satisfies.mjs +18 -0
  22. package/src/common/index.mjs +44 -24
  23. package/src/common/layers/constants.mjs +36 -0
  24. package/src/common/layers/entries.mjs +174 -0
  25. package/src/common/layers/lib.mjs +18 -0
  26. package/src/common/layers/queries.mjs +187 -0
  27. package/src/common/layers/schemas.mjs +50 -0
  28. package/src/common/layers/services.mjs +121 -0
  29. package/src/common/layers/top-level-utils.mjs +18 -0
  30. package/src/common/layers/types.mjs +44 -0
  31. package/src/common/layers/utils.mjs +54 -0
  32. package/src/common/local-plugins/entry-single-service-call.mjs +3 -31
  33. package/src/common/local-plugins/entry-template.mjs +51 -88
  34. package/src/common/local-plugins/feature-name.mjs +5 -24
  35. package/src/common/local-plugins/form-state-naming.mjs +1 -11
  36. package/src/common/local-plugins/form-state-shape.mjs +8 -42
  37. package/src/common/local-plugins/import-path-style.mjs +2 -9
  38. package/src/common/local-plugins/index.mjs +2 -1
  39. package/src/common/local-plugins/layout-main-structural-only.mjs +1 -22
  40. package/src/common/local-plugins/namespace-import-name.mjs +1 -27
  41. package/src/common/local-plugins/no-any-return.mjs +1 -9
  42. package/src/common/local-plugins/no-colocated-test.mjs +26 -0
  43. package/src/common/local-plugins/queries-export.mjs +1 -9
  44. package/src/common/local-plugins/queries-namespace-import.mjs +1 -11
  45. package/src/common/local-plugins/schema-naming.mjs +2 -8
  46. package/src/common/local-plugins/supabase-columns-satisfies.mjs +1 -25
  47. package/src/common/local-plugins/supabase-select-typed-columns.mjs +5 -37
  48. package/src/deno/CLAUDE.md +10 -0
  49. package/src/deno/boundaries/entry-point.mjs +44 -0
  50. package/src/deno/boundaries/lib.mjs +28 -0
  51. package/src/deno/boundaries/utils.mjs +25 -0
  52. package/src/deno/index.mjs +9 -13
  53. package/src/deno/local-plugins/flat-entry-point.mjs +1 -6
  54. package/src/deno/local-plugins/index.mjs +0 -1
  55. package/src/next/CLAUDE.md +14 -0
  56. package/src/next/boundaries/components.mjs +36 -0
  57. package/src/next/boundaries/hooks.mjs +36 -0
  58. package/src/next/boundaries/lib.mjs +23 -0
  59. package/src/next/boundaries/page.mjs +36 -0
  60. package/src/next/boundaries/route.mjs +36 -0
  61. package/src/next/boundaries/sitemap.mjs +36 -0
  62. package/src/next/directives.mjs +4 -5
  63. package/src/next/imports.mjs +0 -1
  64. package/src/next/index.mjs +12 -15
  65. package/src/next/layers/components.mjs +30 -0
  66. package/src/next/layers/hooks.mjs +31 -0
  67. package/src/next/layers/layouts.mjs +12 -0
  68. package/src/next/tailwindcss.mjs +2 -23
  69. package/src/node/CLAUDE.md +7 -0
  70. package/src/node/index.mjs +1 -2
  71. package/src/common/imports.mjs +0 -457
  72. package/src/common/layers.mjs +0 -158
  73. package/src/common/naming.mjs +0 -347
  74. package/src/deno/imports.mjs +0 -90
  75. package/src/next/layouts.mjs +0 -18
  76. package/src/next/naming.mjs +0 -60
@@ -0,0 +1,23 @@
1
+ import { featuresGlob } from "../_internal/constants.mjs";
2
+ import { localPlugin } from "../local-plugins/index.mjs";
3
+
4
+ export function createNamespaceImportConfigs({ featureRoot }) {
5
+ return [
6
+ {
7
+ name: "naming/namespace-import-name",
8
+ files: featuresGlob(featureRoot, "**/*.ts"),
9
+ plugins: { local: localPlugin },
10
+ rules: {
11
+ "local/namespace-import-name": ["error", { featureRoot }],
12
+ },
13
+ },
14
+ {
15
+ name: "naming/queries-namespace-import",
16
+ files: featuresGlob(featureRoot, "**/*.ts"),
17
+ plugins: { local: localPlugin },
18
+ rules: {
19
+ "local/queries-namespace-import": "error",
20
+ },
21
+ },
22
+ ];
23
+ }
@@ -0,0 +1,18 @@
1
+ import { localPlugin } from "../local-plugins/index.mjs";
2
+
3
+ export function createNoAnyReturnConfigs({ featureRoot, typeAware }) {
4
+ if (!typeAware) return [];
5
+ return [
6
+ {
7
+ name: "layers/no-any-return",
8
+ files: [
9
+ `${featureRoot}/**/queries/*.ts`,
10
+ `${featureRoot}/**/services/*.ts`,
11
+ ],
12
+ plugins: { local: localPlugin },
13
+ rules: {
14
+ "local/no-any-return": "error",
15
+ },
16
+ },
17
+ ];
18
+ }
@@ -0,0 +1,18 @@
1
+ import { localPlugin } from "../local-plugins/index.mjs";
2
+
3
+ export function createNoColocatedTestConfigs({ featureRoot }) {
4
+ return [
5
+ {
6
+ name: "test/no-colocated-test",
7
+ files: [
8
+ `${featureRoot}/**/services/**/*.test.{ts,tsx}`,
9
+ `${featureRoot}/**/queries/**/*.test.{ts,tsx}`,
10
+ `${featureRoot}/**/entries/**/*.test.{ts,tsx}`,
11
+ ],
12
+ plugins: { local: localPlugin },
13
+ rules: {
14
+ "local/no-colocated-test": "error",
15
+ },
16
+ },
17
+ ];
18
+ }
@@ -0,0 +1,18 @@
1
+ import { featuresGlob } from "../_internal/constants.mjs";
2
+ import { localPlugin } from "../local-plugins/index.mjs";
3
+
4
+ export function createSupabaseColumnsSatisfiesConfigs({ featureRoot }) {
5
+ return [
6
+ {
7
+ name: "naming/supabase-columns-satisfies",
8
+ files: [
9
+ ...featuresGlob(featureRoot, "**/queries/*.ts"),
10
+ ...featuresGlob(featureRoot, "**/constants/*.ts"),
11
+ ],
12
+ plugins: { local: localPlugin },
13
+ rules: {
14
+ "local/supabase-columns-satisfies": "error",
15
+ },
16
+ },
17
+ ];
18
+ }
@@ -1,33 +1,53 @@
1
- import { generatePrefixLibMapping } from "./constants.mjs";
2
- import { createImportsConfigs } from "./imports.mjs";
3
- import { createJsdocConfigs } from "./jsdoc.mjs";
4
- import { createLayersConfigs } from "./layers.mjs";
5
- import { createLibNamingConfigs, createNamingConfigs, createUtilsNamingConfigs } from "./naming.mjs";
6
- import { createRulesConfigs } from "./rules.mjs";
1
+ import { generatePrefixLibMapping } from "./_internal/constants.mjs";
2
+ import { createTypescriptConfigs } from "./base/typescript.mjs";
3
+ import { createBanAliasConfigs } from "./cross-cutting/ban-alias.mjs";
4
+ import { createFeatureDefaultImportsConfigs } from "./cross-cutting/feature-default-imports.mjs";
5
+ import { createFeatureNameConfigs } from "./cross-cutting/feature-name.mjs";
6
+ import { createFeaturesTsOnlyConfigs } from "./cross-cutting/features-ts-only.mjs";
7
+ import { createFormStateConfigs } from "./cross-cutting/form-state.mjs";
8
+ import { createJsdocConfigs } from "./cross-cutting/jsdoc.mjs";
9
+ import { createLoggerConfigs } from "./cross-cutting/logger.mjs";
10
+ import { createNamespaceImportConfigs } from "./cross-cutting/namespace-import.mjs";
11
+ import { createNoAnyReturnConfigs } from "./cross-cutting/no-any-return.mjs";
12
+ import { createNoColocatedTestConfigs } from "./cross-cutting/no-colocated-test.mjs";
13
+ import { createSupabaseColumnsSatisfiesConfigs } from "./cross-cutting/supabase-columns-satisfies.mjs";
14
+ import { createConstantsConfigs } from "./layers/constants.mjs";
15
+ import { createEntriesConfigs } from "./layers/entries.mjs";
16
+ import { createLibLayerConfigs } from "./layers/lib.mjs";
17
+ import { createQueriesConfigs } from "./layers/queries.mjs";
18
+ import { createSchemasConfigs } from "./layers/schemas.mjs";
19
+ import { createServicesConfigs } from "./layers/services.mjs";
20
+ import { createTopLevelUtilsConfigs } from "./layers/top-level-utils.mjs";
21
+ import { createTypesConfigs } from "./layers/types.mjs";
22
+ import { createUtilsConfigs } from "./layers/utils.mjs";
7
23
 
8
- /**
9
- * Build common configs scoped to the given feature root:
10
- *
11
- * - `banAliasImports: true` enforces relative imports inside the feature root
12
- * - `typeAware: false` disables type-aware rules and `local/no-any-return`,
13
- * for environments without a project tsconfig (e.g., Deno entry)
14
- * - `rulesFiles` narrows the parser/rules block. Pass when combining multiple
15
- * entries so each entry only overrides its own files (e.g., the deno entry
16
- * passes `["supabase/functions/**\/*.ts"]` so it doesn't override next's
17
- * parser settings on `src/`).
18
- */
19
24
  export function createCommonConfigs(
20
25
  featureRoot,
21
26
  { banAliasImports = false, typeAware = true, rulesFiles } = {},
22
27
  ) {
23
28
  const prefixLibMapping = generatePrefixLibMapping(featureRoot);
29
+ const ctx = { featureRoot, prefixLibMapping, typeAware };
24
30
  return [
25
- ...createRulesConfigs({ typeAware, ...(rulesFiles && { files: rulesFiles }) }),
26
- ...createNamingConfigs(featureRoot, prefixLibMapping),
27
- ...createLibNamingConfigs(featureRoot),
28
- ...createUtilsNamingConfigs(featureRoot),
29
- ...createLayersConfigs(featureRoot, { typeAware }),
30
- ...createImportsConfigs(featureRoot, prefixLibMapping, { banAliasImports }),
31
- ...createJsdocConfigs(featureRoot),
31
+ ...createTypescriptConfigs({ typeAware, ...(rulesFiles && { files: rulesFiles }) }),
32
+ ...createFeatureNameConfigs(ctx),
33
+ ...createNamespaceImportConfigs(ctx),
34
+ ...createServicesConfigs(ctx),
35
+ ...createQueriesConfigs(ctx),
36
+ ...createFormStateConfigs(ctx),
37
+ ...createSupabaseColumnsSatisfiesConfigs(ctx),
38
+ ...createLibLayerConfigs(ctx),
39
+ ...createTopLevelUtilsConfigs(ctx),
40
+ ...createTypesConfigs(ctx),
41
+ ...createSchemasConfigs(ctx),
42
+ ...createUtilsConfigs(ctx),
43
+ ...createConstantsConfigs(ctx),
44
+ ...createEntriesConfigs(ctx),
45
+ ...createFeaturesTsOnlyConfigs(ctx),
46
+ ...createNoColocatedTestConfigs(ctx),
47
+ ...createLoggerConfigs(ctx),
48
+ ...createNoAnyReturnConfigs(ctx),
49
+ ...createFeatureDefaultImportsConfigs(ctx),
50
+ ...createJsdocConfigs(ctx),
51
+ ...(banAliasImports ? createBanAliasConfigs(ctx) : []),
32
52
  ];
33
53
  }
@@ -0,0 +1,36 @@
1
+ import { featuresGlob } from "../_internal/constants.mjs";
2
+ import { checkFile } from "../_internal/plugins.mjs";
3
+
4
+ export function createConstantsConfigs({ featureRoot, prefixLibMapping }) {
5
+ const prefixes = Object.keys(prefixLibMapping);
6
+ const hasPrefixes = prefixes.length > 0;
7
+ const sharedPrefixPattern = hasPrefixes
8
+ ? `@(shared|${prefixes.join("|")})`
9
+ : "shared";
10
+
11
+ return [
12
+ {
13
+ name: "naming/constants",
14
+ files: featuresGlob(featureRoot, "*/constants/*.ts"),
15
+ ignores: featuresGlob(featureRoot, "shared/constants/*.ts"),
16
+ plugins: { "check-file": checkFile },
17
+ rules: {
18
+ "check-file/filename-naming-convention": [
19
+ "error",
20
+ { "**/*/constants/*.ts": "<1>" },
21
+ ],
22
+ },
23
+ },
24
+ {
25
+ name: "naming/constants-shared",
26
+ files: featuresGlob(featureRoot, "shared/constants/*.ts"),
27
+ plugins: { "check-file": checkFile },
28
+ rules: {
29
+ "check-file/filename-naming-convention": [
30
+ "error",
31
+ { "**/*.ts": sharedPrefixPattern },
32
+ ],
33
+ },
34
+ },
35
+ ];
36
+ }
@@ -0,0 +1,174 @@
1
+ import { featuresGlob } from "../_internal/constants.mjs";
2
+ import {
3
+ LIB_BOUNDARY_PATTERNS,
4
+ MAPPING_PATTERNS,
5
+ } from "../_internal/import-patterns.mjs";
6
+ import { checkFile } from "../_internal/plugins.mjs";
7
+ import {
8
+ aliasDynamicImportMessage,
9
+ aliasDynamicImportSelector,
10
+ } from "../_internal/selectors.mjs";
11
+ import { localPlugin } from "../local-plugins/index.mjs";
12
+
13
+ const LAYER_PATTERNS = [
14
+ {
15
+ group: ["**/queries/*", "**/queries"],
16
+ message:
17
+ "entries は queries を import 不可。queries は service 経由で使う。",
18
+ },
19
+ {
20
+ group: ["**/hooks/*", "**/hooks"],
21
+ message: "entries は hooks を import 不可。依存は単方向に保つ。",
22
+ },
23
+ ];
24
+
25
+ const LATERAL_PATTERNS = [
26
+ {
27
+ group: ["@/features/*/entries/*", "@/features/*/entries"],
28
+ message: "他 feature の entries は import 不可。feature を跨ぐ依存は禁止。",
29
+ },
30
+ {
31
+ group: [
32
+ "@/features/*/services/*",
33
+ "@/features/*/services",
34
+ "!@/features/shared/services/*",
35
+ "!@/features/shared/services",
36
+ ],
37
+ message:
38
+ "他 feature の services は import 不可:\n" +
39
+ "- 同一 feature の service を 1:1 で使うか、orchestration を service 層へ移す\n" +
40
+ "- `shared/services/*` は横断的な副作用 (通知等) のため例外",
41
+ },
42
+ ];
43
+
44
+ const CARDINALITY_PATTERNS = {
45
+ server: [
46
+ {
47
+ group: ["**/services/client", "**/services/admin"],
48
+ message:
49
+ "server entry は server service のみ import 可。context を跨ぐ呼び出しは禁止。",
50
+ },
51
+ ],
52
+ client: [
53
+ {
54
+ group: ["**/services/server", "**/services/admin"],
55
+ message:
56
+ "client entry は client service のみ import 可。context を跨ぐ呼び出しは禁止。",
57
+ },
58
+ ],
59
+ admin: [
60
+ {
61
+ group: ["**/services/server", "**/services/client"],
62
+ message:
63
+ "admin entry は admin service のみ import 可。context を跨ぐ呼び出しは禁止。",
64
+ },
65
+ ],
66
+ };
67
+
68
+ export function createEntriesConfigs({ featureRoot, prefixLibMapping }) {
69
+ const prefixes = Object.keys(prefixLibMapping);
70
+ const hasPrefixes = prefixes.length > 0;
71
+ const prefixPattern = hasPrefixes ? `@(${prefixes.join("|")})` : "*";
72
+ const sharedPrefixPattern = hasPrefixes
73
+ ? `@(shared|${prefixes.join("|")})`
74
+ : "shared";
75
+
76
+ const configs = [
77
+ {
78
+ name: "naming/entries",
79
+ files: featuresGlob(featureRoot, "**/entries/*.ts"),
80
+ ignores: [
81
+ ...featuresGlob(featureRoot, "shared/entries/*.ts"),
82
+ "**/*.test.ts",
83
+ ],
84
+ plugins: { "check-file": checkFile },
85
+ rules: {
86
+ "check-file/filename-naming-convention": [
87
+ "error",
88
+ { "**/*.ts": prefixPattern },
89
+ ],
90
+ },
91
+ },
92
+ {
93
+ name: "naming/entries-shared",
94
+ files: featuresGlob(featureRoot, "shared/entries/*.ts"),
95
+ ignores: ["**/*.test.ts"],
96
+ plugins: { "check-file": checkFile },
97
+ rules: {
98
+ "check-file/filename-naming-convention": [
99
+ "error",
100
+ { "**/*.ts": sharedPrefixPattern },
101
+ ],
102
+ },
103
+ },
104
+ {
105
+ name: "naming/entry-template",
106
+ files: featuresGlob(featureRoot, "**/entries/*.ts"),
107
+ plugins: { local: localPlugin },
108
+ rules: {
109
+ "local/entry-template": "error",
110
+ },
111
+ },
112
+ {
113
+ name: "naming/entry-single-service-call",
114
+ files: featuresGlob(featureRoot, "**/entries/*.ts"),
115
+ plugins: { local: localPlugin },
116
+ rules: {
117
+ "local/entry-single-service-call": "error",
118
+ },
119
+ },
120
+ {
121
+ name: "layers/entries",
122
+ files: [`${featureRoot}/**/entries/*.ts`],
123
+ rules: {
124
+ "no-restricted-syntax": [
125
+ "error",
126
+ {
127
+ selector: aliasDynamicImportSelector,
128
+ message: aliasDynamicImportMessage,
129
+ },
130
+ ],
131
+ },
132
+ },
133
+ {
134
+ name: "imports/entries",
135
+ files: [`${featureRoot}/**/entries/*.ts`],
136
+ rules: {
137
+ "no-restricted-imports": [
138
+ "error",
139
+ {
140
+ patterns: [
141
+ ...LAYER_PATTERNS,
142
+ ...LATERAL_PATTERNS,
143
+ ...LIB_BOUNDARY_PATTERNS,
144
+ ...MAPPING_PATTERNS,
145
+ ],
146
+ },
147
+ ],
148
+ },
149
+ },
150
+ ];
151
+
152
+ for (const prefix of ["server", "client", "admin"]) {
153
+ configs.push({
154
+ name: `imports/entries/${prefix}`,
155
+ files: [`${featureRoot}/**/entries/${prefix}.ts`],
156
+ rules: {
157
+ "no-restricted-imports": [
158
+ "error",
159
+ {
160
+ patterns: [
161
+ ...LAYER_PATTERNS,
162
+ ...LATERAL_PATTERNS,
163
+ ...CARDINALITY_PATTERNS[prefix],
164
+ ...LIB_BOUNDARY_PATTERNS,
165
+ ...MAPPING_PATTERNS,
166
+ ],
167
+ },
168
+ ],
169
+ },
170
+ });
171
+ }
172
+
173
+ return configs;
174
+ }
@@ -0,0 +1,18 @@
1
+ import { checkFile } from "../_internal/plugins.mjs";
2
+
3
+ export function createLibLayerConfigs({ featureRoot }) {
4
+ const libRoot = featureRoot.replace(/features$/, "lib");
5
+ return [
6
+ {
7
+ name: "naming/lib",
8
+ files: [`${libRoot}/**/*.ts`],
9
+ plugins: { "check-file": checkFile },
10
+ rules: {
11
+ "check-file/filename-naming-convention": [
12
+ "error",
13
+ { "**/*.ts": "*" },
14
+ ],
15
+ },
16
+ },
17
+ ];
18
+ }
@@ -0,0 +1,187 @@
1
+ import { featuresGlob } from "../_internal/constants.mjs";
2
+ import { MAPPING_PATTERNS } from "../_internal/import-patterns.mjs";
3
+ import { checkFile } from "../_internal/plugins.mjs";
4
+ import {
5
+ aliasDynamicImportMessage,
6
+ aliasDynamicImportSelector,
7
+ loggerMessage,
8
+ loggerSelector,
9
+ } from "../_internal/selectors.mjs";
10
+ import { localPlugin } from "../local-plugins/index.mjs";
11
+
12
+ const LAYER_PATTERNS = [
13
+ {
14
+ group: ["**/services/*", "**/services"],
15
+ message: "queries は services を import 不可。ロジックは services へ。",
16
+ },
17
+ {
18
+ group: ["**/entries/*", "**/entries"],
19
+ message: "queries は entries を import 不可。依存は単方向に保つ。",
20
+ },
21
+ {
22
+ group: ["**/hooks/*", "**/hooks"],
23
+ message: "queries は hooks を import 不可。依存は単方向に保つ。",
24
+ },
25
+ ];
26
+
27
+ const LATERAL_PATTERNS = [
28
+ {
29
+ group: ["@/features/*/queries/*", "@/features/*/queries"],
30
+ message:
31
+ "他 feature の queries は import 不可。feature を跨ぐ依存は禁止。",
32
+ },
33
+ ];
34
+
35
+ function prefixLibPatterns(prefix, mapping) {
36
+ const prefixes = Object.keys(mapping);
37
+ const allowedLib = mapping[prefix];
38
+ return prefixes
39
+ .filter((p) => p !== prefix)
40
+ .map((p) => ({
41
+ group: [`**/lib/${mapping[p]}`, `**/lib/${mapping[p]}/*`],
42
+ message: `queries/${prefix}.ts は lib/${allowedLib} のみ import 可。lib ごとに対応する query file を使う。`,
43
+ }));
44
+ }
45
+
46
+ export function createQueriesConfigs({ featureRoot, prefixLibMapping }) {
47
+ const prefixes = Object.keys(prefixLibMapping);
48
+ const hasPrefixes = prefixes.length > 0;
49
+ const prefixPattern = hasPrefixes ? `@(${prefixes.join("|")})` : "*";
50
+ const sharedPrefixPattern = hasPrefixes
51
+ ? `@(shared|${prefixes.join("|")})`
52
+ : "shared";
53
+
54
+ const configs = [
55
+ {
56
+ name: "naming/queries",
57
+ files: featuresGlob(featureRoot, "**/queries/*.ts"),
58
+ ignores: [
59
+ ...featuresGlob(featureRoot, "shared/queries/*.ts"),
60
+ "**/*.test.ts",
61
+ ],
62
+ plugins: { "check-file": checkFile },
63
+ rules: {
64
+ "check-file/filename-naming-convention": [
65
+ "error",
66
+ { "**/*.ts": prefixPattern },
67
+ ],
68
+ },
69
+ },
70
+ {
71
+ name: "naming/queries-shared",
72
+ files: featuresGlob(featureRoot, "shared/queries/*.ts"),
73
+ ignores: ["**/*.test.ts"],
74
+ plugins: { "check-file": checkFile },
75
+ rules: {
76
+ "check-file/filename-naming-convention": [
77
+ "error",
78
+ { "**/*.ts": sharedPrefixPattern },
79
+ ],
80
+ },
81
+ },
82
+ {
83
+ name: "naming/queries-export",
84
+ files: featuresGlob(featureRoot, "**/queries/*.ts"),
85
+ plugins: { local: localPlugin },
86
+ rules: {
87
+ "local/queries-export": "error",
88
+ },
89
+ },
90
+ {
91
+ name: "naming/supabase-select",
92
+ files: featuresGlob(featureRoot, "**/queries/*.ts"),
93
+ plugins: { local: localPlugin },
94
+ rules: {
95
+ "local/supabase-select-typed-columns": "error",
96
+ },
97
+ },
98
+ {
99
+ name: "layers/queries",
100
+ files: [`${featureRoot}/**/queries/*.ts`],
101
+ rules: {
102
+ "no-restricted-syntax": [
103
+ "error",
104
+ {
105
+ selector: "TryStatement",
106
+ message:
107
+ "queries では try-catch 禁止。エラーは `{ data, error }` で返す。",
108
+ },
109
+ {
110
+ selector: "IfStatement",
111
+ message:
112
+ "queries で if 文は禁止。条件分岐は services に置く。",
113
+ },
114
+ {
115
+ selector: "ForStatement",
116
+ message:
117
+ "queries でループは禁止。queries は薄い CRUD ラッパー、反復は services に置く。",
118
+ },
119
+ {
120
+ selector: "ForOfStatement",
121
+ message:
122
+ "queries でループは禁止。queries は薄い CRUD ラッパー、反復は services に置く。",
123
+ },
124
+ {
125
+ selector: "ForInStatement",
126
+ message:
127
+ "queries でループは禁止。queries は薄い CRUD ラッパー、反復は services に置く。",
128
+ },
129
+ {
130
+ selector: "WhileStatement",
131
+ message:
132
+ "queries でループは禁止。queries は薄い CRUD ラッパー、反復は services に置く。",
133
+ },
134
+ {
135
+ selector: "DoWhileStatement",
136
+ message:
137
+ "queries でループは禁止。queries は薄い CRUD ラッパー、反復は services に置く。",
138
+ },
139
+ {
140
+ selector: "ThrowStatement",
141
+ message:
142
+ "queries で throw は禁止。Supabase の `{ data, error }` をそのまま返す。",
143
+ },
144
+ { selector: loggerSelector, message: loggerMessage },
145
+ {
146
+ selector: aliasDynamicImportSelector,
147
+ message: aliasDynamicImportMessage,
148
+ },
149
+ ],
150
+ },
151
+ },
152
+ {
153
+ name: "imports/queries",
154
+ files: [`${featureRoot}/**/queries/*.ts`],
155
+ rules: {
156
+ "no-restricted-imports": [
157
+ "error",
158
+ { patterns: [...LAYER_PATTERNS, ...LATERAL_PATTERNS, ...MAPPING_PATTERNS] },
159
+ ],
160
+ },
161
+ },
162
+ ];
163
+
164
+ for (const prefix of prefixes) {
165
+ const patterns = prefixLibPatterns(prefix, prefixLibMapping);
166
+ if (patterns.length === 0) continue;
167
+ configs.push({
168
+ name: `imports/queries/${prefix}`,
169
+ files: [`${featureRoot}/**/queries/${prefix}.ts`],
170
+ rules: {
171
+ "no-restricted-imports": [
172
+ "error",
173
+ {
174
+ patterns: [
175
+ ...LAYER_PATTERNS,
176
+ ...LATERAL_PATTERNS,
177
+ ...patterns,
178
+ ...MAPPING_PATTERNS,
179
+ ],
180
+ },
181
+ ],
182
+ },
183
+ });
184
+ }
185
+
186
+ return configs;
187
+ }
@@ -0,0 +1,50 @@
1
+ import { featuresGlob } from "../_internal/constants.mjs";
2
+ import { checkFile } from "../_internal/plugins.mjs";
3
+ import { localPlugin } from "../local-plugins/index.mjs";
4
+
5
+ export function createSchemasConfigs({ featureRoot, prefixLibMapping }) {
6
+ const prefixes = Object.keys(prefixLibMapping);
7
+ const hasPrefixes = prefixes.length > 0;
8
+ const sharedPrefixPattern = hasPrefixes
9
+ ? `@(shared|${prefixes.join("|")})`
10
+ : "shared";
11
+
12
+ return [
13
+ {
14
+ name: "naming/schemas",
15
+ files: featuresGlob(featureRoot, "*/schemas/*.ts"),
16
+ ignores: [
17
+ ...featuresGlob(featureRoot, "shared/schemas/*.ts"),
18
+ "**/*.test.ts",
19
+ ],
20
+ plugins: { "check-file": checkFile },
21
+ rules: {
22
+ "check-file/filename-naming-convention": [
23
+ "error",
24
+ { "**/*/schemas/*.ts": "<1>" },
25
+ ],
26
+ },
27
+ },
28
+ {
29
+ name: "naming/schemas-shared",
30
+ files: featuresGlob(featureRoot, "shared/schemas/*.ts"),
31
+ ignores: ["**/*.test.ts"],
32
+ plugins: { "check-file": checkFile },
33
+ rules: {
34
+ "check-file/filename-naming-convention": [
35
+ "error",
36
+ { "**/*.ts": sharedPrefixPattern },
37
+ ],
38
+ },
39
+ },
40
+ {
41
+ name: "naming/schema-naming",
42
+ files: featuresGlob(featureRoot, "**/schemas/*.ts"),
43
+ ignores: ["**/*.test.ts"],
44
+ plugins: { local: localPlugin },
45
+ rules: {
46
+ "local/schema-naming": "error",
47
+ },
48
+ },
49
+ ];
50
+ }