@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.
- package/README.md +9 -152
- package/package.json +7 -1
- package/src/cli/test-audit.mjs +97 -0
- package/src/common/CLAUDE.md +17 -0
- package/src/common/{constants.mjs → _internal/constants.mjs} +1 -19
- package/src/common/_internal/import-patterns.mjs +16 -0
- package/src/common/{plugins.mjs → _internal/plugins.mjs} +0 -1
- package/src/common/_internal/selectors.mjs +12 -0
- package/src/common/{rules.mjs → base/typescript.mjs} +15 -36
- package/src/common/{entry-points.mjs → boundaries/entry-point.mjs} +1 -2
- package/src/common/cross-cutting/ban-alias.mjs +22 -0
- package/src/common/cross-cutting/feature-default-imports.mjs +26 -0
- package/src/common/cross-cutting/feature-name.mjs +15 -0
- package/src/common/cross-cutting/features-ts-only.mjs +20 -0
- package/src/common/cross-cutting/form-state.mjs +16 -0
- package/src/common/{jsdoc.mjs → cross-cutting/jsdoc.mjs} +2 -3
- package/src/common/cross-cutting/logger.mjs +21 -0
- package/src/common/cross-cutting/namespace-import.mjs +23 -0
- package/src/common/cross-cutting/no-any-return.mjs +18 -0
- package/src/common/cross-cutting/no-colocated-test.mjs +18 -0
- package/src/common/cross-cutting/supabase-columns-satisfies.mjs +18 -0
- package/src/common/index.mjs +44 -24
- package/src/common/layers/constants.mjs +36 -0
- package/src/common/layers/entries.mjs +174 -0
- package/src/common/layers/lib.mjs +18 -0
- package/src/common/layers/queries.mjs +187 -0
- package/src/common/layers/schemas.mjs +50 -0
- package/src/common/layers/services.mjs +121 -0
- package/src/common/layers/top-level-utils.mjs +18 -0
- package/src/common/layers/types.mjs +44 -0
- package/src/common/layers/utils.mjs +54 -0
- package/src/common/local-plugins/entry-single-service-call.mjs +3 -31
- package/src/common/local-plugins/entry-template.mjs +51 -88
- package/src/common/local-plugins/feature-name.mjs +5 -24
- package/src/common/local-plugins/form-state-naming.mjs +1 -11
- package/src/common/local-plugins/form-state-shape.mjs +8 -42
- package/src/common/local-plugins/import-path-style.mjs +2 -9
- package/src/common/local-plugins/index.mjs +2 -1
- package/src/common/local-plugins/layout-main-structural-only.mjs +1 -22
- package/src/common/local-plugins/namespace-import-name.mjs +1 -27
- package/src/common/local-plugins/no-any-return.mjs +1 -9
- package/src/common/local-plugins/no-colocated-test.mjs +26 -0
- package/src/common/local-plugins/queries-export.mjs +1 -9
- package/src/common/local-plugins/queries-namespace-import.mjs +1 -11
- package/src/common/local-plugins/schema-naming.mjs +2 -8
- package/src/common/local-plugins/supabase-columns-satisfies.mjs +1 -25
- package/src/common/local-plugins/supabase-select-typed-columns.mjs +5 -37
- package/src/deno/CLAUDE.md +10 -0
- package/src/deno/boundaries/entry-point.mjs +44 -0
- package/src/deno/boundaries/lib.mjs +28 -0
- package/src/deno/boundaries/utils.mjs +25 -0
- package/src/deno/index.mjs +9 -13
- package/src/deno/local-plugins/flat-entry-point.mjs +1 -6
- package/src/deno/local-plugins/index.mjs +0 -1
- package/src/next/CLAUDE.md +14 -0
- package/src/next/boundaries/components.mjs +36 -0
- package/src/next/boundaries/hooks.mjs +36 -0
- package/src/next/boundaries/lib.mjs +23 -0
- package/src/next/boundaries/page.mjs +36 -0
- package/src/next/boundaries/route.mjs +36 -0
- package/src/next/boundaries/sitemap.mjs +36 -0
- package/src/next/directives.mjs +4 -5
- package/src/next/imports.mjs +0 -1
- package/src/next/index.mjs +12 -15
- package/src/next/layers/components.mjs +30 -0
- package/src/next/layers/hooks.mjs +31 -0
- package/src/next/layers/layouts.mjs +12 -0
- package/src/next/tailwindcss.mjs +2 -23
- package/src/node/CLAUDE.md +7 -0
- package/src/node/index.mjs +1 -2
- package/src/common/imports.mjs +0 -457
- package/src/common/layers.mjs +0 -158
- package/src/common/naming.mjs +0 -347
- package/src/deno/imports.mjs +0 -90
- package/src/next/layouts.mjs +0 -18
- package/src/next/naming.mjs +0 -60
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
/** Ensure Edge Function entry points are directly under supabase/functions/. */
|
|
2
1
|
export const flatEntryPointRule = {
|
|
3
2
|
meta: {
|
|
4
3
|
type: "problem",
|
|
5
4
|
messages: {
|
|
6
5
|
nested:
|
|
7
|
-
"Edge Function entry
|
|
6
|
+
"Edge Function の entry point は supabase/functions/ 直下に置く。ネストした directory (例 commands/{{name}}) は Supabase CLI 非対応。",
|
|
8
7
|
},
|
|
9
8
|
schema: [],
|
|
10
9
|
},
|
|
@@ -18,14 +17,10 @@ export const flatEntryPointRule = {
|
|
|
18
17
|
const relative = filename.slice(idx + "supabase/functions/".length);
|
|
19
18
|
const segments = relative.split("/").filter(Boolean);
|
|
20
19
|
|
|
21
|
-
// _prefix directories are shared code, not entry points
|
|
22
20
|
if (segments[0]?.startsWith("_")) return;
|
|
23
21
|
|
|
24
|
-
// Root-level files (deno.json, .env, etc.) are not entry points
|
|
25
22
|
if (segments.length <= 1) return;
|
|
26
23
|
|
|
27
|
-
// Valid: <name>/index.ts (exactly 2 segments)
|
|
28
|
-
// Invalid: <name>/<nested>/index.ts (3+ segments)
|
|
29
24
|
if (segments.length > 2) {
|
|
30
25
|
context.report({
|
|
31
26
|
node,
|
|
@@ -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/` に追加する。
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LIB_BOUNDARY_PATTERNS,
|
|
3
|
+
MAPPING_PATTERNS,
|
|
4
|
+
} from "../../common/_internal/import-patterns.mjs";
|
|
5
|
+
|
|
6
|
+
const COMPONENTS_BOUNDARY_PATTERNS = [
|
|
7
|
+
{
|
|
8
|
+
group: ["**/queries/*", "**/queries"],
|
|
9
|
+
message:
|
|
10
|
+
"components は queries を直接 import 不可。entries か hooks 経由で使う。",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
group: ["**/services/*", "**/services"],
|
|
14
|
+
message:
|
|
15
|
+
"components は services を直接 import 不可。entries か hooks 経由で使う。",
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export const componentsBoundaryConfigs = [
|
|
20
|
+
{
|
|
21
|
+
name: "imports/components-boundary",
|
|
22
|
+
files: ["src/components/**/*.{ts,tsx}"],
|
|
23
|
+
rules: {
|
|
24
|
+
"no-restricted-imports": [
|
|
25
|
+
"error",
|
|
26
|
+
{
|
|
27
|
+
patterns: [
|
|
28
|
+
...COMPONENTS_BOUNDARY_PATTERNS,
|
|
29
|
+
...LIB_BOUNDARY_PATTERNS,
|
|
30
|
+
...MAPPING_PATTERNS,
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LIB_BOUNDARY_PATTERNS,
|
|
3
|
+
MAPPING_PATTERNS,
|
|
4
|
+
} from "../../common/_internal/import-patterns.mjs";
|
|
5
|
+
|
|
6
|
+
const HOOKS_BOUNDARY_PATTERNS = [
|
|
7
|
+
{
|
|
8
|
+
group: ["**/queries/*", "**/queries"],
|
|
9
|
+
message:
|
|
10
|
+
"hooks は queries を直接 import 不可。entries 経由で使う。",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
group: ["**/services/*", "**/services"],
|
|
14
|
+
message:
|
|
15
|
+
"hooks は services を直接 import 不可。entries 経由で使う。",
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export const hooksBoundaryConfigs = [
|
|
20
|
+
{
|
|
21
|
+
name: "imports/hooks-boundary",
|
|
22
|
+
files: ["src/features/**/hooks/*.ts"],
|
|
23
|
+
rules: {
|
|
24
|
+
"no-restricted-imports": [
|
|
25
|
+
"error",
|
|
26
|
+
{
|
|
27
|
+
patterns: [
|
|
28
|
+
...HOOKS_BOUNDARY_PATTERNS,
|
|
29
|
+
...LIB_BOUNDARY_PATTERNS,
|
|
30
|
+
...MAPPING_PATTERNS,
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LIB_BOUNDARY_PATTERNS,
|
|
3
|
+
MAPPING_PATTERNS,
|
|
4
|
+
} from "../../common/_internal/import-patterns.mjs";
|
|
5
|
+
|
|
6
|
+
export const libBoundaryConfigs = [
|
|
7
|
+
{
|
|
8
|
+
name: "imports/lib-boundary",
|
|
9
|
+
files: ["src/**/*.{ts,tsx}"],
|
|
10
|
+
ignores: [
|
|
11
|
+
"src/lib/**",
|
|
12
|
+
"src/proxy.ts",
|
|
13
|
+
"src/app/**/route.ts",
|
|
14
|
+
"src/features/**",
|
|
15
|
+
],
|
|
16
|
+
rules: {
|
|
17
|
+
"no-restricted-imports": [
|
|
18
|
+
"error",
|
|
19
|
+
{ patterns: [...LIB_BOUNDARY_PATTERNS, ...MAPPING_PATTERNS] },
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LIB_BOUNDARY_PATTERNS,
|
|
3
|
+
MAPPING_PATTERNS,
|
|
4
|
+
} from "../../common/_internal/import-patterns.mjs";
|
|
5
|
+
|
|
6
|
+
const PAGE_BOUNDARY_PATTERNS = [
|
|
7
|
+
{
|
|
8
|
+
group: ["**/queries/*", "**/queries"],
|
|
9
|
+
message:
|
|
10
|
+
"page.tsx は queries を直接 import 不可。entries 経由で使う。",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
group: ["**/services/*", "**/services"],
|
|
14
|
+
message:
|
|
15
|
+
"page.tsx は services を直接 import 不可。entries 経由で使う。",
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export const pageBoundaryConfigs = [
|
|
20
|
+
{
|
|
21
|
+
name: "imports/page-boundary",
|
|
22
|
+
files: ["src/app/**/page.tsx"],
|
|
23
|
+
rules: {
|
|
24
|
+
"no-restricted-imports": [
|
|
25
|
+
"error",
|
|
26
|
+
{
|
|
27
|
+
patterns: [
|
|
28
|
+
...PAGE_BOUNDARY_PATTERNS,
|
|
29
|
+
...LIB_BOUNDARY_PATTERNS,
|
|
30
|
+
...MAPPING_PATTERNS,
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LIB_BOUNDARY_PATTERNS,
|
|
3
|
+
MAPPING_PATTERNS,
|
|
4
|
+
} from "../../common/_internal/import-patterns.mjs";
|
|
5
|
+
|
|
6
|
+
const ROUTE_BOUNDARY_PATTERNS = [
|
|
7
|
+
{
|
|
8
|
+
group: ["**/queries/*", "**/queries"],
|
|
9
|
+
message:
|
|
10
|
+
"route.ts は queries を直接 import 不可。entries 経由で使う。",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
group: ["**/services/*", "**/services"],
|
|
14
|
+
message:
|
|
15
|
+
"route.ts は services を直接 import 不可。entries 経由で使う。",
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export const routeBoundaryConfigs = [
|
|
20
|
+
{
|
|
21
|
+
name: "imports/route-boundary",
|
|
22
|
+
files: ["src/app/**/route.ts"],
|
|
23
|
+
rules: {
|
|
24
|
+
"no-restricted-imports": [
|
|
25
|
+
"error",
|
|
26
|
+
{
|
|
27
|
+
patterns: [
|
|
28
|
+
...ROUTE_BOUNDARY_PATTERNS,
|
|
29
|
+
...LIB_BOUNDARY_PATTERNS,
|
|
30
|
+
...MAPPING_PATTERNS,
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LIB_BOUNDARY_PATTERNS,
|
|
3
|
+
MAPPING_PATTERNS,
|
|
4
|
+
} from "../../common/_internal/import-patterns.mjs";
|
|
5
|
+
|
|
6
|
+
const SITEMAP_BOUNDARY_PATTERNS = [
|
|
7
|
+
{
|
|
8
|
+
group: ["**/queries/*", "**/queries"],
|
|
9
|
+
message:
|
|
10
|
+
"sitemap.ts は queries を直接 import 不可。entries 経由で使う。",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
group: ["**/services/*", "**/services"],
|
|
14
|
+
message:
|
|
15
|
+
"sitemap.ts は services を直接 import 不可。entries 経由で使う。",
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export const sitemapBoundaryConfigs = [
|
|
20
|
+
{
|
|
21
|
+
name: "imports/sitemap-boundary",
|
|
22
|
+
files: ["src/app/sitemap.ts", "src/app/**/sitemap.ts"],
|
|
23
|
+
rules: {
|
|
24
|
+
"no-restricted-imports": [
|
|
25
|
+
"error",
|
|
26
|
+
{
|
|
27
|
+
patterns: [
|
|
28
|
+
...SITEMAP_BOUNDARY_PATTERNS,
|
|
29
|
+
...LIB_BOUNDARY_PATTERNS,
|
|
30
|
+
...MAPPING_PATTERNS,
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
];
|
package/src/next/directives.mjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/** Enforce "use server" / "use client" directives per file convention. */
|
|
2
1
|
export const directivesConfigs = [
|
|
3
2
|
{
|
|
4
3
|
name: "directives/server-entry",
|
|
@@ -10,7 +9,7 @@ export const directivesConfigs = [
|
|
|
10
9
|
selector:
|
|
11
10
|
"Program > :first-child:not(ExpressionStatement[expression.value='use server'])",
|
|
12
11
|
message:
|
|
13
|
-
'entries/server.ts
|
|
12
|
+
'entries/server.ts は先頭に "use server" directive が必須。',
|
|
14
13
|
},
|
|
15
14
|
],
|
|
16
15
|
},
|
|
@@ -25,7 +24,7 @@ export const directivesConfigs = [
|
|
|
25
24
|
selector:
|
|
26
25
|
"Program > :first-child:not(ExpressionStatement[expression.value='use server'])",
|
|
27
26
|
message:
|
|
28
|
-
'entries/admin.ts
|
|
27
|
+
'entries/admin.ts は先頭に "use server" directive が必須。',
|
|
29
28
|
},
|
|
30
29
|
],
|
|
31
30
|
},
|
|
@@ -39,7 +38,7 @@ export const directivesConfigs = [
|
|
|
39
38
|
{
|
|
40
39
|
selector: "ExpressionStatement[expression.value='use server']",
|
|
41
40
|
message:
|
|
42
|
-
'entries/client.ts
|
|
41
|
+
'entries/client.ts は "use server" 禁止。@/lib/supabase/client を使うため。',
|
|
43
42
|
},
|
|
44
43
|
],
|
|
45
44
|
},
|
|
@@ -53,7 +52,7 @@ export const directivesConfigs = [
|
|
|
53
52
|
{
|
|
54
53
|
selector:
|
|
55
54
|
"Program > :first-child:not(ExpressionStatement[expression.value='use client'])",
|
|
56
|
-
message: '
|
|
55
|
+
message: 'hooks は先頭に "use client" directive が必須。',
|
|
57
56
|
},
|
|
58
57
|
],
|
|
59
58
|
},
|
package/src/next/imports.mjs
CHANGED
package/src/next/index.mjs
CHANGED
|
@@ -1,28 +1,24 @@
|
|
|
1
|
-
import { createEntryPointConfigs } from "../common/entry-
|
|
1
|
+
import { createEntryPointConfigs } from "../common/boundaries/entry-point.mjs";
|
|
2
2
|
import { createCommonConfigs } from "../common/index.mjs";
|
|
3
|
-
import {
|
|
4
|
-
componentsBoundaryConfigs,
|
|
5
|
-
hooksBoundaryConfigs,
|
|
6
|
-
libBoundaryConfigs,
|
|
7
|
-
pageBoundaryConfigs,
|
|
8
|
-
routeBoundaryConfigs,
|
|
9
|
-
sitemapBoundaryConfigs,
|
|
10
|
-
} from "../common/imports.mjs";
|
|
11
3
|
|
|
4
|
+
import { componentsBoundaryConfigs } from "./boundaries/components.mjs";
|
|
5
|
+
import { hooksBoundaryConfigs } from "./boundaries/hooks.mjs";
|
|
6
|
+
import { libBoundaryConfigs } from "./boundaries/lib.mjs";
|
|
7
|
+
import { pageBoundaryConfigs } from "./boundaries/page.mjs";
|
|
8
|
+
import { routeBoundaryConfigs } from "./boundaries/route.mjs";
|
|
9
|
+
import { sitemapBoundaryConfigs } from "./boundaries/sitemap.mjs";
|
|
12
10
|
import { directivesConfigs } from "./directives.mjs";
|
|
13
11
|
import { importPathStyleConfigs } from "./imports.mjs";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
12
|
+
import { componentsLayerConfigs } from "./layers/components.mjs";
|
|
13
|
+
import { hooksLayerConfigs } from "./layers/hooks.mjs";
|
|
14
|
+
import { layoutsConfigs } from "./layers/layouts.mjs";
|
|
16
15
|
import { tailwindcssConfigs } from "./tailwindcss.mjs";
|
|
17
16
|
|
|
18
17
|
const nextEntryPointConfigs = createEntryPointConfigs(
|
|
19
18
|
["src/app/**/*.ts", "src/app/**/*.tsx"],
|
|
20
19
|
);
|
|
21
20
|
|
|
22
|
-
/** Next.js ESLint flat config entry point. */
|
|
23
21
|
export const eslintConfig = [
|
|
24
|
-
// shadcn/ui generated components live directly under `src/components/shared/ui/`.
|
|
25
|
-
// Files in `custom/` are user-authored and remain linted.
|
|
26
22
|
{
|
|
27
23
|
name: "rules/ignore-shadcn-ui",
|
|
28
24
|
ignores: ["src/components/shared/ui/*.{ts,tsx}"],
|
|
@@ -34,7 +30,8 @@ export const eslintConfig = [
|
|
|
34
30
|
...sitemapBoundaryConfigs,
|
|
35
31
|
...hooksBoundaryConfigs,
|
|
36
32
|
...componentsBoundaryConfigs,
|
|
37
|
-
...
|
|
33
|
+
...hooksLayerConfigs,
|
|
34
|
+
...componentsLayerConfigs,
|
|
38
35
|
...directivesConfigs,
|
|
39
36
|
...importPathStyleConfigs,
|
|
40
37
|
...layoutsConfigs,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { checkFile } from "../../common/_internal/plugins.mjs";
|
|
2
|
+
|
|
3
|
+
export const componentsLayerConfigs = [
|
|
4
|
+
{
|
|
5
|
+
name: "naming/components-tsx-only",
|
|
6
|
+
files: ["src/components/**/*.ts"],
|
|
7
|
+
rules: {
|
|
8
|
+
"no-restricted-syntax": [
|
|
9
|
+
"error",
|
|
10
|
+
{
|
|
11
|
+
selector: "Program",
|
|
12
|
+
message:
|
|
13
|
+
"components/ は .tsx のみ。ロジックは src/features/ に置く。",
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: "naming/components-pascal-case",
|
|
20
|
+
files: ["src/components/**/*.tsx"],
|
|
21
|
+
ignores: ["src/components/shared/ui/**", "src/components/**/index.tsx"],
|
|
22
|
+
plugins: { "check-file": checkFile },
|
|
23
|
+
rules: {
|
|
24
|
+
"check-file/filename-naming-convention": [
|
|
25
|
+
"error",
|
|
26
|
+
{ "**/*.tsx": "PASCAL_CASE" },
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { checkFile } from "../../common/_internal/plugins.mjs";
|
|
2
|
+
|
|
3
|
+
export const hooksLayerConfigs = [
|
|
4
|
+
{
|
|
5
|
+
name: "naming/hooks",
|
|
6
|
+
files: ["src/features/**/hooks/*.ts"],
|
|
7
|
+
plugins: { "check-file": checkFile },
|
|
8
|
+
rules: {
|
|
9
|
+
"check-file/filename-naming-convention": [
|
|
10
|
+
"error",
|
|
11
|
+
{ "**/*.ts": "use-+([a-z0-9])*(-+([a-z0-9]))" },
|
|
12
|
+
{ ignoreMiddleExtensions: true },
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: "naming/hooks-export",
|
|
18
|
+
files: ["src/features/**/hooks/*.ts"],
|
|
19
|
+
rules: {
|
|
20
|
+
"no-restricted-syntax": [
|
|
21
|
+
"error",
|
|
22
|
+
{
|
|
23
|
+
selector:
|
|
24
|
+
"ExportNamedDeclaration > FunctionDeclaration[id.name!=/^use[A-Z]/]",
|
|
25
|
+
message:
|
|
26
|
+
"hooks の export 関数は 'use' で始める (例: useAuth)。",
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { localPlugin } from "../../common/local-plugins/index.mjs";
|
|
2
|
+
|
|
3
|
+
export const layoutsConfigs = [
|
|
4
|
+
{
|
|
5
|
+
name: "layouts/main-structural-only",
|
|
6
|
+
files: ["src/app/**/layout.tsx"],
|
|
7
|
+
plugins: { local: localPlugin },
|
|
8
|
+
rules: {
|
|
9
|
+
"local/layout-main-structural-only": "error",
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
];
|
package/src/next/tailwindcss.mjs
CHANGED
|
@@ -3,14 +3,6 @@ import { dirname, join, sep } from "node:path";
|
|
|
3
3
|
|
|
4
4
|
import betterTailwindcss from "eslint-plugin-better-tailwindcss";
|
|
5
5
|
|
|
6
|
-
// `eslint-plugin-better-tailwindcss` resolves a relative `entryPoint` against
|
|
7
|
-
// the linter's `cwd`, which under LSP servers (vscode-eslint, Zed) is often
|
|
8
|
-
// the edited file's directory rather than the consumer's project root and
|
|
9
|
-
// breaks resolution. Mirror the `findProjectRoot` pattern from
|
|
10
|
-
// `common/rules.mjs` and `common/constants.mjs`: walk up from this module
|
|
11
|
-
// outside of `node_modules` and locate `src/app/globals.css`, then pass the
|
|
12
|
-
// absolute path so resolution is cwd-independent. Falls back to the relative
|
|
13
|
-
// path when not found, preserving the previous CLI-only behavior.
|
|
14
6
|
const findEntryPoint = (start) => {
|
|
15
7
|
let dir = start;
|
|
16
8
|
while (dir !== dirname(dir)) {
|
|
@@ -27,19 +19,6 @@ const findEntryPoint = (start) => {
|
|
|
27
19
|
|
|
28
20
|
const entryPoint = findEntryPoint(import.meta.dirname);
|
|
29
21
|
|
|
30
|
-
/**
|
|
31
|
-
* Tailwind CSS v4 lint rules:
|
|
32
|
-
*
|
|
33
|
-
* - margin is forbidden; spacing is controlled by padding/gap on the parent
|
|
34
|
-
* - `space-x-*` / `space-y-*` are also banned because they apply margin to
|
|
35
|
-
* children under the hood. Use `flex/grid + gap` instead. Negative variants
|
|
36
|
-
* (`-space-x-2`) remain allowed for intentional overlap
|
|
37
|
-
* - class order, deprecated classes, conflicts, duplicates, and whitespace
|
|
38
|
-
* are enforced via `eslint-plugin-better-tailwindcss`
|
|
39
|
-
* - `entryPoint` is auto-resolved to the consuming project's
|
|
40
|
-
* `src/app/globals.css` via walk-up from this module. Override in the
|
|
41
|
-
* project's eslint.config.mjs if the file lives elsewhere.
|
|
42
|
-
*/
|
|
43
22
|
export const tailwindcssConfigs = [
|
|
44
23
|
{
|
|
45
24
|
name: "tailwindcss/rules",
|
|
@@ -63,12 +42,12 @@ export const tailwindcssConfigs = [
|
|
|
63
42
|
{
|
|
64
43
|
pattern: "^(?!mx-auto$)m[trblxy]?-(?!auto$)[^-\\s]+$",
|
|
65
44
|
message:
|
|
66
|
-
"
|
|
45
|
+
"margin を避け、padding/gap で間隔を制御する (例外: mx-auto, -mt-*)",
|
|
67
46
|
},
|
|
68
47
|
{
|
|
69
48
|
pattern: "^space-[xy]-[^-\\s]+$",
|
|
70
49
|
message:
|
|
71
|
-
"
|
|
50
|
+
"space-x/space-y は避ける (内部で margin を使う)。flex/grid + gap を使う",
|
|
72
51
|
},
|
|
73
52
|
],
|
|
74
53
|
},
|
package/src/node/index.mjs
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { createEntryPointConfigs } from "../common/entry-
|
|
1
|
+
import { createEntryPointConfigs } from "../common/boundaries/entry-point.mjs";
|
|
2
2
|
import { createCommonConfigs } from "../common/index.mjs";
|
|
3
3
|
|
|
4
4
|
const nodeEntryPointConfigs = createEntryPointConfigs(
|
|
5
5
|
["scripts/commands/*.ts"],
|
|
6
6
|
);
|
|
7
7
|
|
|
8
|
-
/** Node.js ESLint flat config entry point. */
|
|
9
8
|
export const eslintConfig = [
|
|
10
9
|
...createCommonConfigs("scripts/features", { banAliasImports: true }),
|
|
11
10
|
...nodeEntryPointConfigs,
|