前后端基本架构和完全excel表的解析及统计图表的生成以及excel表的到出
This commit is contained in:
28
frontend/.rules/SelectItem.yml
Normal file
28
frontend/.rules/SelectItem.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
id: selectItemWithEmptyValue
|
||||
language: Tsx
|
||||
files:
|
||||
- src/**/*.tsx
|
||||
rule:
|
||||
kind: jsx_opening_element
|
||||
all:
|
||||
- has:
|
||||
kind: identifier
|
||||
regex: '^SelectItem$'
|
||||
- has:
|
||||
kind: jsx_attribute
|
||||
all:
|
||||
- has:
|
||||
kind: property_identifier
|
||||
regex: '^value$'
|
||||
- any:
|
||||
- has:
|
||||
kind: string
|
||||
regex: '^""$'
|
||||
- has:
|
||||
kind: jsx_expression
|
||||
has:
|
||||
kind: string
|
||||
regex: '^""$'
|
||||
|
||||
message: "检测到 SelectItem 组件使用空字符串 value: $MATCH, 这是错误用法, 运行时会报错, 请修改, 如果想实现全选,建议使用all代替空字符串"
|
||||
severity: error
|
||||
39
frontend/.rules/check.sh
Normal file
39
frontend/.rules/check.sh
Normal file
@@ -0,0 +1,39 @@
|
||||
#!/bin/bash
|
||||
|
||||
ast-grep scan -r .rules/SelectItem.yml
|
||||
|
||||
ast-grep scan -r .rules/contrast.yml
|
||||
|
||||
ast-grep scan -r .rules/supabase-google-sso.yml
|
||||
|
||||
ast-grep scan -r .rules/toast-hook.yml
|
||||
|
||||
ast-grep scan -r .rules/slot-nesting.yml
|
||||
|
||||
ast-grep scan -r .rules/require-button-interaction.yml
|
||||
|
||||
useauth_output=$(ast-grep scan -r .rules/useAuth.yml 2>/dev/null)
|
||||
|
||||
if [ -z "$useauth_output" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
authprovider_output=$(ast-grep scan -r .rules/authProvider.yml 2>/dev/null)
|
||||
|
||||
if [ -n "$authprovider_output" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "=== ast-grep scan -r .rules/useAuth.yml output ==="
|
||||
echo "$useauth_output"
|
||||
echo ""
|
||||
echo "=== ast-grep scan -r .rules/authProvider.yml output ==="
|
||||
echo "$authprovider_output"
|
||||
echo ""
|
||||
echo "⚠️ Issue detected:"
|
||||
echo "The code uses useAuth Hook but does not have AuthProvider component wrapping the components."
|
||||
echo "Please ensure that components using useAuth are wrapped with AuthProvider to provide proper authentication context."
|
||||
echo ""
|
||||
echo "Suggested fixes:"
|
||||
echo "1. Add AuthProvider wrapper in app.tsx or corresponding root component"
|
||||
echo "2. Ensure all components using useAuth are within AuthProvider scope"
|
||||
103
frontend/.rules/contrast.yml
Normal file
103
frontend/.rules/contrast.yml
Normal file
@@ -0,0 +1,103 @@
|
||||
id: button-outline-text-foreground-contrast
|
||||
language: tsx
|
||||
files:
|
||||
- src/**/*.tsx
|
||||
message: "Outline button with text-foreground class causes invisible text. The outline variant has a transparent background, making text-foreground color blend with the background and become unreadable. Use text-primary or another contrasting color instead."
|
||||
rule:
|
||||
kind: jsx_element
|
||||
has:
|
||||
kind: jsx_opening_element
|
||||
all:
|
||||
- has:
|
||||
field: name
|
||||
regex: "^Button$"
|
||||
- has:
|
||||
kind: jsx_attribute
|
||||
all:
|
||||
- has:
|
||||
kind: property_identifier
|
||||
regex: "^variant$"
|
||||
- has:
|
||||
kind: string
|
||||
has:
|
||||
kind: string_fragment
|
||||
regex: "^outline$"
|
||||
- has:
|
||||
kind: jsx_attribute
|
||||
all:
|
||||
- has:
|
||||
kind: property_identifier
|
||||
regex: "^className$"
|
||||
- has:
|
||||
kind: string
|
||||
has:
|
||||
kind: string_fragment
|
||||
regex: "(^|\\s)text-foreground(\\s|$)"
|
||||
---
|
||||
id: button-default-text-primary-contrast
|
||||
language: tsx
|
||||
files:
|
||||
- src/**/*.tsx
|
||||
message: "Default button with text-primary class causes poor contrast. The default variant has a primary-colored background, making text-primary color blend with the background and become hard to read. Remove the text-primary class or specify a different variant like 'outline' or 'ghost'."
|
||||
rule:
|
||||
kind: jsx_element
|
||||
has:
|
||||
kind: jsx_opening_element
|
||||
all:
|
||||
- has:
|
||||
field: name
|
||||
regex: "^Button$"
|
||||
- has:
|
||||
kind: jsx_attribute
|
||||
all:
|
||||
- has:
|
||||
kind: property_identifier
|
||||
regex: "^className$"
|
||||
- has:
|
||||
kind: string
|
||||
has:
|
||||
kind: string_fragment
|
||||
regex: "(^|\\s)text-primary(\\s|$)"
|
||||
- not:
|
||||
has:
|
||||
kind: jsx_attribute
|
||||
has:
|
||||
kind: property_identifier
|
||||
regex: "^variant$"
|
||||
|
||||
---
|
||||
id: button-outline-white-gray-contrast
|
||||
language: tsx
|
||||
files:
|
||||
- src/**/*.tsx
|
||||
message: "Outline button with white/gray text color has poor contrast. Remove the text color class and use the default button text color."
|
||||
rule:
|
||||
kind: jsx_element
|
||||
has:
|
||||
kind: jsx_opening_element
|
||||
all:
|
||||
- has:
|
||||
field: name
|
||||
regex: "^Button$"
|
||||
- has:
|
||||
kind: jsx_attribute
|
||||
all:
|
||||
- has:
|
||||
kind: property_identifier
|
||||
regex: "^variant$"
|
||||
- has:
|
||||
kind: string
|
||||
has:
|
||||
kind: string_fragment
|
||||
regex: "^outline$"
|
||||
- has:
|
||||
kind: jsx_attribute
|
||||
all:
|
||||
- has:
|
||||
kind: property_identifier
|
||||
regex: "^className$"
|
||||
- has:
|
||||
kind: string
|
||||
has:
|
||||
kind: string_fragment
|
||||
regex: "(^|\\s)text-(white|gray)(-[0-9]+)?(\\s|$)"
|
||||
56
frontend/.rules/require-button-interaction.yml
Normal file
56
frontend/.rules/require-button-interaction.yml
Normal file
@@ -0,0 +1,56 @@
|
||||
id: require-button-interaction
|
||||
language: Tsx
|
||||
files:
|
||||
- src/**/*.tsx
|
||||
- src/**/*.jsx
|
||||
rule:
|
||||
kind: jsx_opening_element
|
||||
all:
|
||||
# 必须是 <Button> 组件
|
||||
- has:
|
||||
kind: identifier
|
||||
regex: '^Button$'
|
||||
# 没有 onClick
|
||||
- not:
|
||||
has:
|
||||
kind: jsx_attribute
|
||||
has:
|
||||
kind: property_identifier
|
||||
regex: '^onClick$'
|
||||
# 没有 asChild
|
||||
- not:
|
||||
has:
|
||||
kind: jsx_attribute
|
||||
has:
|
||||
kind: property_identifier
|
||||
regex: '^asChild$'
|
||||
# 没有 type="submit" 或 type="reset"
|
||||
- not:
|
||||
has:
|
||||
kind: jsx_attribute
|
||||
all:
|
||||
- has:
|
||||
kind: property_identifier
|
||||
regex: '^type$'
|
||||
- any:
|
||||
- has:
|
||||
kind: string
|
||||
regex: '^"(submit|reset)"$'
|
||||
- has:
|
||||
kind: jsx_expression
|
||||
has:
|
||||
kind: string
|
||||
regex: '^"(submit|reset)"$'
|
||||
# 不在 *Trigger 组件内部(如 DialogTrigger、SheetTrigger)
|
||||
- not:
|
||||
inside:
|
||||
stopBy: end
|
||||
kind: jsx_element
|
||||
has:
|
||||
kind: jsx_opening_element
|
||||
has:
|
||||
kind: identifier
|
||||
regex: 'Trigger$'
|
||||
|
||||
message: '<Button> 必须是可点击的:请添加 onClick、type="submit"、type="reset"、asChild 属性,或将其包裹在 *Trigger 组件中'
|
||||
severity: error
|
||||
52
frontend/.rules/slot-nesting.yml
Normal file
52
frontend/.rules/slot-nesting.yml
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
id: radix-trigger-formcontrol-nesting
|
||||
language: tsx
|
||||
files:
|
||||
- src/**/*.tsx
|
||||
message: |
|
||||
❌ 检测到危险的 Slot 嵌套:Radix UI Trigger (asChild) 内包裹 FormControl
|
||||
|
||||
问题代码:
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl> ← 会导致点击事件失效
|
||||
<Button>...</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
|
||||
正确写法:
|
||||
<PopoverTrigger asChild>
|
||||
<Button>...</Button> ← 直接使用 Button
|
||||
</PopoverTrigger>
|
||||
|
||||
原因:FormControl 和 Trigger 都使用 Radix UI 的 Slot 机制,双层嵌套会导致:
|
||||
- ref 传递链断裂
|
||||
- 点击事件丢失
|
||||
- 内部组件无法交互
|
||||
|
||||
FormControl 只应该用于原生表单控件(Input, Textarea, Select),不要用于触发器按钮。
|
||||
severity: error
|
||||
rule:
|
||||
kind: jsx_element
|
||||
all:
|
||||
# 开始标签需要满足的条件
|
||||
- has:
|
||||
kind: jsx_opening_element
|
||||
all:
|
||||
# 匹配所有 Radix UI 的 Trigger 组件
|
||||
- has:
|
||||
field: name
|
||||
regex: "^(Popover|Dialog|DropdownMenu|AlertDialog|HoverCard|Menubar|NavigationMenu|ContextMenu|Tooltip)Trigger$"
|
||||
# 必须有 asChild 属性
|
||||
- has:
|
||||
kind: jsx_attribute
|
||||
has:
|
||||
kind: property_identifier
|
||||
regex: "^asChild$"
|
||||
# 直接子元素包含 FormControl
|
||||
- has:
|
||||
kind: jsx_element
|
||||
has:
|
||||
kind: jsx_opening_element
|
||||
has:
|
||||
field: name
|
||||
regex: "^FormControl$"
|
||||
20
frontend/.rules/supabase-google-sso.yml
Normal file
20
frontend/.rules/supabase-google-sso.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
id: supabase-google-sso
|
||||
language: Tsx
|
||||
files:
|
||||
- src/**/*.tsx
|
||||
rule:
|
||||
pattern: |
|
||||
$AUTH.signInWithOAuth({ provider: 'google', $$$ })
|
||||
message: |
|
||||
Replace `signInWithOAuth` with `signInWithSSO` for Google authentication (Supabase).
|
||||
|
||||
Refactor to:
|
||||
```typescript
|
||||
const { data, error } = await supabase.auth.signInWithSSO({
|
||||
domain: 'miaoda-gg.com',
|
||||
options: { redirectTo: window.location.origin },
|
||||
});
|
||||
if (data?.url) window.open(data.url, '_self');
|
||||
```
|
||||
Ensure `window.open` uses `_self` target.
|
||||
severity: warning
|
||||
10
frontend/.rules/testBuild.sh
Normal file
10
frontend/.rules/testBuild.sh
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
OUTPUT=$(npx vite build --minify false --logLevel error --outDir /workspace/.dist 2>&1)
|
||||
EXIT_CODE=$?
|
||||
|
||||
if [ $EXIT_CODE -ne 0 ]; then
|
||||
echo "$OUTPUT"
|
||||
fi
|
||||
|
||||
exit $EXIT_CODE
|
||||
11
frontend/.rules/toast-hook.yml
Normal file
11
frontend/.rules/toast-hook.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
id: use-toast-import
|
||||
message: Use 'import { toast } from "sonner"' instead of "@/hooks/use-toast"
|
||||
severity: error
|
||||
language: Tsx
|
||||
note: |
|
||||
The new shadcn/ui pattern uses sonner for toast notifications.
|
||||
Replace: import { toast } from "@/hooks/use-toast"
|
||||
With: import { toast } from "sonner"
|
||||
|
||||
rule:
|
||||
pattern: import { $$$IMPORTS } from "@/hooks/use-toast"
|
||||
Reference in New Issue
Block a user