@yasainet/eslint 0.0.72 → 0.0.74
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 +17 -60
- package/package.json +1 -1
- package/src/common/{constants.mjs → _internal/constants.mjs} +0 -18
- 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 +10 -0
- package/src/common/{rules.mjs → base/typescript.mjs} +2 -29
- package/src/common/{entry-points.mjs → boundaries/entry-point.mjs} +0 -1
- 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/supabase-columns-satisfies.mjs +18 -0
- package/src/common/index.mjs +42 -24
- package/src/common/layers/constants.mjs +36 -0
- package/src/common/layers/entries.mjs +168 -0
- package/src/common/layers/lib.mjs +18 -0
- package/src/common/layers/queries.mjs +183 -0
- package/src/common/layers/schemas.mjs +45 -0
- package/src/common/layers/services.mjs +115 -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 +50 -0
- package/src/common/local-plugins/entry-single-service-call.mjs +0 -30
- package/src/common/local-plugins/entry-template.mjs +33 -72
- package/src/common/local-plugins/feature-name.mjs +8 -22
- package/src/common/local-plugins/form-state-naming.mjs +0 -10
- package/src/common/local-plugins/form-state-shape.mjs +0 -34
- package/src/common/local-plugins/import-path-style.mjs +0 -7
- package/src/common/local-plugins/index.mjs +0 -1
- package/src/common/local-plugins/layout-main-structural-only.mjs +0 -21
- package/src/common/local-plugins/namespace-import-name.mjs +0 -26
- package/src/common/local-plugins/no-any-return.mjs +0 -8
- package/src/common/local-plugins/queries-export.mjs +0 -8
- package/src/common/local-plugins/queries-namespace-import.mjs +0 -10
- package/src/common/local-plugins/schema-naming.mjs +0 -6
- package/src/common/local-plugins/supabase-columns-satisfies.mjs +0 -24
- package/src/common/local-plugins/supabase-select-typed-columns.mjs +0 -32
- 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 +0 -5
- package/src/deno/local-plugins/index.mjs +0 -1
- 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 +0 -1
- 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 +0 -21
- 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 -58
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { denoLocalPlugin } from "../local-plugins/index.mjs";
|
|
2
|
+
|
|
3
|
+
const FUNCTIONS_ROOT = "supabase/functions";
|
|
4
|
+
|
|
5
|
+
export const denoEntryPointConfigs = [
|
|
6
|
+
{
|
|
7
|
+
name: "deno/entry-point",
|
|
8
|
+
files: [`${FUNCTIONS_ROOT}/**/*.ts`],
|
|
9
|
+
ignores: [`${FUNCTIONS_ROOT}/_*/**`],
|
|
10
|
+
rules: {
|
|
11
|
+
"no-restricted-imports": [
|
|
12
|
+
"error",
|
|
13
|
+
{
|
|
14
|
+
patterns: [
|
|
15
|
+
{
|
|
16
|
+
group: ["**/services/*", "**/services"],
|
|
17
|
+
message:
|
|
18
|
+
"Top-level files must not import services directly. Import from entries instead.",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
group: ["**/queries/*", "**/queries"],
|
|
22
|
+
message:
|
|
23
|
+
"Top-level files must not import queries directly. Import from entries instead.",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
group: ["*/_lib/*", "*/_lib/**"],
|
|
27
|
+
message:
|
|
28
|
+
"Top-level files must not import _lib/ directly. Import from entries instead.",
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "deno/flat-entry-point",
|
|
37
|
+
files: [`${FUNCTIONS_ROOT}/**/*.ts`],
|
|
38
|
+
ignores: [`${FUNCTIONS_ROOT}/_*/**`],
|
|
39
|
+
plugins: { "deno-local": denoLocalPlugin },
|
|
40
|
+
rules: {
|
|
41
|
+
"deno-local/flat-entry-point": "error",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const FUNCTIONS_ROOT = "supabase/functions";
|
|
2
|
+
const FEATURE_ROOT = "supabase/functions/_features";
|
|
3
|
+
|
|
4
|
+
export const denoLibBoundaryConfigs = [
|
|
5
|
+
{
|
|
6
|
+
name: "deno/lib-boundary",
|
|
7
|
+
files: [`${FUNCTIONS_ROOT}/**/*.ts`],
|
|
8
|
+
ignores: [
|
|
9
|
+
`${FUNCTIONS_ROOT}/_lib/**`,
|
|
10
|
+
`${FEATURE_ROOT}/**/queries/**`,
|
|
11
|
+
`${FEATURE_ROOT}/**/types/**`,
|
|
12
|
+
],
|
|
13
|
+
rules: {
|
|
14
|
+
"no-restricted-imports": [
|
|
15
|
+
"error",
|
|
16
|
+
{
|
|
17
|
+
patterns: [
|
|
18
|
+
{
|
|
19
|
+
group: ["*/_lib/*", "*/_lib/**"],
|
|
20
|
+
message:
|
|
21
|
+
"_lib/ can only be imported from queries (lib-boundary violation)",
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
];
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const FUNCTIONS_ROOT = "supabase/functions";
|
|
2
|
+
|
|
3
|
+
export const denoUtilsBoundaryConfigs = [
|
|
4
|
+
{
|
|
5
|
+
name: "deno/utils-boundary",
|
|
6
|
+
files: [`${FUNCTIONS_ROOT}/_utils/**/*.ts`],
|
|
7
|
+
rules: {
|
|
8
|
+
"no-restricted-imports": [
|
|
9
|
+
"error",
|
|
10
|
+
{
|
|
11
|
+
patterns: [
|
|
12
|
+
{
|
|
13
|
+
group: ["*/_features/*", "*/_features/**"],
|
|
14
|
+
message: "_utils/ cannot import _features/",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
group: ["*/_lib/*", "*/_lib/**"],
|
|
18
|
+
message: "_utils/ cannot import _lib/",
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
];
|
package/src/deno/index.mjs
CHANGED
|
@@ -1,29 +1,25 @@
|
|
|
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
|
+
import { denoEntryPointConfigs } from "./boundaries/entry-point.mjs";
|
|
5
|
+
import { denoLibBoundaryConfigs } from "./boundaries/lib.mjs";
|
|
6
|
+
import { denoUtilsBoundaryConfigs } from "./boundaries/utils.mjs";
|
|
4
7
|
|
|
5
8
|
const FEATURE_ROOT = "supabase/functions/_features";
|
|
6
9
|
|
|
7
|
-
const
|
|
10
|
+
const denoNamespaceImportConfigs = createEntryPointConfigs(
|
|
8
11
|
["supabase/functions/**/*.ts"],
|
|
9
12
|
["supabase/functions/_*/**"],
|
|
10
13
|
);
|
|
11
14
|
|
|
12
|
-
// Deno files are not covered by the consumer's project tsconfig
|
|
13
|
-
// (Supabase functions live outside Next.js's tsconfig), so type-aware
|
|
14
|
-
// rules cannot consult the type checker. Disable them here and rely on
|
|
15
|
-
// `deno check` / `deno lint` for type-level guarantees.
|
|
16
|
-
//
|
|
17
|
-
// `rulesFiles` is narrowed so the override only affects Deno files. When this
|
|
18
|
-
// entry is combined with `next`/`node`, those entries keep their type-aware
|
|
19
|
-
// settings on their own files.
|
|
20
|
-
/** Deno ESLint flat config entry point. */
|
|
21
15
|
export const eslintConfig = [
|
|
22
16
|
...createCommonConfigs(FEATURE_ROOT, {
|
|
23
17
|
banAliasImports: true,
|
|
24
18
|
typeAware: false,
|
|
25
19
|
rulesFiles: ["supabase/functions/**/*.ts"],
|
|
26
20
|
}),
|
|
27
|
-
...
|
|
21
|
+
...denoLibBoundaryConfigs,
|
|
28
22
|
...denoEntryPointConfigs,
|
|
23
|
+
...denoUtilsBoundaryConfigs,
|
|
24
|
+
...denoNamespaceImportConfigs,
|
|
29
25
|
];
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/** Ensure Edge Function entry points are directly under supabase/functions/. */
|
|
2
1
|
export const flatEntryPointRule = {
|
|
3
2
|
meta: {
|
|
4
3
|
type: "problem",
|
|
@@ -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,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 can only import entries or hooks, not queries (components-boundary violation)",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
group: ["**/services/*", "**/services"],
|
|
14
|
+
message:
|
|
15
|
+
"components can only import entries or hooks, not services (components-boundary violation)",
|
|
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 can only import entries, not queries (hooks-boundary violation)",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
group: ["**/services/*", "**/services"],
|
|
14
|
+
message:
|
|
15
|
+
"hooks can only import entries, not services (hooks-boundary violation)",
|
|
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 can only import entries, not queries (page-boundary violation)",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
group: ["**/services/*", "**/services"],
|
|
14
|
+
message:
|
|
15
|
+
"page.tsx can only import entries, not services (page-boundary violation)",
|
|
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 can only import entries, not queries (route-boundary violation)",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
group: ["**/services/*", "**/services"],
|
|
14
|
+
message:
|
|
15
|
+
"route.ts can only import entries, not services (route-boundary violation)",
|
|
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 can only import entries, not queries (sitemap-boundary violation)",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
group: ["**/services/*", "**/services"],
|
|
14
|
+
message:
|
|
15
|
+
"sitemap.ts can only import entries, not services (sitemap-boundary violation)",
|
|
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
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/ must only contain .tsx files. Logic belongs in 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
|
+
"Exported functions in hooks must start with 'use' (e.g., 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",
|
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,
|