@kingsword/lint-config 0.1.0
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/LICENSE +21 -0
- package/README.md +54 -0
- package/configs/oxlint/backend.json +3 -0
- package/configs/oxlint/base.json +42 -0
- package/configs/oxlint/frontend.json +34 -0
- package/configs/oxlint/fullstack.json +8 -0
- package/configs/oxlint/recommended.json +45 -0
- package/configs/oxlint/restricted-syntax-base.json +35 -0
- package/configs/oxlint/restricted-syntax-frontend.json +123 -0
- package/configs/oxlint/vitest-kingsword.json +10 -0
- package/configs/oxlint/vitest-strict.json +11 -0
- package/configs/oxlint/vitest.json +24 -0
- package/dist/chunk-CbDLau6x.cjs +34 -0
- package/dist/cli.cjs +106 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +106 -0
- package/dist/config.cjs +220 -0
- package/dist/config.d.cts +20 -0
- package/dist/config.d.mts +20 -0
- package/dist/config.mjs +214 -0
- package/dist/index.cjs +2003 -0
- package/dist/index.d.cts +53 -0
- package/dist/index.d.mts +54 -0
- package/dist/index.mjs +2000 -0
- package/docs/rules.zh-CN.md +491 -0
- package/package.json +92 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kingsword
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# @kingsword/lint-config
|
|
2
|
+
|
|
3
|
+
可复用的 `oxlint` 配置与 `@kingsword/*` 规则插件。
|
|
4
|
+
|
|
5
|
+
> 要求:`oxlint >= 1.43.0`
|
|
6
|
+
|
|
7
|
+
## 安装
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm i -D oxlint @kingsword/lint-config
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 推荐用法(CLI 生成)
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# 生成 oxlint.config.ts(默认 lib + none + recommended)
|
|
17
|
+
npx xlint init lib
|
|
18
|
+
|
|
19
|
+
# 更严格示例
|
|
20
|
+
npx xlint init fullstack --test vitest --level strict
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
生成后执行:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx oxlint .
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 手写配置
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { defineConfig } from "oxlint";
|
|
33
|
+
import { oxlint } from "@kingsword/lint-config/config";
|
|
34
|
+
|
|
35
|
+
export default defineConfig(
|
|
36
|
+
oxlint({
|
|
37
|
+
profile: "lib",
|
|
38
|
+
test: "none",
|
|
39
|
+
level: "recommended",
|
|
40
|
+
}),
|
|
41
|
+
);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 参数说明
|
|
45
|
+
|
|
46
|
+
- `profile`: `base | lib | react | backend | fullstack`
|
|
47
|
+
- `test`: `none | vitest`
|
|
48
|
+
- `level`: `recommended | strict`
|
|
49
|
+
|
|
50
|
+
`oxlint()` 无参数时,默认使用最严格推荐档(`fullstack-vitest-strict`)。
|
|
51
|
+
|
|
52
|
+
## 规则文档
|
|
53
|
+
|
|
54
|
+
- `docs/rules.zh-CN.md`
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"env": {
|
|
3
|
+
"es2022": true,
|
|
4
|
+
"node": true
|
|
5
|
+
},
|
|
6
|
+
"ignorePatterns": ["build/**", "dist/**", "coverage/**", "node_modules/**"],
|
|
7
|
+
"rules": {
|
|
8
|
+
"no-console": "error",
|
|
9
|
+
"no-void": ["error", { "allowAsStatement": true }],
|
|
10
|
+
"prefer-const": "error",
|
|
11
|
+
"typescript/no-empty-object-type": "error",
|
|
12
|
+
"typescript/no-explicit-any": "error",
|
|
13
|
+
"typescript/no-floating-promises": "error",
|
|
14
|
+
"typescript/no-require-imports": "error",
|
|
15
|
+
"oxc/no-barrel-file": "error"
|
|
16
|
+
},
|
|
17
|
+
"overrides": [
|
|
18
|
+
{
|
|
19
|
+
"files": [
|
|
20
|
+
"**/*.test.js",
|
|
21
|
+
"**/*.test.jsx",
|
|
22
|
+
"**/*.test.ts",
|
|
23
|
+
"**/*.test.tsx",
|
|
24
|
+
"**/*.spec.js",
|
|
25
|
+
"**/*.spec.jsx",
|
|
26
|
+
"**/*.spec.ts",
|
|
27
|
+
"**/*.spec.tsx",
|
|
28
|
+
"**/test-utils/**"
|
|
29
|
+
],
|
|
30
|
+
"rules": {
|
|
31
|
+
"no-console": "off",
|
|
32
|
+
"typescript/no-explicit-any": "off"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"files": ["**/index.ts", "**/index.tsx"],
|
|
37
|
+
"rules": {
|
|
38
|
+
"oxc/no-barrel-file": "off"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": ["./recommended.json", "./restricted-syntax-frontend.json"],
|
|
3
|
+
"env": {
|
|
4
|
+
"browser": true
|
|
5
|
+
},
|
|
6
|
+
"rules": {
|
|
7
|
+
"@kingsword/filename-match-export": [
|
|
8
|
+
"error",
|
|
9
|
+
{ "ignoredFiles": ["utils.ts", "constants.ts", "types.ts"] }
|
|
10
|
+
],
|
|
11
|
+
"@kingsword/no-dynamic-styled-components": "error",
|
|
12
|
+
"@kingsword/no-plain-html-text-elements": "error",
|
|
13
|
+
"@kingsword/no-use-effect-in-hooks": "error",
|
|
14
|
+
|
|
15
|
+
"no-restricted-globals": [
|
|
16
|
+
"error",
|
|
17
|
+
{ "name": "fetch", "message": "fetch() is banned. Use an API client/wrapper instead." }
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"overrides": [
|
|
21
|
+
{
|
|
22
|
+
"files": ["**/*.stories.ts", "**/*.stories.tsx"],
|
|
23
|
+
"rules": {
|
|
24
|
+
"@kingsword/no-plain-html-text-elements": "off"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"files": ["**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx"],
|
|
29
|
+
"rules": {
|
|
30
|
+
"@kingsword/no-plain-html-text-elements": "off"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": ["./base.json", "./restricted-syntax-base.json"],
|
|
3
|
+
"jsPlugins": [{ "name": "@kingsword", "specifier": "../../dist/index.cjs" }],
|
|
4
|
+
"rules": {
|
|
5
|
+
"@kingsword/no-exported-string-union-types": "error",
|
|
6
|
+
"@kingsword/structured-logging": "error",
|
|
7
|
+
"@kingsword/enum-file-organization": "error",
|
|
8
|
+
"@kingsword/types-file-organization": "error",
|
|
9
|
+
"@kingsword/constants-file-organization": "error",
|
|
10
|
+
"@kingsword/errors-file-organization": "error",
|
|
11
|
+
"@kingsword/no-exported-function-expressions": "error",
|
|
12
|
+
"@kingsword/test-utils-organization": "error",
|
|
13
|
+
"@kingsword/test-file-location": "error",
|
|
14
|
+
"@kingsword/no-log-exception-with-throw": "error"
|
|
15
|
+
},
|
|
16
|
+
"overrides": [
|
|
17
|
+
{
|
|
18
|
+
"files": ["**/schema.ts"],
|
|
19
|
+
"rules": {
|
|
20
|
+
"@kingsword/types-file-organization": "off",
|
|
21
|
+
"@kingsword/constants-file-organization": "off"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"files": [
|
|
26
|
+
"**/route.ts",
|
|
27
|
+
"**/api.ts",
|
|
28
|
+
"**/slice.ts",
|
|
29
|
+
"**/selectors.ts",
|
|
30
|
+
"**/*.test.js",
|
|
31
|
+
"**/*.test.jsx",
|
|
32
|
+
"**/*.test.ts",
|
|
33
|
+
"**/*.test.tsx",
|
|
34
|
+
"**/*.spec.js",
|
|
35
|
+
"**/*.spec.jsx",
|
|
36
|
+
"**/*.spec.ts",
|
|
37
|
+
"**/*.spec.tsx",
|
|
38
|
+
"**/test-utils/**"
|
|
39
|
+
],
|
|
40
|
+
"rules": {
|
|
41
|
+
"@kingsword/constants-file-organization": "off"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"rules": {
|
|
3
|
+
"@kingsword/no-restricted-syntax": [
|
|
4
|
+
"error",
|
|
5
|
+
{
|
|
6
|
+
"selector": "ForInStatement",
|
|
7
|
+
"message": "Avoid for..in. Use Object.{keys,values,entries} and iterate over the resulting array."
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"selector": "LabeledStatement",
|
|
11
|
+
"message": "Labels are a form of GOTO; using them makes code confusing and hard to maintain."
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"selector": "WithStatement",
|
|
15
|
+
"message": "`with` is disallowed in strict mode because it makes code impossible to predict and optimize."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"selector": "ExportAllDeclaration",
|
|
19
|
+
"message": "Avoid `export *` because it can cause unexpected exposure and ESM transpilation edge cases."
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"selector": "CatchClause CallExpression[callee.name=\"logError\"]",
|
|
23
|
+
"message": "Do not use logError() inside catch; use logException() instead."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"selector": "CatchClause CallExpression[callee.property.name=\"logError\"]",
|
|
27
|
+
"message": "Do not use .logError() inside catch; use logException() instead."
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"selector": "ThrowStatement > NewExpression[callee.name=\"Error\"]",
|
|
31
|
+
"message": "Prefer a domain error type (e.g. MetaError) instead of throwing a raw Error."
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
{
|
|
2
|
+
"rules": {
|
|
3
|
+
"@kingsword/no-restricted-syntax": [
|
|
4
|
+
"error",
|
|
5
|
+
{
|
|
6
|
+
"selector": "ForInStatement",
|
|
7
|
+
"message": "Avoid for..in. Use Object.{keys,values,entries} and iterate over the resulting array."
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"selector": "LabeledStatement",
|
|
11
|
+
"message": "Labels are a form of GOTO; using them makes code confusing and hard to maintain."
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"selector": "WithStatement",
|
|
15
|
+
"message": "`with` is disallowed in strict mode because it makes code impossible to predict and optimize."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"selector": "ExportAllDeclaration",
|
|
19
|
+
"message": "Avoid `export *` because it can cause unexpected exposure and ESM transpilation edge cases."
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"selector": "CatchClause CallExpression[callee.name=\"logError\"]",
|
|
23
|
+
"message": "Do not use logError() inside catch; use logException() instead."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"selector": "CatchClause CallExpression[callee.property.name=\"logError\"]",
|
|
27
|
+
"message": "Do not use .logError() inside catch; use logException() instead."
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"selector": "ThrowStatement > NewExpression[callee.name=\"Error\"]",
|
|
31
|
+
"message": "Prefer a domain error type (e.g. MetaError) instead of throwing a raw Error."
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"selector": "CallExpression[callee.name=\"useEffect\"]",
|
|
35
|
+
"message": "useEffect is banned. Prefer alternative patterns or dedicated hooks."
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"selector": "CallExpression[callee.object.name=\"React\"][callee.property.name=\"useEffect\"]",
|
|
39
|
+
"message": "React.useEffect is banned. Prefer alternative patterns or dedicated hooks."
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"selector": "CallExpression[callee.name=\"useLayoutEffect\"]",
|
|
43
|
+
"message": "useLayoutEffect is banned. Prefer alternative patterns or dedicated hooks."
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"selector": "CallExpression[callee.object.name=\"React\"][callee.property.name=\"useLayoutEffect\"]",
|
|
47
|
+
"message": "React.useLayoutEffect is banned. Prefer alternative patterns or dedicated hooks."
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"selector": "CallExpression[callee.name=\"useMemo\"]",
|
|
51
|
+
"message": "useMemo is banned. Prefer compiler / simpler code first."
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"selector": "CallExpression[callee.object.name=\"React\"][callee.property.name=\"useMemo\"]",
|
|
55
|
+
"message": "React.useMemo is banned. Prefer compiler / simpler code first."
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"selector": "CallExpression[callee.name=\"useCallback\"]",
|
|
59
|
+
"message": "useCallback is banned. Prefer compiler / simpler code first."
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"selector": "CallExpression[callee.object.name=\"React\"][callee.property.name=\"useCallback\"]",
|
|
63
|
+
"message": "React.useCallback is banned. Prefer compiler / simpler code first."
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"selector": "CallExpression[callee.property.name=\"then\"]",
|
|
67
|
+
"message": "Promise.then() is banned. Use async/await with try/catch instead."
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"selector": "CallExpression[callee.property.name=\"catch\"]",
|
|
71
|
+
"message": "Promise.catch() is banned. Use async/await with try/catch instead."
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"selector": "TSTypeReference[typeName.type=\"TSQualifiedName\"][typeName.left.name=\"React\"][typeName.right.name=\"ChangeEvent\"]",
|
|
75
|
+
"message": "React.ChangeEvent is banned. Import ChangeEvent directly from react."
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"selector": "TSTypeReference[typeName.type=\"TSQualifiedName\"][typeName.left.name=\"React\"][typeName.right.name=\"MouseEvent\"]",
|
|
79
|
+
"message": "React.MouseEvent is banned. Import MouseEvent directly from react."
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"selector": "TSTypeReference[typeName.type=\"TSQualifiedName\"][typeName.left.name=\"React\"][typeName.right.name=\"KeyboardEvent\"]",
|
|
83
|
+
"message": "React.KeyboardEvent is banned. Import KeyboardEvent directly from react."
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"selector": "TSTypeReference[typeName.type=\"TSQualifiedName\"][typeName.left.name=\"React\"][typeName.right.name=\"FormEvent\"]",
|
|
87
|
+
"message": "React.FormEvent is banned. Import FormEvent directly from react."
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"selector": "TSTypeReference[typeName.type=\"TSQualifiedName\"][typeName.left.name=\"React\"][typeName.right.name=\"FocusEvent\"]",
|
|
91
|
+
"message": "React.FocusEvent is banned. Import FocusEvent directly from react."
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"selector": "TSTypeReference[typeName.type=\"TSQualifiedName\"][typeName.left.name=\"React\"][typeName.right.name=/.*Event$/]",
|
|
95
|
+
"message": "React.*Event types are banned. Import event types directly from react."
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"selector": "AssignmentExpression[left.object.name=\"window\"][left.property.name=\"location\"]",
|
|
99
|
+
"message": "Direct window.location manipulation is banned. Prefer router navigation instead."
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"selector": "MemberExpression[object.object.name=\"window\"][object.property.name=\"location\"][property.name=\"href\"]",
|
|
103
|
+
"message": "window.location.href is banned. Prefer router navigation instead."
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"selector": "MemberExpression[object.object.name=\"window\"][object.property.name=\"location\"][property.name=\"assign\"]",
|
|
107
|
+
"message": "window.location.assign() is banned. Prefer router navigation instead."
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"selector": "MemberExpression[object.object.name=\"window\"][object.property.name=\"location\"][property.name=\"replace\"]",
|
|
111
|
+
"message": "window.location.replace() is banned. Prefer router navigation instead."
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"selector": "JSXOpeningElement[name.name=/./]:has(JSXAttribute[name.name=\"as\"][value.value=\"a\"]):not(:has(JSXAttribute[name.name=\"target\"][value.value=\"_blank\"]))",
|
|
115
|
+
"message": "as=\"a\" without target=\"_blank\" is banned. Prefer a safe Link component or add target for external links."
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"selector": "JSXOpeningElement[name.name=\"a\"]:not(:has(JSXAttribute[name.name=\"target\"][value.value=\"_blank\"]))",
|
|
119
|
+
"message": "<a> without target=\"_blank\" is banned. Prefer a safe Link component or add target for external links."
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"jsPlugins": [{ "name": "@kingsword", "specifier": "../../dist/index.cjs" }],
|
|
3
|
+
"rules": {
|
|
4
|
+
"@kingsword/vitest-no-focused-tests": "error",
|
|
5
|
+
"@kingsword/vitest-no-disabled-tests": "error",
|
|
6
|
+
"@kingsword/vitest-no-test-prefixes": "error",
|
|
7
|
+
"@kingsword/vitest-mock-require-actual": "error",
|
|
8
|
+
"@kingsword/vitest-mock-absolute-paths": "error"
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": ["./vitest.json"],
|
|
3
|
+
"rules": {
|
|
4
|
+
"vitest/prefer-called-once": "error",
|
|
5
|
+
"vitest/prefer-called-times": "error",
|
|
6
|
+
"vitest/prefer-describe-function-title": "error",
|
|
7
|
+
"vitest/prefer-to-be-falsy": "error",
|
|
8
|
+
"vitest/prefer-to-be-object": "error",
|
|
9
|
+
"vitest/prefer-to-be-truthy": "error"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"plugins": ["unicorn", "typescript", "oxc", "vitest"],
|
|
3
|
+
"rules": {
|
|
4
|
+
"jest/expect-expect": "off",
|
|
5
|
+
"jest/no-conditional-expect": "off",
|
|
6
|
+
"jest/no-disabled-tests": "off",
|
|
7
|
+
"jest/no-export": "off",
|
|
8
|
+
"jest/no-focused-tests": "off",
|
|
9
|
+
"jest/no-standalone-expect": "off",
|
|
10
|
+
"jest/require-to-throw-message": "off",
|
|
11
|
+
"jest/valid-describe-callback": "off",
|
|
12
|
+
"jest/valid-expect": "off",
|
|
13
|
+
"jest/valid-title": "off",
|
|
14
|
+
|
|
15
|
+
"vitest/consistent-each-for": "error",
|
|
16
|
+
"vitest/hoisted-apis-on-top": "error",
|
|
17
|
+
"vitest/no-conditional-tests": "error",
|
|
18
|
+
"vitest/require-local-test-context-for-concurrent-snapshots": "error",
|
|
19
|
+
"vitest/warn-todo": "error",
|
|
20
|
+
|
|
21
|
+
"vitest/consistent-vitest-vi": "error",
|
|
22
|
+
"vitest/no-import-node-test": "error"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: ((k) => from[k]).bind(null, key),
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
23
|
+
value: mod,
|
|
24
|
+
enumerable: true
|
|
25
|
+
}) : target, mod));
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
|
|
29
|
+
Object.defineProperty(exports, '__toESM', {
|
|
30
|
+
enumerable: true,
|
|
31
|
+
get: function () {
|
|
32
|
+
return __toESM;
|
|
33
|
+
}
|
|
34
|
+
});
|
package/dist/cli.cjs
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-CbDLau6x.cjs');
|
|
2
|
+
let tiny_bin = require("tiny-bin");
|
|
3
|
+
tiny_bin = require_chunk.__toESM(tiny_bin);
|
|
4
|
+
let node_fs = require("node:fs");
|
|
5
|
+
let node_path = require("node:path");
|
|
6
|
+
let node_url = require("node:url");
|
|
7
|
+
|
|
8
|
+
//#region src/cli.ts
|
|
9
|
+
const __dirname$1 = (0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
|
|
10
|
+
const ALLOWED_PROFILES = [
|
|
11
|
+
"base",
|
|
12
|
+
"lib",
|
|
13
|
+
"react",
|
|
14
|
+
"backend",
|
|
15
|
+
"fullstack"
|
|
16
|
+
];
|
|
17
|
+
const ALLOWED_LEVELS = ["recommended", "strict"];
|
|
18
|
+
const ALLOWED_TESTS = ["none", "vitest"];
|
|
19
|
+
function getVersion() {
|
|
20
|
+
try {
|
|
21
|
+
const pkgPath = (0, node_path.join)(__dirname$1, "..", "package.json");
|
|
22
|
+
return JSON.parse((0, node_fs.readFileSync)(pkgPath, "utf-8")).version || "0.0.0";
|
|
23
|
+
} catch {
|
|
24
|
+
return "0.0.0";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function isAllowed(value, allowed) {
|
|
28
|
+
return allowed.includes(value);
|
|
29
|
+
}
|
|
30
|
+
function readPackageTypeNear(startDir) {
|
|
31
|
+
let current = (0, node_path.resolve)(startDir);
|
|
32
|
+
while (true) {
|
|
33
|
+
const packageJsonPath = (0, node_path.join)(current, "package.json");
|
|
34
|
+
if ((0, node_fs.existsSync)(packageJsonPath)) try {
|
|
35
|
+
return JSON.parse((0, node_fs.readFileSync)(packageJsonPath, "utf-8")).type === "module" ? "module" : "commonjs";
|
|
36
|
+
} catch {
|
|
37
|
+
return "commonjs";
|
|
38
|
+
}
|
|
39
|
+
const parent = (0, node_path.dirname)(current);
|
|
40
|
+
if (parent === current) return "commonjs";
|
|
41
|
+
current = parent;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function renderTsConfigCode(opts, moduleType) {
|
|
45
|
+
if (moduleType === "module") return [
|
|
46
|
+
"import { defineConfig } from \"oxlint\";",
|
|
47
|
+
"import { oxlint } from \"@kingsword/lint-config/config\";",
|
|
48
|
+
"",
|
|
49
|
+
`export default defineConfig(oxlint({ profile: "${opts.profile}", test: "${opts.test}", level: "${opts.level}" }));`,
|
|
50
|
+
""
|
|
51
|
+
].join("\n");
|
|
52
|
+
return [
|
|
53
|
+
"const { defineConfig } = require(\"oxlint\");",
|
|
54
|
+
"const { oxlint } = require(\"@kingsword/lint-config/config\");",
|
|
55
|
+
"",
|
|
56
|
+
`module.exports = defineConfig(oxlint({ profile: "${opts.profile}", test: "${opts.test}", level: "${opts.level}" }));`,
|
|
57
|
+
""
|
|
58
|
+
].join("\n");
|
|
59
|
+
}
|
|
60
|
+
const version = getVersion();
|
|
61
|
+
(0, tiny_bin.default)("xlint", "Generate oxlint config presets for @kingsword/lint-config").package("@kingsword/lint-config", version).command("init", "Generate oxlint.config.ts").argument("[profile]", `Project profile (${ALLOWED_PROFILES.join(", ")})`).option("-f, --force", "Overwrite existing oxlint.config.ts").option("--profile <profile>", `Project profile (${ALLOWED_PROFILES.join(", ")})`).option("--test <test>", `Test mode (${ALLOWED_TESTS.join(", ")})`).option("--level <level>", `Strictness level (${ALLOWED_LEVELS.join(", ")})`).option("-o, --output <path>", "Output config file path (default: ./oxlint.config.ts)").option("--print", "Print the generated config to stdout (no write)").action((options, args) => {
|
|
62
|
+
const force = options.force === true;
|
|
63
|
+
const profileFromFlag = options.profile;
|
|
64
|
+
const profileFromPositional = args?.[0] || void 0;
|
|
65
|
+
const profileRaw = profileFromFlag || profileFromPositional || "lib";
|
|
66
|
+
const testRaw = options.test || "none";
|
|
67
|
+
const levelRaw = options.level || "recommended";
|
|
68
|
+
const print = options.print === true;
|
|
69
|
+
const outputRaw = options.output;
|
|
70
|
+
if (!isAllowed(profileRaw, ALLOWED_PROFILES)) {
|
|
71
|
+
console.error(`Unknown profile: ${profileRaw}`);
|
|
72
|
+
console.error(`Expected one of: ${ALLOWED_PROFILES.join(", ")}`);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
if (!isAllowed(testRaw, ALLOWED_TESTS)) {
|
|
76
|
+
console.error(`Unknown test mode: ${testRaw}`);
|
|
77
|
+
console.error(`Expected one of: ${ALLOWED_TESTS.join(", ")}`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
if (!isAllowed(levelRaw, ALLOWED_LEVELS)) {
|
|
81
|
+
console.error(`Unknown level: ${levelRaw}`);
|
|
82
|
+
console.error(`Expected one of: ${ALLOWED_LEVELS.join(", ")}`);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
const outAbs = outputRaw ? (0, node_path.resolve)(process.cwd(), outputRaw) : (0, node_path.resolve)(process.cwd(), "oxlint.config.ts");
|
|
86
|
+
const outDir = (0, node_path.dirname)(outAbs);
|
|
87
|
+
const moduleType = readPackageTypeNear(outDir);
|
|
88
|
+
const code = renderTsConfigCode({
|
|
89
|
+
profile: profileRaw,
|
|
90
|
+
test: testRaw,
|
|
91
|
+
level: levelRaw
|
|
92
|
+
}, moduleType);
|
|
93
|
+
if (print) {
|
|
94
|
+
process.stdout.write(code);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if ((0, node_fs.existsSync)(outAbs) && !force) {
|
|
98
|
+
console.error(`Refusing to overwrite existing ${outAbs}. Use --force to overwrite.`);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
(0, node_fs.mkdirSync)(outDir, { recursive: true });
|
|
102
|
+
(0, node_fs.writeFileSync)(outAbs, code);
|
|
103
|
+
console.log(`Wrote ${outAbs}`);
|
|
104
|
+
}).run();
|
|
105
|
+
|
|
106
|
+
//#endregion
|
package/dist/cli.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/cli.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|