@yasainet/eslint 0.0.74 → 0.0.76

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 (52) hide show
  1. package/README.md +4 -104
  2. package/package.json +12 -1
  3. package/src/cli/test-audit.mjs +97 -0
  4. package/src/common/CLAUDE.md +19 -0
  5. package/src/common/_internal/constants.mjs +1 -1
  6. package/src/common/_internal/import-patterns.mjs +2 -2
  7. package/src/common/_internal/selectors.mjs +4 -2
  8. package/src/common/base/typescript.mjs +13 -7
  9. package/src/common/boundaries/entry-point.mjs +1 -1
  10. package/src/common/cross-cutting/ban-alias.mjs +1 -1
  11. package/src/common/cross-cutting/features-ts-only.mjs +1 -1
  12. package/src/common/cross-cutting/no-colocated-test.mjs +18 -0
  13. package/src/common/index.mjs +8 -4
  14. package/src/common/layers/entries.mjs +15 -9
  15. package/src/common/layers/queries.mjs +18 -14
  16. package/src/common/layers/schemas.mjs +6 -1
  17. package/src/common/layers/services.mjs +14 -8
  18. package/src/common/layers/{lib.mjs → top-level/lib.mjs} +3 -3
  19. package/src/common/layers/{top-level-utils.mjs → top-level/utils.mjs} +1 -1
  20. package/src/common/layers/utils.mjs +5 -1
  21. package/src/common/local-plugins/entry-single-service-call.mjs +3 -1
  22. package/src/common/local-plugins/entry-template.mjs +18 -16
  23. package/src/common/local-plugins/feature-name.mjs +1 -6
  24. package/src/common/local-plugins/form-state-naming.mjs +1 -1
  25. package/src/common/local-plugins/form-state-shape.mjs +8 -8
  26. package/src/common/local-plugins/import-path-style.mjs +2 -2
  27. package/src/common/local-plugins/index.mjs +2 -0
  28. package/src/common/local-plugins/layout-main-structural-only.mjs +1 -1
  29. package/src/common/local-plugins/namespace-import-name.mjs +1 -1
  30. package/src/common/local-plugins/no-any-return.mjs +1 -1
  31. package/src/common/local-plugins/no-colocated-test.mjs +26 -0
  32. package/src/common/local-plugins/queries-export.mjs +1 -1
  33. package/src/common/local-plugins/queries-namespace-import.mjs +1 -1
  34. package/src/common/local-plugins/schema-naming.mjs +2 -2
  35. package/src/common/local-plugins/supabase-columns-satisfies.mjs +1 -1
  36. package/src/common/local-plugins/supabase-select-typed-columns.mjs +5 -5
  37. package/src/deno/CLAUDE.md +10 -0
  38. package/src/deno/boundaries/entry-point.mjs +3 -3
  39. package/src/deno/boundaries/lib.mjs +1 -1
  40. package/src/deno/boundaries/utils.mjs +2 -2
  41. package/src/deno/local-plugins/flat-entry-point.mjs +1 -1
  42. package/src/next/CLAUDE.md +14 -0
  43. package/src/next/boundaries/components.mjs +2 -2
  44. package/src/next/boundaries/hooks.mjs +2 -2
  45. package/src/next/boundaries/page.mjs +2 -2
  46. package/src/next/boundaries/route.mjs +2 -2
  47. package/src/next/boundaries/sitemap.mjs +2 -2
  48. package/src/next/directives.mjs +4 -4
  49. package/src/next/layers/components.mjs +1 -1
  50. package/src/next/layers/hooks.mjs +1 -1
  51. package/src/next/tailwindcss.mjs +2 -2
  52. package/src/node/CLAUDE.md +7 -0
