@ai0x0/utils 0.0.29 → 0.0.30
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 +38 -7
- package/eslint-config/index.js +67 -0
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @ai0x0/utils
|
|
2
2
|
|
|
3
|
-
AI0x0 shared utilities — backend CRUD factories for Next.js App Router + drizzle-orm,
|
|
3
|
+
AI0x0 shared utilities — backend CRUD factories for Next.js App Router + drizzle-orm, custom ESLint rules and presets.
|
|
4
4
|
|
|
5
5
|
## Backend (`src/backend/`)
|
|
6
6
|
|
|
@@ -15,20 +15,20 @@ Declarative CRUD factories on top of `next-rest-framework`, `drizzle-orm/pg-core
|
|
|
15
15
|
| `createDeleteOperation` | DELETE | Delete a record |
|
|
16
16
|
| `createTableSchema` | — | Generate pg table + 5 Zod schemas |
|
|
17
17
|
|
|
18
|
-
**Built-in conventions:** base fields (`id`, `creatorId`, `editorId`, `createdAt`, `updatedAt`, `accessedAt`), ownership checks via `byCreator`, automatic date coercion, pagination (`current`/`pageSize`/`orderBy`/`orderDir`), list filtering with `ILIKE`, `IN`, `jsonb` array matching, and relation joins.
|
|
19
|
-
|
|
20
18
|
See [SKILL.md](./SKILL.md) for detailed workflow, setup, and escape hatches.
|
|
21
19
|
|
|
22
|
-
## ESLint Rules
|
|
20
|
+
## ESLint Rules & Config
|
|
21
|
+
|
|
22
|
+
### Plugin (`eslint-rules/`)
|
|
23
23
|
|
|
24
|
-
Custom ESLint 9 flat-config rules
|
|
24
|
+
Custom ESLint 9 flat-config rules. All enabled via `configs.recommended`:
|
|
25
25
|
|
|
26
26
|
```js
|
|
27
27
|
// eslint.config.js
|
|
28
|
-
import
|
|
28
|
+
import { ai0x0 } from "@ai0x0/utils/eslint-config/index.js";
|
|
29
29
|
|
|
30
30
|
export default [
|
|
31
|
-
|
|
31
|
+
ai0x0.configs.recommended,
|
|
32
32
|
// ... other config
|
|
33
33
|
];
|
|
34
34
|
```
|
|
@@ -46,6 +46,37 @@ export default [
|
|
|
46
46
|
| `require-use-form` | Use `useForm()` for form state |
|
|
47
47
|
| `require-form-convention` | Form naming conventions |
|
|
48
48
|
|
|
49
|
+
### Shared restrictions (`eslint-config/`)
|
|
50
|
+
|
|
51
|
+
Pre-defined `no-restricted-syntax` selectors for antd + ahooks convention enforcement:
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
import {
|
|
55
|
+
ai0x0,
|
|
56
|
+
allRestrictions,
|
|
57
|
+
allRestrictionsWithNetworking,
|
|
58
|
+
} from "@ai0x0/utils/eslint-config/index.js";
|
|
59
|
+
|
|
60
|
+
export default [
|
|
61
|
+
ai0x0.configs.recommended,
|
|
62
|
+
// ... Prettier + TypeScript configs ...
|
|
63
|
+
// Backend code
|
|
64
|
+
{
|
|
65
|
+
files: ["app/(backend)/**/*.ts"],
|
|
66
|
+
rules: { "no-restricted-syntax": ["error", ...allRestrictions] },
|
|
67
|
+
},
|
|
68
|
+
// Frontend code (also restricts fetch / WebSocket)
|
|
69
|
+
{
|
|
70
|
+
files: ["app/(frontend)/**/*.ts"],
|
|
71
|
+
rules: {
|
|
72
|
+
"no-restricted-syntax": ["error", ...allRestrictionsWithNetworking],
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Restrictions cover: `TryStatement`, `as` (non-const), `useState`, `useEffect`, `useMemo`, `useCallback`, native `div/span/p/h` tags, hardcoded colors, `fetch` and `new WebSocket()`.
|
|
79
|
+
|
|
49
80
|
## Installation
|
|
50
81
|
|
|
51
82
|
```bash
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ai0x0/utils eslint-config — shared ESLint 9 flat config presets.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
*
|
|
6
|
+
* import { ai0x0, allRestrictions, allRestrictionsWithNetworking }
|
|
7
|
+
* from "@ai0x0/utils/eslint-config/index.js";
|
|
8
|
+
*/
|
|
9
|
+
import localPlugin from "../eslint-rules/index.js";
|
|
10
|
+
|
|
11
|
+
export { localPlugin as ai0x0 };
|
|
12
|
+
|
|
13
|
+
export const allRestrictions = [
|
|
14
|
+
{
|
|
15
|
+
selector: "TryStatement",
|
|
16
|
+
message:
|
|
17
|
+
"禁止 try/catch。后端交给 route-operation 工厂 + defaultOnError 兜底;前端交给 axios 拦截器 + useRequest onError。仅允许 JSON.parse/atob 等入口层解析容错,且必须单行 // eslint-disable-next-line no-restricted-syntax 并注明原因。",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
selector:
|
|
21
|
+
"TSAsExpression:not([typeAnnotation.type='TSTypeReference'][typeAnnotation.typeName.name='const'])",
|
|
22
|
+
message:
|
|
23
|
+
"禁止 `as` 类型断言(`as const` 除外)。优先 satisfies / 类型守卫 / openapi-generator 枚举。必须用 as 时加 // eslint-disable-next-line no-restricted-syntax 注明原因。",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
selector: "CallExpression[callee.name='useState']",
|
|
27
|
+
message:
|
|
28
|
+
"禁止 useState。业务组件请用 ahooks:useRequest / useBoolean / useSetState / useUrlState 等。",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
selector: "CallExpression[callee.name='useEffect']",
|
|
32
|
+
message:
|
|
33
|
+
"禁止 useEffect。副作用请用 ahooks:useMount / useUpdateEffect / useAsyncEffect / useInterval 等。",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
selector: "CallExpression[callee.name='useMemo']",
|
|
37
|
+
message: "禁止 useMemo。React Compiler 会自动记忆化,无需手动优化。",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
selector: "CallExpression[callee.name='useCallback']",
|
|
41
|
+
message: "禁止 useCallback。React Compiler 会自动记忆化,无需手动优化。",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
selector: "JSXOpeningElement[name.name=/^(div|span|p|h[1-6])$/]",
|
|
45
|
+
message:
|
|
46
|
+
"禁用原生 div/span/p/h 标签。布局请用 antd Flex,文本请用 Typography.Text/Paragraph/Title。",
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
selector: "Literal[value=/^(#[0-9a-fA-F]{3,8}|rgba?\\(|hsla?\\()/]",
|
|
50
|
+
message:
|
|
51
|
+
"禁止硬编码颜色字面量。请用 antd token(theme.useToken() 或 createStyles({token}) 里的 colorXxx / colorBgXxx)。",
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
export const allRestrictionsWithNetworking = [
|
|
56
|
+
...allRestrictions,
|
|
57
|
+
{
|
|
58
|
+
selector: "CallExpression[callee.name='fetch']",
|
|
59
|
+
message:
|
|
60
|
+
"禁止在前端业务代码中直接使用 fetch。请使用 axios 封装或 ahooks useRequest。",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
selector: "NewExpression[callee.name='WebSocket']",
|
|
64
|
+
message:
|
|
65
|
+
"禁止在前端业务代码中直接使用 new WebSocket()。请使用项目封装的实时通信层。",
|
|
66
|
+
},
|
|
67
|
+
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai0x0/utils",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.30",
|
|
4
4
|
"description": "AI0x0 utils",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai0x0"
|
|
@@ -20,10 +20,11 @@
|
|
|
20
20
|
"module": "./es/index.js",
|
|
21
21
|
"types": "./lib/index.d.ts",
|
|
22
22
|
"files": [
|
|
23
|
-
"
|
|
24
|
-
"lib",
|
|
23
|
+
"SKILL.md",
|
|
25
24
|
"es",
|
|
26
|
-
"
|
|
25
|
+
"eslint-config",
|
|
26
|
+
"eslint-rules",
|
|
27
|
+
"lib"
|
|
27
28
|
],
|
|
28
29
|
"scripts": {
|
|
29
30
|
"build": "node scripts/build.mjs",
|