@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
package/README.md
CHANGED
|
@@ -4,60 +4,17 @@ Shared ESLint configuration for Next.js, Node.js and Deno.
|
|
|
4
4
|
|
|
5
5
|
## Entry Points
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
```text
|
|
16
|
-
src/
|
|
17
|
-
├── common/ # Shared rules for all environments
|
|
18
|
-
├── next/ # Next.js-specific rules (hooks, components, directives)
|
|
19
|
-
├── node/ # Node.js CLI scripts (scripts/features, scripts/commands)
|
|
20
|
-
└── deno/ # Deno entry point (entry-point boundary, _utils boundary, _lib boundary)
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Each entry point enforces a feature-based architecture. **Files do not carry role suffixes — the directory declares the role**:
|
|
24
|
-
|
|
25
|
-
```text
|
|
26
|
-
{featureRoot}/
|
|
27
|
-
├── {feature}/
|
|
28
|
-
│ ├── entries/ # entry points called from page.tsx / route.ts / hooks (server.ts / admin.ts / client.ts)
|
|
29
|
-
│ ├── services/ # business logic (server.ts ...)
|
|
30
|
-
│ ├── queries/ # data access (one file per upstream lib: <lib-name>.ts)
|
|
31
|
-
│ ├── types/ # type defs (one file per feature: <feature>.ts)
|
|
32
|
-
│ ├── schemas/ # zod schemas (<feature>.ts)
|
|
33
|
-
│ ├── utils/ # pure helpers (<feature>.ts)
|
|
34
|
-
│ └── constants/ # constants (<feature>.ts)
|
|
35
|
-
├── shared/ # Cross-feature shared modules
|
|
36
|
-
{libRoot}/
|
|
37
|
-
├── {single-client-lib}/index.ts # SDK wrapper entry (e.g., gallery-dl, fxembed, r2)
|
|
38
|
-
├── {single-client-lib}/types.ts # raw SDK types
|
|
39
|
-
├── {single-client-lib}/<sub>.ts # internal sub-modules (parser, etc.) — auto-hidden from queries
|
|
40
|
-
├── {multi-client-lib}/<role>.ts # one role per file (e.g., supabase: admin / server / client / proxy)
|
|
41
|
-
└── {multi-client-lib}/types.ts
|
|
42
|
-
{utilsRoot}/ # top-level pure utilities (cn.ts / logger.ts ...)
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### single-client vs multi-client lib
|
|
7
|
+
- `@yasainet/eslint/next` — Common rules + Next.js
|
|
8
|
+
- Feature Root: `src/features/`
|
|
9
|
+
- `@yasainet/eslint/node` — Common rules for CLI scripts
|
|
10
|
+
- Feature Root: `scripts/features/`
|
|
11
|
+
- Entry Points: `scripts/commands/*.ts`
|
|
12
|
+
- `@yasainet/eslint/deno` — Common rules for Edge Functions
|
|
13
|
+
- Feature Root: `supabase/functions/features/`
|
|
46
14
|
|
|
47
|
-
|
|
48
|
-
| -------------------------------------------- | ---------------- | --------------------------------------------- |
|
|
49
|
-
| `lib/<dir>/index.ts` exists | single-client | `lib/gallery-dl/{index.ts, parser.ts, types.ts}` |
|
|
50
|
-
| `lib/<dir>/index.ts` absent | multi-client | `lib/supabase/{admin.ts, server.ts, client.ts, ...}` |
|
|
15
|
+
## Architecture
|
|
51
16
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
### File naming rules
|
|
55
|
-
|
|
56
|
-
- **No multi-extension suffixes** (`.lib`, `.service`, `.query`, `.util`, `.type`, `.schema`, `.constant`, `.entry` are forbidden). The directory carries the role.
|
|
57
|
-
- `lib/<dir>/index.ts` for single-client lib entries (avoids `lib/<dir>/<dir>.ts` redundancy).
|
|
58
|
-
- `lib/<dir>/types.ts` and `lib/<dir>/proxy.ts` are excluded from the prefix mapping so queries cannot directly depend on them.
|
|
59
|
-
- `<feature>/{types,schemas,utils,constants}/<feature>.ts` — exactly one file per feature, named after the feature.
|
|
60
|
-
- `<feature>/queries/<lib-name>.ts` — file name must match a registered lib prefix; queries can only import from the matching lib (lib-boundary lint).
|
|
17
|
+
`feature-based architecture` を ESLint で機械的に enforce する設定集。詳細な命名規約・directory 構造・各 layer の責務は [CLAUDE.md](./CLAUDE.md) を参照。consuming project の Claude Code は CLAUDE.md を読んで自動的に規約に従う。
|
|
61
18
|
|
|
62
19
|
## Setup
|
|
63
20
|
|
|
@@ -151,14 +108,14 @@ export default [...eslintConfig];
|
|
|
151
108
|
|
|
152
109
|
## Release
|
|
153
110
|
|
|
154
|
-
Version
|
|
111
|
+
Version は Git tag から派生する。CI が自動で `package.json` の version を設定して publish する。
|
|
155
112
|
|
|
156
|
-
1.
|
|
157
|
-
2.
|
|
113
|
+
1. `main` にコミット & push
|
|
114
|
+
2. tag を作成 & push:
|
|
158
115
|
|
|
159
|
-
```sh
|
|
160
|
-
git tag v1.0.0
|
|
161
|
-
git push --tags
|
|
162
|
-
```
|
|
116
|
+
```sh
|
|
117
|
+
git tag v1.0.0
|
|
118
|
+
git push --tags
|
|
119
|
+
```
|
|
163
120
|
|
|
164
|
-
3. GitHub Actions
|
|
121
|
+
3. GitHub Actions が npm に publish する
|
package/package.json
CHANGED
|
@@ -20,22 +20,8 @@ function findProjectRoot() {
|
|
|
20
20
|
|
|
21
21
|
const PROJECT_ROOT = findProjectRoot();
|
|
22
22
|
|
|
23
|
-
/**
|
|
24
|
-
* Files / basenames that should never become a prefix:
|
|
25
|
-
*
|
|
26
|
-
* - `types.ts` / `type.ts`: 型定義のみで lib の役割を持たない (単複どちらの命名でも除外)
|
|
27
|
-
* - `proxy.ts`: middleware adapter (Next.js の proxy.ts と意味が衝突するため queries から呼ばせない)
|
|
28
|
-
*/
|
|
29
23
|
const EXCLUDE_LIST = ["types.ts", "type.ts", "proxy.ts"];
|
|
30
24
|
|
|
31
|
-
/**
|
|
32
|
-
* Scan lib directory and build prefix-to-lib-relative-path mapping:
|
|
33
|
-
*
|
|
34
|
-
* - single-client lib (`lib/<dir>/index.ts`): prefix = dir 名、entry のみ登録 — 同 dir 内の他ファイル (parser 等 sub-module) は自動除外
|
|
35
|
-
* - multi-client lib (index.ts なし): dir 内の全 `<role>.ts` を登録 (e.g., supabase の admin / server / client)
|
|
36
|
-
* - 多重拡張子 (`.test.ts` 等) を持つファイルは sub-module / 非 lib として除外
|
|
37
|
-
* - types.ts / type.ts / proxy.ts のような lib として queries から呼ばせたくないものは EXCLUDE_LIST で除外
|
|
38
|
-
*/
|
|
39
25
|
export function generatePrefixLibMapping(featureRoot) {
|
|
40
26
|
const libRoot = featureRoot.replace(/features$/, "lib");
|
|
41
27
|
const libDir = path.join(PROJECT_ROOT, libRoot);
|
|
@@ -61,11 +47,8 @@ export function generatePrefixLibMapping(featureRoot) {
|
|
|
61
47
|
.map((e) => e.name);
|
|
62
48
|
|
|
63
49
|
if (plainTsFiles.includes("index.ts")) {
|
|
64
|
-
// single-client lib: index.ts を entry とみなし、prefix = dir 名で登録
|
|
65
|
-
// 同 dir 内の他ファイル (parser 等) は sub-module として自動除外
|
|
66
50
|
mapping[entry.name] = `${entry.name}/index`;
|
|
67
51
|
} else {
|
|
68
|
-
// multi-client lib: 全 role file を登録 (e.g., supabase の admin / server / client)
|
|
69
52
|
for (const fileName of plainTsFiles) {
|
|
70
53
|
const prefix = fileName.replace(/\.ts$/, "");
|
|
71
54
|
mapping[prefix] = `${entry.name}/${prefix}`;
|
|
@@ -80,7 +63,6 @@ export function generatePrefixLibMapping(featureRoot) {
|
|
|
80
63
|
return mapping;
|
|
81
64
|
}
|
|
82
65
|
|
|
83
|
-
/** Build glob patterns scoped to the given feature root. */
|
|
84
66
|
export const featuresGlob = (featureRoot, subpath) => [
|
|
85
67
|
`${featureRoot}/${subpath}`,
|
|
86
68
|
];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const LIB_BOUNDARY_PATTERNS = [
|
|
2
|
+
{
|
|
3
|
+
group: ["@/lib/*", "@/lib/**"],
|
|
4
|
+
message:
|
|
5
|
+
"lib/* can only be imported from queries (lib-boundary violation)",
|
|
6
|
+
},
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
export const MAPPING_PATTERNS = [
|
|
10
|
+
{
|
|
11
|
+
group: ["@/utils/mapping.util"],
|
|
12
|
+
importNames: ["mapSnakeToCamel", "mapCamelToSnake"],
|
|
13
|
+
message:
|
|
14
|
+
"Mapping functions are only allowed in services. Snake/camel conversion belongs at the service boundary.",
|
|
15
|
+
},
|
|
16
|
+
];
|
|
@@ -3,7 +3,6 @@ import checkFile from "eslint-plugin-check-file";
|
|
|
3
3
|
import jsdocPlugin from "eslint-plugin-jsdoc";
|
|
4
4
|
import simpleImportSortPlugin from "eslint-plugin-simple-import-sort";
|
|
5
5
|
|
|
6
|
-
/** Shared plugin instances used across ESLint configs. */
|
|
7
6
|
export const plugins = {
|
|
8
7
|
"@stylistic": stylistic,
|
|
9
8
|
"check-file": checkFile,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const loggerSelector = "CallExpression[callee.object.name='logger']";
|
|
2
|
+
|
|
3
|
+
export const loggerMessage =
|
|
4
|
+
"logger is not allowed outside entries. Logging belongs in entries.";
|
|
5
|
+
|
|
6
|
+
export const aliasDynamicImportSelector =
|
|
7
|
+
"ImportExpression[source.type='Literal'][source.value=/^@\\//]";
|
|
8
|
+
|
|
9
|
+
export const aliasDynamicImportMessage =
|
|
10
|
+
"Dynamic imports of `@/` aliased paths are not allowed in features layers. They bypass prefix-lib and lateral cardinality (e.g. `await import('@/lib/supabase/admin')` from queries/server.ts escapes the lib-boundary check). Create the correct queries/<prefix>.ts or services/<prefix>.ts file instead. External npm packages can still be lazy-loaded for cold-start optimization.";
|
|
@@ -3,13 +3,8 @@ import { dirname, join, sep } from "node:path";
|
|
|
3
3
|
|
|
4
4
|
import tseslint from "typescript-eslint";
|
|
5
5
|
|
|
6
|
-
import { simpleImportSortPlugin, stylistic } from "
|
|
6
|
+
import { simpleImportSortPlugin, stylistic } from "../_internal/plugins.mjs";
|
|
7
7
|
|
|
8
|
-
// When evaluated under LSP servers like vscode-eslint, `process.cwd()` returns
|
|
9
|
-
// the linted file's directory rather than the consumer's project root, so it
|
|
10
|
-
// cannot be used to derive `tsconfigRootDir`. Walk up from this module until a
|
|
11
|
-
// `tsconfig.json` outside of `node_modules` is found. Falls back to
|
|
12
|
-
// `process.cwd()` for CLI parity if no such directory is reachable.
|
|
13
8
|
const findProjectRoot = (start) => {
|
|
14
9
|
let dir = start;
|
|
15
10
|
while (dir !== dirname(dir)) {
|
|
@@ -43,7 +38,6 @@ const sharedRulesConfig = {
|
|
|
43
38
|
"simple-import-sort/imports": "warn",
|
|
44
39
|
"simple-import-sort/exports": "warn",
|
|
45
40
|
"@stylistic/quotes": ["warn", "double", { avoidEscape: true }],
|
|
46
|
-
// Dead code detection: rules with no legitimate use case, so always safe to error.
|
|
47
41
|
"no-unreachable": "error",
|
|
48
42
|
"no-unreachable-loop": "error",
|
|
49
43
|
"no-useless-return": "error",
|
|
@@ -74,18 +68,11 @@ const syntacticTypeScriptRules = {
|
|
|
74
68
|
};
|
|
75
69
|
|
|
76
70
|
const typeAwareTypeScriptRules = {
|
|
77
|
-
// Detect defensive fallbacks on non-nullable values (e.g., `?? ''`
|
|
78
|
-
// on a non-null column). Promoted to error once consuming projects
|
|
79
|
-
// (bitcomic.net, getpayme.net) reached 0 warnings.
|
|
80
71
|
"@typescript-eslint/no-unnecessary-condition": "error",
|
|
81
|
-
// Type-aware async safety: silent await omissions are a leading cause
|
|
82
|
-
// of race conditions in server actions and background tasks.
|
|
83
72
|
"@typescript-eslint/no-floating-promises": "error",
|
|
84
73
|
"@typescript-eslint/no-misused-promises": "error",
|
|
85
74
|
"@typescript-eslint/await-thenable": "error",
|
|
86
75
|
"@typescript-eslint/require-await": "error",
|
|
87
|
-
// Type-aware `any` propagation checks: any が境界を越えた瞬間に
|
|
88
|
-
// 残りのコードで型検査が無効化されるため、検出したら確実に止める。
|
|
89
76
|
"@typescript-eslint/no-unsafe-assignment": "error",
|
|
90
77
|
"@typescript-eslint/no-unsafe-call": "error",
|
|
91
78
|
"@typescript-eslint/no-unsafe-member-access": "error",
|
|
@@ -97,21 +84,7 @@ const typeAwareRulesOff = Object.fromEntries(
|
|
|
97
84
|
Object.keys(typeAwareTypeScriptRules).map((rule) => [rule, "off"]),
|
|
98
85
|
);
|
|
99
86
|
|
|
100
|
-
|
|
101
|
-
* Build base rule configs:
|
|
102
|
-
*
|
|
103
|
-
* - `typeAware: true` (default) enables `projectService` and type-aware rules
|
|
104
|
-
* (`no-unnecessary-condition`, `no-floating-promises`, `no-unsafe-*`, etc.)
|
|
105
|
-
* for the matched `files`
|
|
106
|
-
* - `typeAware: false` disables `projectService` and forces type-aware rules
|
|
107
|
-
* off for the matched `files`. Use for files outside the project tsconfig
|
|
108
|
-
* (e.g., Deno files in Supabase Edge Functions)
|
|
109
|
-
*
|
|
110
|
-
* `files` defaults to all TypeScript sources. When combining multiple entries
|
|
111
|
-
* (e.g., next + deno), pass a narrow pattern so the type-aware override only
|
|
112
|
-
* applies to its target files.
|
|
113
|
-
*/
|
|
114
|
-
export function createRulesConfigs({
|
|
87
|
+
export function createTypescriptConfigs({
|
|
115
88
|
typeAware = true,
|
|
116
89
|
files = ["**/*.ts", "**/*.tsx"],
|
|
117
90
|
} = {}) {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function createBanAliasConfigs({ featureRoot }) {
|
|
2
|
+
return [
|
|
3
|
+
{
|
|
4
|
+
name: "imports/ban-alias",
|
|
5
|
+
files: [`${featureRoot}/**/*.ts`],
|
|
6
|
+
rules: {
|
|
7
|
+
"no-restricted-imports": [
|
|
8
|
+
"error",
|
|
9
|
+
{
|
|
10
|
+
patterns: [
|
|
11
|
+
{
|
|
12
|
+
group: ["@/*", "@/**"],
|
|
13
|
+
message:
|
|
14
|
+
"Alias imports (@/) are not available in this environment. Use relative paths.",
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
];
|
|
22
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LIB_BOUNDARY_PATTERNS,
|
|
3
|
+
MAPPING_PATTERNS,
|
|
4
|
+
} from "../_internal/import-patterns.mjs";
|
|
5
|
+
|
|
6
|
+
export function createFeatureDefaultImportsConfigs({ featureRoot }) {
|
|
7
|
+
return [
|
|
8
|
+
{
|
|
9
|
+
name: "imports/feature-other",
|
|
10
|
+
files: [`${featureRoot}/**/*.ts`],
|
|
11
|
+
ignores: [
|
|
12
|
+
`${featureRoot}/**/services/*.ts`,
|
|
13
|
+
`${featureRoot}/**/queries/*.ts`,
|
|
14
|
+
`${featureRoot}/**/entries/*.ts`,
|
|
15
|
+
`${featureRoot}/**/utils/*.ts`,
|
|
16
|
+
`${featureRoot}/**/types/*.ts`,
|
|
17
|
+
],
|
|
18
|
+
rules: {
|
|
19
|
+
"no-restricted-imports": [
|
|
20
|
+
"error",
|
|
21
|
+
{ patterns: [...LIB_BOUNDARY_PATTERNS, ...MAPPING_PATTERNS] },
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { featuresGlob } from "../_internal/constants.mjs";
|
|
2
|
+
import { localPlugin } from "../local-plugins/index.mjs";
|
|
3
|
+
|
|
4
|
+
export function createFeatureNameConfigs({ featureRoot }) {
|
|
5
|
+
return [
|
|
6
|
+
{
|
|
7
|
+
name: "naming/feature-name",
|
|
8
|
+
files: featuresGlob(featureRoot, "**/*.ts"),
|
|
9
|
+
plugins: { local: localPlugin },
|
|
10
|
+
rules: {
|
|
11
|
+
"local/feature-name": ["error", { featureRoot }],
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
];
|
|
15
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { featuresGlob } from "../_internal/constants.mjs";
|
|
2
|
+
|
|
3
|
+
export function createFeaturesTsOnlyConfigs({ featureRoot }) {
|
|
4
|
+
return [
|
|
5
|
+
{
|
|
6
|
+
name: "naming/features-ts-only",
|
|
7
|
+
files: featuresGlob(featureRoot, "**/*.tsx"),
|
|
8
|
+
rules: {
|
|
9
|
+
"no-restricted-syntax": [
|
|
10
|
+
"error",
|
|
11
|
+
{
|
|
12
|
+
selector: "Program",
|
|
13
|
+
message:
|
|
14
|
+
"features/ must only contain .ts files. Components belong in src/components/.",
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
];
|
|
20
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { featuresGlob } from "../_internal/constants.mjs";
|
|
2
|
+
import { localPlugin } from "../local-plugins/index.mjs";
|
|
3
|
+
|
|
4
|
+
export function createFormStateConfigs({ featureRoot }) {
|
|
5
|
+
return [
|
|
6
|
+
{
|
|
7
|
+
name: "naming/form-state",
|
|
8
|
+
files: featuresGlob(featureRoot, "**/*.ts"),
|
|
9
|
+
plugins: { local: localPlugin },
|
|
10
|
+
rules: {
|
|
11
|
+
"local/form-state-naming": "error",
|
|
12
|
+
"local/form-state-shape": "error",
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
];
|
|
16
|
+
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import jsdocPlugin from "eslint-plugin-jsdoc";
|
|
2
2
|
|
|
3
|
-
import { featuresGlob } from "
|
|
3
|
+
import { featuresGlob } from "../_internal/constants.mjs";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
export function createJsdocConfigs(featureRoot) {
|
|
5
|
+
export function createJsdocConfigs({ featureRoot }) {
|
|
7
6
|
return [
|
|
8
7
|
{
|
|
9
8
|
name: "jsdoc",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loggerMessage,
|
|
3
|
+
loggerSelector,
|
|
4
|
+
} from "../_internal/selectors.mjs";
|
|
5
|
+
|
|
6
|
+
export function createLoggerConfigs({ featureRoot }) {
|
|
7
|
+
return [
|
|
8
|
+
{
|
|
9
|
+
name: "layers/logger",
|
|
10
|
+
files: [`${featureRoot}/**/*.ts`],
|
|
11
|
+
ignores: [`${featureRoot}/**/entries/*.ts`],
|
|
12
|
+
rules: {
|
|
13
|
+
"no-console": "error",
|
|
14
|
+
"no-restricted-syntax": [
|
|
15
|
+
"error",
|
|
16
|
+
{ selector: loggerSelector, message: loggerMessage },
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
}
|
|
@@ -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 { 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
|
+
}
|
package/src/common/index.mjs
CHANGED
|
@@ -1,33 +1,51 @@
|
|
|
1
|
-
import { generatePrefixLibMapping } from "./constants.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
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 { createSupabaseColumnsSatisfiesConfigs } from "./cross-cutting/supabase-columns-satisfies.mjs";
|
|
13
|
+
import { createConstantsConfigs } from "./layers/constants.mjs";
|
|
14
|
+
import { createEntriesConfigs } from "./layers/entries.mjs";
|
|
15
|
+
import { createLibLayerConfigs } from "./layers/lib.mjs";
|
|
16
|
+
import { createQueriesConfigs } from "./layers/queries.mjs";
|
|
17
|
+
import { createSchemasConfigs } from "./layers/schemas.mjs";
|
|
18
|
+
import { createServicesConfigs } from "./layers/services.mjs";
|
|
19
|
+
import { createTopLevelUtilsConfigs } from "./layers/top-level-utils.mjs";
|
|
20
|
+
import { createTypesConfigs } from "./layers/types.mjs";
|
|
21
|
+
import { createUtilsConfigs } from "./layers/utils.mjs";
|
|
7
22
|
|
|
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
23
|
export function createCommonConfigs(
|
|
20
24
|
featureRoot,
|
|
21
25
|
{ banAliasImports = false, typeAware = true, rulesFiles } = {},
|
|
22
26
|
) {
|
|
23
27
|
const prefixLibMapping = generatePrefixLibMapping(featureRoot);
|
|
28
|
+
const ctx = { featureRoot, prefixLibMapping, typeAware };
|
|
24
29
|
return [
|
|
25
|
-
...
|
|
26
|
-
...
|
|
27
|
-
...
|
|
28
|
-
...
|
|
29
|
-
...
|
|
30
|
-
...
|
|
31
|
-
...
|
|
30
|
+
...createTypescriptConfigs({ typeAware, ...(rulesFiles && { files: rulesFiles }) }),
|
|
31
|
+
...createFeatureNameConfigs(ctx),
|
|
32
|
+
...createNamespaceImportConfigs(ctx),
|
|
33
|
+
...createServicesConfigs(ctx),
|
|
34
|
+
...createQueriesConfigs(ctx),
|
|
35
|
+
...createFormStateConfigs(ctx),
|
|
36
|
+
...createSupabaseColumnsSatisfiesConfigs(ctx),
|
|
37
|
+
...createLibLayerConfigs(ctx),
|
|
38
|
+
...createTopLevelUtilsConfigs(ctx),
|
|
39
|
+
...createTypesConfigs(ctx),
|
|
40
|
+
...createSchemasConfigs(ctx),
|
|
41
|
+
...createUtilsConfigs(ctx),
|
|
42
|
+
...createConstantsConfigs(ctx),
|
|
43
|
+
...createEntriesConfigs(ctx),
|
|
44
|
+
...createFeaturesTsOnlyConfigs(ctx),
|
|
45
|
+
...createLoggerConfigs(ctx),
|
|
46
|
+
...createNoAnyReturnConfigs(ctx),
|
|
47
|
+
...createFeatureDefaultImportsConfigs(ctx),
|
|
48
|
+
...createJsdocConfigs(ctx),
|
|
49
|
+
...(banAliasImports ? createBanAliasConfigs(ctx) : []),
|
|
32
50
|
];
|
|
33
51
|
}
|
|
@@ -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
|
+
}
|