@@ -13,7 +13,10 @@ export function createSchemasConfigs({ featureRoot, prefixLibMapping }) {
13
13
  {
14
14
  name: "naming/schemas",
15
15
  files: featuresGlob(featureRoot, "*/schemas/*.ts"),
16
- ignores: featuresGlob(featureRoot, "shared/schemas/*.ts"),
16
+ ignores: [
17
+ ...featuresGlob(featureRoot, "shared/schemas/*.ts"),
18
+ "**/*.test.ts",
19
+ ],
17
20
  plugins: { "check-file": checkFile },
18
21
  rules: {
19
22
  "check-file/filename-naming-convention": [
@@ -25,6 +28,7 @@ export function createSchemasConfigs({ featureRoot, prefixLibMapping }) {
25
28
  {
26
29
  name: "naming/schemas-shared",
27
30
  files: featuresGlob(featureRoot, "shared/schemas/*.ts"),
31
+ ignores: ["**/*.test.ts"],
28
32
  plugins: { "check-file": checkFile },
29
33
  rules: {
30
34
  "check-file/filename-naming-convention": [
@@ -36,6 +40,7 @@ export function createSchemasConfigs({ featureRoot, prefixLibMapping }) {
36
40
  {
37
41
  name: "naming/schema-naming",
38
42
  files: featuresGlob(featureRoot, "**/schemas/*.ts"),
43
+ ignores: ["**/*.test.ts"],
39
44
  plugins: { local: localPlugin },
40
45
  rules: {
41
46
  "local/schema-naming": "error",
@@ -11,11 +11,11 @@ import {
11
11
  const LAYER_PATTERNS = [
12
12
  {
13
13
  group: ["**/entries/*", "**/entries"],
14
- message: "services cannot import entries (layer violation)",
14
+ message: "services entries import 不可。依存は単方向に保つ。",
15
15
  },
16
16
  {
17
17
  group: ["**/hooks/*", "**/hooks"],
18
- message: "services cannot import hooks (layer violation)",
18
+ message: "services hooks import 不可。依存は単方向に保つ。",
19
19
  },
20
20
  ];
21
21
 
@@ -23,7 +23,7 @@ const LATERAL_PATTERNS = [
23
23
  {
24
24
  group: ["@/features/*/services/*", "@/features/*/services"],
25
25
  message:
26
- "services cannot import other feature's services (lateral violation)",
26
+ "他 feature の services import 不可。feature を跨ぐ依存は禁止。",
27
27
  },
28
28
  ];
29
29
 
@@ -39,7 +39,10 @@ export function createServicesConfigs({ featureRoot, prefixLibMapping }) {
39
39
  {
40
40
  name: "naming/services",
41
41
  files: featuresGlob(featureRoot, "**/services/*.ts"),
42
- ignores: featuresGlob(featureRoot, "shared/services/*.ts"),
42
+ ignores: [
43
+ ...featuresGlob(featureRoot, "shared/services/*.ts"),
44
+ "**/*.test.ts",
45
+ ],
43
46
  plugins: { "check-file": checkFile },
44
47
  rules: {
45
48
  "check-file/filename-naming-convention": [
@@ -51,6 +54,7 @@ export function createServicesConfigs({ featureRoot, prefixLibMapping }) {
51
54
  {
52
55
  name: "naming/services-shared",
53
56
  files: featuresGlob(featureRoot, "shared/services/*.ts"),
57
+ ignores: ["**/*.test.ts"],
54
58
  plugins: { "check-file": checkFile },
55
59
  rules: {
56
60
  "check-file/filename-naming-convention": [
@@ -68,25 +72,27 @@ export function createServicesConfigs({ featureRoot, prefixLibMapping }) {
68
72
  {
69
73
  selector: "TryStatement",
70
74
  message:
71
- "try-catch is not allowed in services. Error handling belongs in entries.",
75
+ "services で try-catch は禁止。エラー処理は entries に集約する。",
72
76
  },
73
77
  {
74
78
  selector: "ThrowStatement",
75
79
  message:
76
- "throw is not allowed in services. Communicate failures via T | null / { data, error } / empty default. Native exceptions from libs auto-propagate to entry's catch.",
80
+ "services throw は禁止。失敗は値で返す:\n" +
81
+ "- `T | null` / `{ data, error }` / 空デフォルトのいずれか\n" +
82
+ "- lib の native 例外は entry の catch に自動伝播する",
77
83
  },
78
84
  { selector: loggerSelector, message: loggerMessage },
79
85
  {
80
86
  selector:
81
87
  "LogicalExpression[operator='??'][left.type='ChainExpression'][left.expression.property.name='message'][right.type='Literal']",
82
88
  message:
83
- "Dead fallback for error message. If you reached this branch the error is known return the error directly. Unhandled exceptions belong in entries.",
89
+ "error message dead fallback。この分岐に来た時点で error は既知 — error をそのまま返す。",
84
90
  },
85
91
  {
86
92
  selector:
87
93
  "LogicalExpression[operator='??'][left.type='MemberExpression'][left.property.name='error'][right.type='ObjectExpression']",
88
94
  message:
89
- "Dead fallback for nullable error. Check `if (error)` and return the error directly. Unhandled exceptions belong in entries.",
95
+ "nullable error dead fallback。`if (error)` で判定し error をそのまま返す。",
90
96
  },
91
97
  {
92
98
  selector: aliasDynamicImportSelector,
@@ -1,10 +1,10 @@
1
- import { checkFile } from "../_internal/plugins.mjs";
1
+ import { checkFile } from "../../_internal/plugins.mjs";
2
2
 
3
- export function createLibLayerConfigs({ featureRoot }) {
3
+ export function createTopLevelLibConfigs({ featureRoot }) {
4
4
  const libRoot = featureRoot.replace(/features$/, "lib");
5
5
  return [
6
6
  {
7
- name: "naming/lib",
7
+ name: "naming/top-level-lib",
8
8
  files: [`${libRoot}/**/*.ts`],
9
9
  plugins: { "check-file": checkFile },
10
10
  rules: {
@@ -1,4 +1,4 @@
1
- import { checkFile } from "../_internal/plugins.mjs";
1
+ import { checkFile } from "../../_internal/plugins.mjs";
2
2
 
3
3
  export function createTopLevelUtilsConfigs({ featureRoot }) {
4
4
  const utilsRoot = featureRoot.replace(/features$/, "utils");
@@ -16,7 +16,10 @@ export function createUtilsConfigs({ featureRoot, prefixLibMapping }) {
16
16
  {
17
17
  name: "naming/utils",
18
18
  files: featuresGlob(featureRoot, "*/utils/*.ts"),
19
- ignores: featuresGlob(featureRoot, "shared/utils/*.ts"),
19
+ ignores: [
20
+ ...featuresGlob(featureRoot, "shared/utils/*.ts"),
21
+ "**/*.test.ts",
22
+ ],
20
23
  plugins: { "check-file": checkFile },
21
24
  rules: {
22
25
  "check-file/filename-naming-convention": [
@@ -28,6 +31,7 @@ export function createUtilsConfigs({ featureRoot, prefixLibMapping }) {
28
31
  {
29
32
  name: "naming/utils-shared",
30
33
  files: featuresGlob(featureRoot, "shared/utils/*.ts"),
34
+ ignores: ["**/*.test.ts"],
31
35
  plugins: { "check-file": checkFile },
32
36
  rules: {
33
37
  "check-file/filename-naming-convention": [
@@ -39,7 +39,9 @@ export const entrySingleServiceCallRule = {
39
39
  },
40
40
  messages: {
41
41
  multipleServiceCalls:
42
- "entry '{{ funcName }}' calls more than one feature service ({{ count }} total). entries must be a thin wrapper that calls a single service. Move orchestration into the service layer. `shared/services/*` (e.g. `sharedDiscordService`) is exempt.",
42
+ "entry '{{ funcName }}' が複数の feature service を呼んでいる ({{ count }} ):\n" +
43
+ "- entry は単一 service を呼ぶ薄いラッパー、orchestration は service 層へ移す\n" +
44
+ "- `shared/services/*` (例 `sharedDiscordService`) は例外",
43
45
  },
44
46
  schema: [],
45
47
  },
@@ -485,35 +485,37 @@ export const entryTemplateRule = {
485
485
  },
486
486
  messages: {
487
487
  bodyNotTryCatch:
488
- "entry '{{ funcName }}' body must be either a single try/catch (Pattern A) or a try/catch followed by a terminal navigation call such as `redirect(...)` / `notFound(...)` (Pattern B).",
489
- tryEmpty: "entry '{{ funcName }}' try block is empty.",
488
+ "entry '{{ funcName }}' body は次のいずれか:\n" +
489
+ "- 単一の try/catch (Pattern A)\n" +
490
+ "- try/catch + 末尾の navigation 呼び出し `redirect(...)` / `notFound(...)` (Pattern B)",
491
+ tryEmpty: "entry '{{ funcName }}' の try block が空。",
490
492
  tryMissingStartLog:
491
- "entry '{{ funcName }}' try block must start with `logger.info(<obj>, \"Start {{ funcName }}\")`.",
493
+ "entry '{{ funcName }}' try block `logger.info(<obj>, \"Start {{ funcName }}\")` で始める。",
492
494
  trySuccessLogMissing:
493
- "entry '{{ funcName }}' success return must be preceded by `logger.info(<obj>, \"Success {{ funcName }}\")`.",
495
+ "entry '{{ funcName }}' success return の直前に `logger.info(<obj>, \"Success {{ funcName }}\")` が必須。",
494
496
  trySuccessReturnMissing:
495
- "entry '{{ funcName }}' must contain a success return `return { data, error: null }`.",
497
+ "entry '{{ funcName }}' success return `return { data, error: null }` が必須。",
496
498
  failedLogMissing:
497
- "entry '{{ funcName }}' Failed branch must call `logger.error(<obj>, \"Failed {{ funcName }}\")` before return.",
499
+ "entry '{{ funcName }}' Failed 分岐は return 前に `logger.error(<obj>, \"Failed {{ funcName }}\")` を呼ぶ。",
498
500
  catchParamWrongType:
499
- "entry '{{ funcName }}' catch param must be `error: unknown`.",
500
- catchEmpty: "entry '{{ funcName }}' catch block is empty.",
501
+ "entry '{{ funcName }}' catch param `error: unknown`。",
502
+ catchEmpty: "entry '{{ funcName }}' catch block が空。",
501
503
  catchMissingErrorLog:
502
- "entry '{{ funcName }}' catch block must start with `logger.error(<obj>, \"Unexpected error in {{ funcName }}\")`.",
504
+ "entry '{{ funcName }}' catch block `logger.error(<obj>, \"Unexpected error in {{ funcName }}\")` で始める。",
503
505
  catchLastNotReturn:
504
- "entry '{{ funcName }}' catch block must end with a return statement.",
506
+ "entry '{{ funcName }}' catch block return 文で終える。",
505
507
  catchWrongReturnMessage:
506
- "entry '{{ funcName }}' catch return error.message must be the literal '{{ expected }}'. Got: '{{ actual }}'.",
508
+ "entry '{{ funcName }}' catch return error.message はリテラル '{{ expected }}'。実際: '{{ actual }}'",
507
509
  logWrongCallShape:
508
- "{{ where }} log in '{{ funcName }}' must be `logger.{{ expectedLevel }}(<obj>, \"{{ expectedMessage }}\")`.",
510
+ "'{{ funcName }}' {{ where }} log `logger.{{ expectedLevel }}(<obj>, \"{{ expectedMessage }}\")`。",
509
511
  logWrongMessage:
510
- "{{ where }} log message must be '{{ expectedMessage }}'. Got: '{{ actual }}'.",
512
+ "{{ where }} log message '{{ expectedMessage }}'。実際: '{{ actual }}'",
511
513
  logFirstArgNotObject:
512
- "{{ where }} log in '{{ funcName }}' first argument must be an object literal.",
514
+ "'{{ funcName }}' {{ where }} log の第 1 引数は object literal にする。",
513
515
  logErrKeyNotFirst:
514
- "{{ where }} log in '{{ funcName }}' object must start with `err:` key.",
516
+ "'{{ funcName }}' {{ where }} log object `err:` キーで始める。",
515
517
  logMissingInputArg:
516
- "{{ where }} log in '{{ funcName }}' is missing input arg '{{ argName }}'. All function inputs must propagate to log objects.",
518
+ "'{{ funcName }}' {{ where }} log に入力引数 '{{ argName }}' が無い。全ての関数入力を log object に伝播する。",
517
519
  },
518
520
  schema: [],
519
521
  },
@@ -66,7 +66,7 @@ export const featureNameRule = {
66
66
  type: "problem",
67
67
  messages: {
68
68
  invalidFeatureName:
69
- "Feature directory '{{ name }}' is not allowed. Allowed: {{ allowed }}.",
69
+ "feature directory '{{ name }}' は許可されない。許可: {{ allowed }}",
70
70
  },
71
71
  schema: [
72
72
  {
@@ -93,15 +93,10 @@ export const featureNameRule = {
93
93
 
94
94
  const projectRoot = filename.slice(0, rootIdx).replace(/\/src$/, "");
95
95
  const candidateTypePaths = [
96
- path.join(
97
- projectRoot,
98
- featureRoot.replace(/features$/, "lib/supabase/types.ts"),
99
- ),
100
96
  path.join(
101
97
  projectRoot,
102
98
  featureRoot.replace(/features$/, "lib/supabase/type.ts"),
103
99
  ),
104
- path.join(projectRoot, "src/lib/supabase/types.ts"),
105
100
  path.join(projectRoot, "src/lib/supabase/type.ts"),
106
101
  ];
107
102
  const supabaseTypePath =
@@ -16,7 +16,7 @@ export const formStateNamingRule = {
16
16
  type: "problem",
17
17
  messages: {
18
18
  invalidName:
19
- "FormState type '{{ name }}' must follow {Verb}{Subject}FormState pattern (e.g. CreateCommentFormState, SignInFormState). At least two PascalCase words are required.",
19
+ "FormState '{{ name }}' {Verb}{Subject}FormState 形式にする ( CreateCommentFormState, SignInFormState)PascalCase 2 語以上が必須。",
20
20
  },
21
21
  schema: [],
22
22
  },
@@ -134,21 +134,21 @@ export const formStateShapeRule = {
134
134
  },
135
135
  messages: {
136
136
  dataMissing:
137
- "FormState '{{ name }}' must have a `data` property (use `data: null` if there is no payload).",
137
+ "FormState '{{ name }}' `data` プロパティが必須 (payload が無ければ `data: null`)",
138
138
  dataNotNullable:
139
- "FormState '{{ name }}' `data` must allow null (e.g. `data: T | null` or `data: null`).",
139
+ "FormState '{{ name }}' `data` null 許容にする (例: `data: T | null` / `data: null`)",
140
140
  errorMissing:
141
- "FormState '{{ name }}' must have an `error: { message: string } | null` property.",
141
+ "FormState '{{ name }}' `error: { message: string } | null` プロパティが必須。",
142
142
  errorNotNullable:
143
- "FormState '{{ name }}' `error` must be nullable (`{ message: string } | null`).",
143
+ "FormState '{{ name }}' `error` nullable にする (`{ message: string } | null`)",
144
144
  errorWrongShape:
145
- "FormState '{{ name }}' `error` must be exactly `{ message: string } | null`.",
145
+ "FormState '{{ name }}' `error` は厳密に `{ message: string } | null`。",
146
146
  errorExtraField:
147
- "FormState '{{ name }}' `error` object must contain only `message: string`. Forbidden field: '{{ field }}'. See form-state-shape rule docstring for the rationale and the future opt-out plan for Stripe-like cases.",
147
+ "FormState '{{ name }}' `error` `message: string` のみ許可。禁止フィールド: '{{ field }}'",
148
148
  extraProperty:
149
- "FormState '{{ name }}' must contain only `data` and `error`. Forbidden property: '{{ field }}'.",
149
+ "FormState '{{ name }}' `data` `error` のみ。禁止プロパティ: '{{ field }}'",
150
150
  discriminatedUnion:
151
- "FormState '{{ name }}' must be a single interface or type literal, not a discriminated union.",
151
+ "FormState '{{ name }}' は単一の interface type literal にする。discriminated union 不可。",
152
152
  },
153
153
  schema: [],
154
154
  },
@@ -5,9 +5,9 @@ export const importPathStyleRule = {
5
5
  type: "problem",
6
6
  messages: {
7
7
  useRelative:
8
- "Same-feature import must use a relative path instead of '{{ importPath }}'.",
8
+ "同一 feature import は相対パスにする ('{{ importPath }}' を使わない)。",
9
9
  useAlias:
10
- "Cross-feature import must use '@/' instead of relative path '{{ importPath }}'.",
10
+ "feature を跨ぐ import '@/' にする (相対パス '{{ importPath }}' を使わない)。",
11
11
  },
12
12
  schema: [
13
13
  {
@@ -7,6 +7,7 @@ import { importPathStyleRule } from "./import-path-style.mjs";
7
7
  import { layoutMainStructuralOnlyRule } from "./layout-main-structural-only.mjs";
8
8
  import { namespaceImportNameRule } from "./namespace-import-name.mjs";
9
9
  import { noAnyReturnRule } from "./no-any-return.mjs";
10
+ import { noColocatedTestRule } from "./no-colocated-test.mjs";
10
11
  import { queriesExportRule } from "./queries-export.mjs";
11
12
  import { queriesNamespaceImportRule } from "./queries-namespace-import.mjs";
12
13
  import { schemaNamingRule } from "./schema-naming.mjs";
@@ -24,6 +25,7 @@ export const localPlugin = {
24
25
  "layout-main-structural-only": layoutMainStructuralOnlyRule,
25
26
  "namespace-import-name": namespaceImportNameRule,
26
27
  "no-any-return": noAnyReturnRule,
28
+ "no-colocated-test": noColocatedTestRule,
27
29
  "queries-export": queriesExportRule,
28
30
  "queries-namespace-import": queriesNamespaceImportRule,
29
31
  "schema-naming": schemaNamingRule,
@@ -47,7 +47,7 @@ export const layoutMainStructuralOnlyRule = {
47
47
  type: "problem",
48
48
  messages: {
49
49
  invalidToken:
50
- "<main> in layout.tsx must be structural-only. Move spacing/decoration ({{ tokens }}) to page.tsx (e.g. <Container className=\"py-8\">).",
50
+ "layout.tsx <main> は構造のみ。spacing/装飾 ({{ tokens }}) page.tsx へ移す ( <Container className=\"py-8\">)",
51
51
  },
52
52
  schema: [],
53
53
  },
@@ -55,7 +55,7 @@ export const namespaceImportNameRule = {
55
55
  type: "suggestion",
56
56
  messages: {
57
57
  mismatch:
58
- "Namespace import should be named '{{ expected }}' instead of '{{ actual }}'.",
58
+ "namespace import '{{ expected }}' と命名する ('{{ actual }}' ではなく)。",
59
59
  },
60
60
  schema: [
61
61
  {
@@ -9,7 +9,7 @@ export const noAnyReturnRule = {
9
9
  },
10
10
  messages: {
11
11
  anyInReturn:
12
- "Exported function's inferred return type contains `any`: {{ typeText }}. Annotate with a known type or narrow from the source — public layer APIs must have known shapes.",
12
+ "export 関数の推論された返り値型に `any` が含まれる: {{ typeText }}。既知の型を注釈するか絞り込む (public な層の API は型を確定させる)。",
13
13
  },
14
14
  schema: [],
15
15
  },
@@ -0,0 +1,26 @@
1
+ /**
2
+ * orchestration layer (services / queries / entries) での co-located test を禁止する:
3
+ *
4
+ * - これらは Supabase 等への配線で、unit 化すると mock の echo になる
5
+ * - 検証は e2e に委ね、純粋ロジックは utils へ抽出してそちらを unit する
6
+ */
7
+ export const noColocatedTestRule = {
8
+ meta: {
9
+ type: "problem",
10
+ messages: {
11
+ forbidden:
12
+ "orchestration layer (services/queries/entries) に test を置かない。" +
13
+ "mock の echo になる:\n" +
14
+ "- 配線の検証は e2e に委ねる\n" +
15
+ "- 純粋ロジックは utils へ抽出し、そちらを unit する",
16
+ },
17
+ schema: [],
18
+ },
19
+ create(context) {
20
+ return {
21
+ Program(node) {
22
+ context.report({ node, messageId: "forbidden" });
23
+ },
24
+ };
25
+ },
26
+ };
@@ -29,7 +29,7 @@ export const queriesExportRule = {
29
29
  type: "problem",
30
30
  messages: {
31
31
  invalidName:
32
- "queries export '{{ name }}' must start with one of: get, create, update, delete, signUp, signIn, signOut. (Rails 5 actions translated to TS idiom)",
32
+ "queries export '{{ name }}' get, create, update, delete, signUp, signIn, signOut のいずれかで始める。",
33
33
  },
34
34
  schema: [],
35
35
  },
@@ -5,7 +5,7 @@ export const queriesNamespaceImportRule = {
5
5
  type: "problem",
6
6
  messages: {
7
7
  useNamespace:
8
- 'Use `import * as xxxQuery from "{{ source }}"` instead of named imports for queries layer. Type-only imports (`import type {}`) are allowed.',
8
+ 'queries 層は named import でなく `import * as xxxQuery from "{{ source }}"` を使う (`import type {}` は可)',
9
9
  },
10
10
  schema: [],
11
11
  },
@@ -3,9 +3,9 @@ export const schemaNamingRule = {
3
3
  type: "problem",
4
4
  messages: {
5
5
  missingSuffix:
6
- "Exported variable '{{ name }}' in a schema file must end with 'Schema'.",
6
+ "schema file の export 変数 '{{ name }}' 'Schema' で終える。",
7
7
  invalidCasing:
8
- "Exported variable '{{ name }}' must be camelCase (start with a lowercase letter).",
8
+ "export 変数 '{{ name }}' camelCase にする (小文字始まり)",
9
9
  },
10
10
  schema: [],
11
11
  },
@@ -17,7 +17,7 @@ export const supabaseColumnsSatisfiesRule = {
17
17
  type: "problem",
18
18
  messages: {
19
19
  shape:
20
- 'Column constant `{{ name }}` must be `"<comma-separated columns>" as const`. `as const` を外すと Supabase の `.select()` 型推論が壊れる。配列 / template literal も不可。',
20
+ 'column 定数 `{{ name }}` `"<comma-separated columns>" as const` にする。`as const` を外すと Supabase の `.select()` 型推論が壊れる。配列 / template literal も不可。',
21
21
  },
22
22
  schema: [],
23
23
  },
@@ -5,15 +5,15 @@ export const supabaseSelectTypedColumnsRule = {
5
5
  type: "problem",
6
6
  messages: {
7
7
  noArgs:
8
- "Empty `.select()` returns all columns implicitly. Pass a string literal or a `*_COLUMNS` constant.",
8
+ "空の `.select()` は全列を暗黙取得する。文字列リテラルか `*_COLUMNS` 定数を渡す。",
9
9
  wildcard:
10
- '`.select("*")` exposes new schema columns silently. Enumerate columns explicitly.',
10
+ '`.select("*")` はスキーマ拡張時に列を暗黙露出する。列を明示列挙する。',
11
11
  template:
12
- "Template literal in `.select()` defeats type inference. Use a string literal or a `*_COLUMNS` constant.",
12
+ "`.select()` template literal は型推論を壊す。文字列リテラルか `*_COLUMNS` 定数を使う。",
13
13
  shapeArg:
14
- "`.select()` argument must be a string literal or a `*_COLUMNS` identifier.",
14
+ "`.select()` の引数は文字列リテラルか `*_COLUMNS` 識別子にする。",
15
15
  naming:
16
- "Column constant `{{ name }}` must be UPPER_SNAKE_CASE ending with `_COLUMNS` (e.g. POST_DETAIL_COLUMNS).",
16
+ "column 定数 `{{ name }}` `_COLUMNS` で終わる UPPER_SNAKE_CASE にする ( POST_DETAIL_COLUMNS)",
17
17
  },
18
18
  schema: [],
19
19
  },
@@ -0,0 +1,10 @@
1
+ # src/deno/CLAUDE.md
2
+
3
+ Supabase Edge Functions (Deno) 固有 rule の置き場所判断:
4
+
5
+ - `boundaries/<surface>.mjs` — Deno 固有の boundary (外界 → features の入口)
6
+ - 種類: lib / utils / entry-point
7
+ - `local-plugins/` — Deno 固有の local plugin
8
+ - `index.mjs` — Deno entry。common の rule + 上記 file を合成
9
+
10
+ Deno entry 横断の共通 rule は `src/common/` に追加する。
@@ -15,17 +15,17 @@ export const denoEntryPointConfigs = [
15
15
  {
16
16
  group: ["**/services/*", "**/services"],
17
17
  message:
18
- "Top-level files must not import services directly. Import from entries instead.",
18
+ "top-level file services を直接 import 不可。entries 経由で使う。",
19
19
  },
20
20
  {
21
21
  group: ["**/queries/*", "**/queries"],
22
22
  message:
23
- "Top-level files must not import queries directly. Import from entries instead.",
23
+ "top-level file queries を直接 import 不可。entries 経由で使う。",
24
24
  },
25
25
  {
26
26
  group: ["*/_lib/*", "*/_lib/**"],
27
27
  message:
28
- "Top-level files must not import _lib/ directly. Import from entries instead.",
28
+ "top-level file _lib/ を直接 import 不可。entries 経由で使う。",
29
29
  },
30
30
  ],
31
31
  },
@@ -18,7 +18,7 @@ export const denoLibBoundaryConfigs = [
18
18
  {
19
19
  group: ["*/_lib/*", "*/_lib/**"],
20
20
  message:
21
- "_lib/ can only be imported from queries (lib-boundary violation)",
21
+ "_lib/ queries からのみ import 可。他層は queries 経由で使う。",
22
22
  },
23
23
  ],
24
24
  },
@@ -11,11 +11,11 @@ export const denoUtilsBoundaryConfigs = [
11
11
  patterns: [
12
12
  {
13
13
  group: ["*/_features/*", "*/_features/**"],
14
- message: "_utils/ cannot import _features/",
14
+ message: "_utils/ _features/ を import 不可。依存方向を守る。",
15
15
  },
16
16
  {
17
17
  group: ["*/_lib/*", "*/_lib/**"],
18
- message: "_utils/ cannot import _lib/",
18
+ message: "_utils/ _lib/ を import 不可。依存方向を守る。",
19
19
  },
20
20
  ],
21
21
  },
@@ -3,7 +3,7 @@ export const flatEntryPointRule = {
3
3
  type: "problem",
4
4
  messages: {
5
5
  nested:
6
- "Edge Function entry points must be directly under supabase/functions/. Nested directories (e.g., commands/{{name}}) are not supported by Supabase CLI.",
6
+ "Edge Function entry point supabase/functions/ 直下に置く。ネストした directory ( commands/{{name}}) Supabase CLI 非対応。",
7
7
  },
8
8
  schema: [],
9
9
  },
@@ -0,0 +1,14 @@
1
+ # src/next/CLAUDE.md
2
+
3
+ Next.js 固有 rule の置き場所判断:
4
+
5
+ - `boundaries/<surface>.mjs` — Next.js 固有の boundary (外界 → features の入口)
6
+ - 種類: page / route / sitemap / hooks / components / lib
7
+ - `layers/<layer>.mjs` — Next.js 固有の layer
8
+ - 種類: components / hooks / layouts
9
+ - `directives.mjs` — `"use server"` / `"use client"` 等の directive 制約
10
+ - `imports.mjs` — Next.js 固有の import パターン
11
+ - `tailwindcss.mjs` — Tailwind CSS rule (margin 禁止等)
12
+ - `index.mjs` — Next.js entry。common の rule + 上記 file を合成
13
+
14
+ Next.js entry 横断の共通 rule は `src/common/` に追加する。
@@ -7,12 +7,12 @@ const COMPONENTS_BOUNDARY_PATTERNS = [
7
7
  {
8
8
  group: ["**/queries/*", "**/queries"],
9
9
  message:
10
- "components can only import entries or hooks, not queries (components-boundary violation)",
10
+ "components queries を直接 import 不可。entries hooks 経由で使う。",
11
11
  },
12
12
  {
13
13
  group: ["**/services/*", "**/services"],
14
14
  message:
15
- "components can only import entries or hooks, not services (components-boundary violation)",
15
+ "components services を直接 import 不可。entries hooks 経由で使う。",
16
16
  },
17
17
  ];
18
18
 
@@ -7,12 +7,12 @@ const HOOKS_BOUNDARY_PATTERNS = [
7
7
  {
8
8
  group: ["**/queries/*", "**/queries"],
9
9
  message:
10
- "hooks can only import entries, not queries (hooks-boundary violation)",
10
+ "hooks queries を直接 import 不可。entries 経由で使う。",
11
11
  },
12
12
  {
13
13
  group: ["**/services/*", "**/services"],
14
14
  message:
15
- "hooks can only import entries, not services (hooks-boundary violation)",
15
+ "hooks services を直接 import 不可。entries 経由で使う。",
16
16
  },
17
17
  ];
18
18
 
@@ -7,12 +7,12 @@ const PAGE_BOUNDARY_PATTERNS = [
7
7
  {
8
8
  group: ["**/queries/*", "**/queries"],
9
9
  message:
10
- "page.tsx can only import entries, not queries (page-boundary violation)",
10
+ "page.tsx queries を直接 import 不可。entries 経由で使う。",
11
11
  },
12
12
  {
13
13
  group: ["**/services/*", "**/services"],
14
14
  message:
15
- "page.tsx can only import entries, not services (page-boundary violation)",
15
+ "page.tsx services を直接 import 不可。entries 経由で使う。",
16
16
  },
17
17
  ];
18
18
 
@@ -7,12 +7,12 @@ const ROUTE_BOUNDARY_PATTERNS = [
7
7
  {
8
8
  group: ["**/queries/*", "**/queries"],
9
9
  message:
10
- "route.ts can only import entries, not queries (route-boundary violation)",
10
+ "route.ts queries を直接 import 不可。entries 経由で使う。",
11
11
  },
12
12
  {
13
13
  group: ["**/services/*", "**/services"],
14
14
  message:
15
- "route.ts can only import entries, not services (route-boundary violation)",
15
+ "route.ts services を直接 import 不可。entries 経由で使う。",
16
16
  },
17
17
  ];
18
18
 
@@ -7,12 +7,12 @@ const SITEMAP_BOUNDARY_PATTERNS = [
7
7
  {
8
8
  group: ["**/queries/*", "**/queries"],
9
9
  message:
10
- "sitemap.ts can only import entries, not queries (sitemap-boundary violation)",
10
+ "sitemap.ts queries を直接 import 不可。entries 経由で使う。",
11
11
  },
12
12
  {
13
13
  group: ["**/services/*", "**/services"],
14
14
  message:
15
- "sitemap.ts can only import entries, not services (sitemap-boundary violation)",
15
+ "sitemap.ts services を直接 import 不可。entries 経由で使う。",
16
16
  },
17
17
  ];
18
18