@lark-apaas/fullstack-presets 1.1.2 → 1.1.3-beta.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/README.md +162 -1
- package/lib/custom-eslint-rules/index.d.ts +3 -0
- package/lib/custom-eslint-rules/index.js +10 -0
- package/lib/custom-eslint-rules/no-nested-styled-jsx.d.ts +13 -0
- package/lib/custom-eslint-rules/no-nested-styled-jsx.js +122 -0
- package/lib/simple/recommend/eslint/eslint-client.d.ts +20 -2
- package/lib/simple/recommend/eslint/eslint-client.js +45 -2
- package/lib/simple/recommend/eslint/index.d.ts +15 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -1,2 +1,163 @@
|
|
|
1
1
|
# 全栈技术栈 Presets
|
|
2
|
-
独立拆分 simple 目录,属于全栈精简版,目前妙搭场景专用。
|
|
2
|
+
独立拆分 simple 目录,属于全栈精简版,目前妙搭场景专用。
|
|
3
|
+
|
|
4
|
+
## ESLint 自定义规则
|
|
5
|
+
|
|
6
|
+
### `no-nested-styled-jsx`
|
|
7
|
+
|
|
8
|
+
检测嵌套的 styled-jsx 标签,防止编译错误。https://nextjs.org/docs/messages/nested-styled-jsx-tags
|
|
9
|
+
|
|
10
|
+
该规则镜像了 styled-jsx babel 插件中的验证逻辑:
|
|
11
|
+
- [babel.js#L215](https://github.com/vercel/styled-jsx/blob/d7a59379134d73afaeb98177387cd62d54d746be/src/babel.js#L215)
|
|
12
|
+
- [babel.js#L222](https://github.com/vercel/styled-jsx/blob/d7a59379134d73afaeb98177387cd62d54d746be/src/babel.js#L222)
|
|
13
|
+
|
|
14
|
+
#### 使用方式
|
|
15
|
+
|
|
16
|
+
该规则已在 `eslint-client.ts` 配置中默认启用,无需额外配置:
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import clientConfig from '@lark-apaas/fullstack-presets/recommend/eslint/eslint-client';
|
|
20
|
+
|
|
21
|
+
export default [
|
|
22
|
+
clientConfig,
|
|
23
|
+
// 其他配置...
|
|
24
|
+
];
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
如需单独使用该规则:
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { customRules } from '@lark-apaas/fullstack-presets/custom-eslint-rules';
|
|
31
|
+
|
|
32
|
+
export default [
|
|
33
|
+
{
|
|
34
|
+
plugins: {
|
|
35
|
+
'@lark-apaas': { rules: customRules },
|
|
36
|
+
},
|
|
37
|
+
rules: {
|
|
38
|
+
'@lark-apaas/no-nested-styled-jsx': 'error',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
#### 错误信息
|
|
45
|
+
|
|
46
|
+
当检测到嵌套的 styled-jsx 标签时,规则会提供详细的错误信息,指出与哪一行的外层 styled-jsx 标签冲突:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
17:23 error Detected nested styled-jsx tag. The outer styled-jsx tag is at line 4. Read more: https://nextjs.org/docs/messages/nested-styled-jsx-tags @lark-apaas/no-nested-styled-jsx
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
这样可以快速定位到冲突的外层 styled-jsx 标签,方便修复问题。
|
|
53
|
+
|
|
54
|
+
#### 自定义错误信息
|
|
55
|
+
|
|
56
|
+
可通过配置自定义报错信息:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
rules: {
|
|
60
|
+
'@lark-apaas/no-nested-styled-jsx': ['error', {
|
|
61
|
+
message: '禁止嵌套 styled-jsx 标签,请将 <style jsx> 移到组件根级别'
|
|
62
|
+
}],
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
注意:使用自定义错误信息时,将不会显示外层 styled-jsx 标签的行号信息。
|
|
67
|
+
|
|
68
|
+
#### 参考资料
|
|
69
|
+
|
|
70
|
+
- [Next.js 错误说明](https://nextjs.org/docs/messages/nested-styled-jsx-tags)
|
|
71
|
+
- [styled-jsx GitHub Issue #42](https://github.com/vercel/styled-jsx/issues/42)
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
### 路由守卫规则 (RoutesComponent)
|
|
76
|
+
|
|
77
|
+
保护 `client/src/app.tsx` 中的 RoutesComponent 组件结构,确保路由配置不被意外破坏。
|
|
78
|
+
|
|
79
|
+
#### 规则目的
|
|
80
|
+
|
|
81
|
+
该规则强制 `RoutesComponent` 必须直接返回 `<Routes>` 组件,不允许在外层添加任何包装元素(如 `<div>`、`<BrowserRouter>` 等)。这确保了:
|
|
82
|
+
- ✅ 路由结构保持一致和可预测
|
|
83
|
+
- ✅ 防止开发者误修改核心路由架构
|
|
84
|
+
- ✅ 允许在 `<Routes>` 内部自由添加/修改/删除路由配置
|
|
85
|
+
|
|
86
|
+
#### 生效范围
|
|
87
|
+
|
|
88
|
+
**仅在 loose 模式下对 `client/src/app.tsx` 文件生效**
|
|
89
|
+
|
|
90
|
+
该规则通过环境变量 `FORCE_FRAMEWORK_LINT_LOOSE_MODE=true` 启用,并且只检查项目中的 `client/src/app.tsx` 文件。
|
|
91
|
+
|
|
92
|
+
#### 错误示例
|
|
93
|
+
|
|
94
|
+
❌ **不允许:添加外层包装元素**
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
// ❌ 错误:使用 div 包装
|
|
98
|
+
const RoutesComponent = () => (
|
|
99
|
+
<div>
|
|
100
|
+
<Routes>
|
|
101
|
+
<Route path="/" element={<HomePage />} />
|
|
102
|
+
</Routes>
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
// ❌ 错误:使用 BrowserRouter 包装
|
|
107
|
+
const RoutesComponent = () => {
|
|
108
|
+
return (
|
|
109
|
+
<BrowserRouter>
|
|
110
|
+
<Routes>
|
|
111
|
+
<Route path="/" element={<HomePage />} />
|
|
112
|
+
</Routes>
|
|
113
|
+
</BrowserRouter>
|
|
114
|
+
);
|
|
115
|
+
};
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
#### 正确示例
|
|
119
|
+
|
|
120
|
+
✅ **允许:直接返回 Routes,在内部修改路由**
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
// ✅ 正确:直接返回 Routes
|
|
124
|
+
const RoutesComponent = () => (
|
|
125
|
+
<Routes>
|
|
126
|
+
<Route path="/" element={<HomePage />} />
|
|
127
|
+
<Route path="/about" element={<AboutPage />} />
|
|
128
|
+
<Route path="/users" element={<UsersPage />} />
|
|
129
|
+
<Route path="*" element={<NotFound />} />
|
|
130
|
+
</Routes>
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
// ✅ 正确:使用嵌套路由
|
|
134
|
+
const RoutesComponent = () => (
|
|
135
|
+
<Routes>
|
|
136
|
+
<Route element={<Layout />}>
|
|
137
|
+
<Route index element={<HomePage />} />
|
|
138
|
+
<Route path="/about" element={<AboutPage />} />
|
|
139
|
+
</Route>
|
|
140
|
+
<Route path="*" element={<NotFound />} />
|
|
141
|
+
</Routes>
|
|
142
|
+
);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
#### 错误信息
|
|
146
|
+
|
|
147
|
+
当违反规则时,会看到以下错误信息:
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
47:23 error RoutesComponent must return <Routes> directly without any wrapper. Do not add <div>, <BrowserRouter> or other wrappers. You can only modify routes inside <Routes> (add/edit/remove <Route> elements). no-restricted-syntax
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
错误信息包含三个层次的指导:
|
|
154
|
+
1. **明确要求**:必须直接返回 `<Routes>`,不能有包装器
|
|
155
|
+
2. **具体禁止**:不要添加 `<div>`、`<BrowserRouter>` 或其他包装器
|
|
156
|
+
3. **允许操作**:可以在 `<Routes>` 内部添加/编辑/删除 `<Route>` 元素
|
|
157
|
+
|
|
158
|
+
#### 使用场景
|
|
159
|
+
|
|
160
|
+
该规则主要用于妙搭等需要保护核心路由结构的场景。在这些场景中:
|
|
161
|
+
- 框架会自动管理路由的外层结构(如 BrowserRouter)
|
|
162
|
+
- 开发者只需关注路由配置本身(路径、组件映射等)
|
|
163
|
+
- 防止开发者误修改导致路由失效
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.customRules = void 0;
|
|
7
|
+
const no_nested_styled_jsx_1 = __importDefault(require("./no-nested-styled-jsx"));
|
|
8
|
+
exports.customRules = {
|
|
9
|
+
'no-nested-styled-jsx': no_nested_styled_jsx_1.default,
|
|
10
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint rule to detect nested styled-jsx tags.
|
|
3
|
+
*
|
|
4
|
+
* This rule mirrors the validation logic in styled-jsx's babel plugin:
|
|
5
|
+
* @see https://github.com/vercel/styled-jsx/blob/d7a59379134d73afaeb98177387cd62d54d746be/src/babel.js#L215
|
|
6
|
+
* @see https://github.com/vercel/styled-jsx/blob/d7a59379134d73afaeb98177387cd62d54d746be/src/babel.js#L222
|
|
7
|
+
*
|
|
8
|
+
* Test fixture:
|
|
9
|
+
* @see https://github.com/vercel/styled-jsx/blob/d7a59379134d73afaeb98177387cd62d54d746be/test/fixtures/nested-style-tags.js
|
|
10
|
+
*/
|
|
11
|
+
import type { Rule } from 'eslint';
|
|
12
|
+
declare const rule: Rule.RuleModule;
|
|
13
|
+
export default rule;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const DEFAULT_MESSAGE = 'Detected nested styled-jsx tag. Read more: https://nextjs.org/docs/messages/nested-styled-jsx-tags';
|
|
4
|
+
const rule = {
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'problem',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'Disallow nested styled-jsx tags',
|
|
9
|
+
category: 'Possible Errors',
|
|
10
|
+
recommended: true,
|
|
11
|
+
url: 'https://nextjs.org/docs/messages/nested-styled-jsx-tags',
|
|
12
|
+
},
|
|
13
|
+
schema: [
|
|
14
|
+
{
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
message: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'Custom error message',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
additionalProperties: false,
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
messages: {
|
|
26
|
+
nestedStyleJsx: DEFAULT_MESSAGE,
|
|
27
|
+
nestedStyleJsxWithLocation: 'Detected nested styled-jsx tag. The outer styled-jsx tag is at line {{line}}. Read more: https://nextjs.org/docs/messages/nested-styled-jsx-tags',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
create(context) {
|
|
31
|
+
const options = context.options[0];
|
|
32
|
+
const customMessage = options?.message;
|
|
33
|
+
return {
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35
|
+
JSXElement(node) {
|
|
36
|
+
const openingElement = node.openingElement;
|
|
37
|
+
if (!openingElement)
|
|
38
|
+
return;
|
|
39
|
+
const elementName = openingElement.name;
|
|
40
|
+
// Check if this is a <style> element with jsx attribute
|
|
41
|
+
if (elementName.type !== 'JSXIdentifier' || elementName.name !== 'style') {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
45
|
+
const hasJsxAttribute = openingElement.attributes.some((attr) => attr.type === 'JSXAttribute' &&
|
|
46
|
+
attr.name?.type === 'JSXIdentifier' &&
|
|
47
|
+
attr.name?.name === 'jsx');
|
|
48
|
+
if (!hasJsxAttribute) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// Count JSXElement and JSXFragment ancestors and find the outer styled-jsx tag
|
|
52
|
+
// styled-jsx uses ignoreClosing counter that increments on JSXOpeningElement enter
|
|
53
|
+
// and checks if ignoreClosing > 1 on style tag exit
|
|
54
|
+
// @see https://github.com/vercel/styled-jsx/blob/d7a59379134d73afaeb98177387cd62d54d746be/src/babel.js#L222
|
|
55
|
+
// Note: JSXFragment (<>...</>) should also be counted as a container
|
|
56
|
+
let jsxElementCount = 0;
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
58
|
+
let outerStyledJsxNode = null;
|
|
59
|
+
let current = node.parent;
|
|
60
|
+
while (current) {
|
|
61
|
+
// Count both JSXElement and JSXFragment as containers
|
|
62
|
+
if (current.type === 'JSXElement' || current.type === 'JSXFragment') {
|
|
63
|
+
jsxElementCount++;
|
|
64
|
+
// Check if any sibling or ancestor siblings contain a styled-jsx tag
|
|
65
|
+
// Always update to find the outermost styled-jsx, not the first encountered
|
|
66
|
+
if (current.parent) {
|
|
67
|
+
const parentNode = current.parent;
|
|
68
|
+
// Check if parent has children that we can iterate
|
|
69
|
+
const children = parentNode.children ||
|
|
70
|
+
(parentNode.type === 'JSXElement' || parentNode.type === 'JSXFragment' ? parentNode.children : null);
|
|
71
|
+
if (children && Array.isArray(children)) {
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
73
|
+
for (const child of children) {
|
|
74
|
+
if (child.type === 'JSXElement' && child !== node) {
|
|
75
|
+
const childOpeningElement = child.openingElement;
|
|
76
|
+
if (childOpeningElement) {
|
|
77
|
+
const childElementName = childOpeningElement.name;
|
|
78
|
+
if (childElementName?.type === 'JSXIdentifier' &&
|
|
79
|
+
childElementName?.name === 'style') {
|
|
80
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
81
|
+
const hasChildJsxAttr = childOpeningElement.attributes?.some((attr) => attr.type === 'JSXAttribute' &&
|
|
82
|
+
attr.name?.type === 'JSXIdentifier' &&
|
|
83
|
+
attr.name?.name === 'jsx');
|
|
84
|
+
if (hasChildJsxAttr) {
|
|
85
|
+
// Always update to find the outermost styled-jsx
|
|
86
|
+
outerStyledJsxNode = child;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
current = current.parent;
|
|
97
|
+
}
|
|
98
|
+
// If there's more than 1 JSXElement ancestor, the style tag is nested
|
|
99
|
+
if (jsxElementCount > 1) {
|
|
100
|
+
if (outerStyledJsxNode && outerStyledJsxNode.loc) {
|
|
101
|
+
// Report with location information about the outer styled-jsx tag
|
|
102
|
+
context.report({
|
|
103
|
+
node,
|
|
104
|
+
messageId: 'nestedStyleJsxWithLocation',
|
|
105
|
+
data: {
|
|
106
|
+
line: outerStyledJsxNode.loc.start.line,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
// Fallback to the original message if we can't find the outer styled-jsx tag
|
|
112
|
+
context.report({
|
|
113
|
+
node,
|
|
114
|
+
...(customMessage ? { message: customMessage } : { messageId: 'nestedStyleJsx' }),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
exports.default = rule;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
declare const
|
|
1
|
+
export declare const looseRestrictSyntaxRules: {
|
|
2
|
+
selector: string;
|
|
3
|
+
message: string;
|
|
4
|
+
}[];
|
|
5
|
+
declare const _default: ({
|
|
2
6
|
name: string;
|
|
3
7
|
languageOptions: {
|
|
4
8
|
ecmaVersion: number;
|
|
@@ -11,6 +15,11 @@ declare const _default: {
|
|
|
11
15
|
globals: any;
|
|
12
16
|
};
|
|
13
17
|
plugins: {
|
|
18
|
+
'@lark-apaas'?: {
|
|
19
|
+
rules: {
|
|
20
|
+
'no-nested-styled-jsx': import("eslint").Rule.RuleModule;
|
|
21
|
+
};
|
|
22
|
+
} | undefined;
|
|
14
23
|
'react-hooks': any;
|
|
15
24
|
import: any;
|
|
16
25
|
};
|
|
@@ -25,5 +34,14 @@ declare const _default: {
|
|
|
25
34
|
};
|
|
26
35
|
};
|
|
27
36
|
rules: any;
|
|
28
|
-
}
|
|
37
|
+
} | {
|
|
38
|
+
name: string;
|
|
39
|
+
files: string[];
|
|
40
|
+
rules: {
|
|
41
|
+
'no-restricted-syntax': (string | {
|
|
42
|
+
message: string;
|
|
43
|
+
selector: string;
|
|
44
|
+
})[];
|
|
45
|
+
};
|
|
46
|
+
} | null)[];
|
|
29
47
|
export default _default;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.looseRestrictSyntaxRules = void 0;
|
|
3
4
|
const globals = require('globals');
|
|
4
5
|
const reactHooks = require('eslint-plugin-react-hooks');
|
|
5
6
|
const tseslint = require('typescript-eslint');
|
|
6
7
|
const importPlugin = require('eslint-plugin-import');
|
|
8
|
+
const custom_eslint_rules_1 = require("../../../custom-eslint-rules");
|
|
7
9
|
// 检查是否启用宽松 lint 模式
|
|
8
10
|
const isLooseMode = process.env.FORCE_FRAMEWORK_LINT_LOOSE_MODE === 'true';
|
|
9
11
|
// 基础语法规则:所有模式都启用(包括 loose 模式)
|
|
@@ -29,6 +31,20 @@ const baseSyntaxRules = [
|
|
|
29
31
|
message: "Please don't use relative paths in <a> tags. Use NavLink from 'react-router-dom' instead.",
|
|
30
32
|
},
|
|
31
33
|
];
|
|
34
|
+
// loose模式特化的规则
|
|
35
|
+
exports.looseRestrictSyntaxRules = [
|
|
36
|
+
// 约束RoutesComponent路由组件 dom规则
|
|
37
|
+
{
|
|
38
|
+
// 箭头函数 block body
|
|
39
|
+
selector: "VariableDeclarator[id.name='RoutesComponent'] > ArrowFunctionExpression > BlockStatement > ReturnStatement[argument.type='JSXElement'][argument.openingElement.name.name!='Routes']",
|
|
40
|
+
message: 'RoutesComponent must return <Routes> directly without any wrapper. Do not add <div>, <BrowserRouter> or other wrappers. You can only modify routes inside <Routes> (add/edit/remove <Route> elements).',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
// 箭头函数 expression body
|
|
44
|
+
selector: "VariableDeclarator[id.name='RoutesComponent'] > ArrowFunctionExpression > JSXElement:not([openingElement.name.name='Routes'])",
|
|
45
|
+
message: 'RoutesComponent must return <Routes> directly without any wrapper. Do not add <div>, <BrowserRouter> or other wrappers. You can only modify routes inside <Routes> (add/edit/remove <Route> elements).',
|
|
46
|
+
},
|
|
47
|
+
];
|
|
32
48
|
// 严格语法规则:仅正常模式启用,loose 模式下不启用
|
|
33
49
|
const strictSyntaxRules = [
|
|
34
50
|
// 限制使用 fetch(推荐使用生成的 API Client)
|
|
@@ -78,15 +94,23 @@ const strictSyntaxRules = [
|
|
|
78
94
|
message: 'Classname "text-accent" would cause visibility issues. Consider using proper semantic color tokens from `client/src/tailwind-theme.css`',
|
|
79
95
|
},
|
|
80
96
|
];
|
|
97
|
+
const looseSpecificPlugins = {
|
|
98
|
+
'@lark-apaas': { rules: custom_eslint_rules_1.customRules }
|
|
99
|
+
};
|
|
100
|
+
const looseSpecificRules = {
|
|
101
|
+
'@lark-apaas/no-nested-styled-jsx': 'error'
|
|
102
|
+
};
|
|
81
103
|
// 宽松模式下覆盖的规则(关闭非关键规则)
|
|
82
104
|
const looseOverrideRules = isLooseMode
|
|
83
105
|
? {
|
|
106
|
+
...looseSpecificRules,
|
|
84
107
|
'@typescript-eslint/no-unsafe-function-type': 'off',
|
|
85
108
|
'@typescript-eslint/no-unused-expressions': 'off',
|
|
86
109
|
'no-useless-escape': 'off', // 允许不必要的转义字符
|
|
87
110
|
}
|
|
88
111
|
: {};
|
|
89
|
-
|
|
112
|
+
// 基础配置(适用于所有文件)
|
|
113
|
+
const baseConfig = {
|
|
90
114
|
name: 'fullstack-presets/client-recommend',
|
|
91
115
|
languageOptions: {
|
|
92
116
|
ecmaVersion: 2020,
|
|
@@ -104,6 +128,7 @@ exports.default = {
|
|
|
104
128
|
plugins: {
|
|
105
129
|
'react-hooks': reactHooks,
|
|
106
130
|
import: importPlugin,
|
|
131
|
+
...(isLooseMode ? looseSpecificPlugins : {}),
|
|
107
132
|
},
|
|
108
133
|
settings: {
|
|
109
134
|
'import/resolver': {
|
|
@@ -149,8 +174,26 @@ exports.default = {
|
|
|
149
174
|
],
|
|
150
175
|
},
|
|
151
176
|
],
|
|
152
|
-
'no-restricted-syntax': [
|
|
177
|
+
'no-restricted-syntax': [
|
|
178
|
+
'error',
|
|
179
|
+
...baseSyntaxRules,
|
|
180
|
+
// 注意:严格模式的 strictSyntaxRules 仍然应用于所有文件
|
|
181
|
+
...(isLooseMode ? [] : strictSyntaxRules),
|
|
182
|
+
],
|
|
153
183
|
// 宽松模式下覆盖上述规则
|
|
154
184
|
...looseOverrideRules,
|
|
155
185
|
},
|
|
156
186
|
};
|
|
187
|
+
// app.tsx 专属配置(仅在 loose 模式下生效)
|
|
188
|
+
const appTsxConfig = isLooseMode
|
|
189
|
+
? {
|
|
190
|
+
// 路由守卫规则
|
|
191
|
+
name: '@lark-apaas/client-recommend/app-tsx',
|
|
192
|
+
files: ['client/src/app.tsx'],
|
|
193
|
+
rules: {
|
|
194
|
+
'no-restricted-syntax': ['error', ...baseSyntaxRules, ...exports.looseRestrictSyntaxRules],
|
|
195
|
+
},
|
|
196
|
+
}
|
|
197
|
+
: null;
|
|
198
|
+
// 导出配置数组,过滤掉 null
|
|
199
|
+
exports.default = [baseConfig, appTsxConfig].filter(Boolean);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const eslintPresets: {
|
|
2
2
|
client: ({
|
|
3
3
|
readonly rules: Readonly<import("eslint").Linter.RulesRecord>;
|
|
4
|
-
} | import("typescript-eslint/dist/compatibility-types").CompatibleConfig | {
|
|
4
|
+
} | import("typescript-eslint/dist/compatibility-types").CompatibleConfig | ({
|
|
5
5
|
name: string;
|
|
6
6
|
languageOptions: {
|
|
7
7
|
ecmaVersion: number;
|
|
@@ -14,6 +14,11 @@ export declare const eslintPresets: {
|
|
|
14
14
|
globals: any;
|
|
15
15
|
};
|
|
16
16
|
plugins: {
|
|
17
|
+
'@lark-apaas'?: {
|
|
18
|
+
rules: {
|
|
19
|
+
'no-nested-styled-jsx': import("eslint").Rule.RuleModule;
|
|
20
|
+
};
|
|
21
|
+
} | undefined;
|
|
17
22
|
'react-hooks': any;
|
|
18
23
|
import: any;
|
|
19
24
|
};
|
|
@@ -29,6 +34,15 @@ export declare const eslintPresets: {
|
|
|
29
34
|
};
|
|
30
35
|
rules: any;
|
|
31
36
|
} | {
|
|
37
|
+
name: string;
|
|
38
|
+
files: string[];
|
|
39
|
+
rules: {
|
|
40
|
+
'no-restricted-syntax': (string | {
|
|
41
|
+
message: string;
|
|
42
|
+
selector: string;
|
|
43
|
+
})[];
|
|
44
|
+
};
|
|
45
|
+
} | null)[] | {
|
|
32
46
|
ignores: string[];
|
|
33
47
|
})[];
|
|
34
48
|
server: ({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lark-apaas/fullstack-presets",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3-beta.0",
|
|
4
4
|
"files": [
|
|
5
5
|
"lib"
|
|
6
6
|
],
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"build": "tsc && npm run copy:json",
|
|
19
19
|
"copy:json": "node scripts/copy-json.js",
|
|
20
20
|
"watch": "tsc --watch",
|
|
21
|
+
"test": "vitest",
|
|
21
22
|
"prepublishOnly": "npm run build"
|
|
22
23
|
},
|
|
23
24
|
"dependencies": {
|
|
@@ -33,8 +34,11 @@
|
|
|
33
34
|
"tailwindcss-animate": "^1.0.7"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
37
|
+
"@babel/core": "^7.24.0",
|
|
38
|
+
"@babel/preset-react": "^7.24.0",
|
|
36
39
|
"@types/eslint": "^9.6.0",
|
|
37
40
|
"eslint": "^9.35.0",
|
|
41
|
+
"styled-jsx": "^5.1.6",
|
|
38
42
|
"typescript": "^5.9.2",
|
|
39
43
|
"typescript-eslint": "^8.44.0"
|
|
40
44
|
},
|