# Convention Detection Script Template 泛化的约定检测脚本模板,基于 new-ai-proj `check-modal-safety.sh` 提取。用于检测代码中违反编码约定的模式。 ## 使用方法 1. 复制下方脚本到 `scripts/check-{NAME}.sh` 2. 替换所有 `{PLACEHOLDER}` 为项目特定值 3. 运行 `chmod +x scripts/check-{NAME}.sh` 4. 验证:`./scripts/check-{NAME}.sh` 输出 PASSED ## 脚本模板 ```bash #!/usr/bin/env bash # # {CONVENTION_NAME} Check — detects {WHAT_IT_DETECTS} in {TARGET_SCOPE}. # # {PROBLEM_DESCRIPTION} # # Usage: # ./scripts/check-{NAME}.sh # Check and report # ./scripts/check-{NAME}.sh --ci # Exit code 1 on violations # set -euo pipefail TARGET_DIR="$(cd "$(dirname "$0")/../{TARGET_DIRECTORY}" && pwd)" CI_MODE=false [[ "${1:-}" == "--ci" ]] && CI_MODE=true violations=0 # ── detection logic ───────────────────────────────────────────────── # Strategy A: Simple grep pattern (file-level) # Find files matching a bad pattern, optionally excluding false positives. # # while IFS= read -r file; do # rel_path="${file#"$TARGET_DIR"/}" # echo "WARNING: $rel_path — {VIOLATION_MESSAGE}" # violations=$((violations + 1)) # done < <(grep -rl '{BAD_PATTERN}' "$TARGET_DIR" --include='{FILE_GLOB}' 2>/dev/null \ # | while read f; do grep -L '{FALSE_POSITIVE_PATTERN}' "$f" 2>/dev/null; done) # Strategy B: Line-level with context (multi-condition) # Find a primary pattern, check nearby lines for secondary pattern. # # while IFS= read -r file; do # while IFS= read -r line_num; do # # Check context around the match # has_mitigation=$(sed -n "${line_num},$((line_num + {CONTEXT_LINES}))p" "$file" \ # | grep -c '{MITIGATION_PATTERN}' || true) # if [[ "$has_mitigation" -eq 0 ]]; then # # Additional condition: check if problematic follow-up exists # after_end=$((line_num + {LOOKAHEAD_LINES})) # has_problem=$(sed -n "$((line_num + 1)),${after_end}p" "$file" \ # | grep -cE '{FOLLOW_UP_BAD_PATTERN}' || true) # if [[ "$has_problem" -gt 0 ]]; then # rel_path="${file#"$TARGET_DIR"/}" # echo "WARNING: $rel_path:$line_num — {VIOLATION_MESSAGE}" # violations=$((violations + 1)) # fi # fi # done < <(grep -n '{PRIMARY_PATTERN}' "$file" | cut -d: -f1) # done < <(grep -rl '{PRIMARY_PATTERN}' "$TARGET_DIR" --include='{FILE_GLOB}' 2>/dev/null) # ── results ───────────────────────────────────────────────────────── if [[ "$violations" -gt 0 ]]; then echo "" echo "Found $violations {CONVENTION_NAME} violation(s)." echo "Fix: {FIX_GUIDANCE}" echo "Docs: see CLAUDE.md '{CLAUDE_MD_SECTION}'" $CI_MODE && exit 1 else echo "{CONVENTION_NAME} check PASSED." fi ``` ## Placeholder 说明 | Placeholder | 含义 | 示例 | |-------------|------|------| | `{NAME}` | 脚本短名 | `modal-safety`, `sql-injection` | | `{CONVENTION_NAME}` | 约定显示名 | `Modal safety`, `SQL injection prevention` | | `{WHAT_IT_DETECTS}` | 检测内容 | `potential modal overlap patterns` | | `{TARGET_SCOPE}` | 目标范围描述 | `frontend code`, `Go handlers` | | `{TARGET_DIRECTORY}` | 扫描目录 | `frontend/src`, `backend` | | `{PROBLEM_DESCRIPTION}` | 问题描述 | `Ant Design Modal.success is non-blocking...` | | `{FILE_GLOB}` | 文件匹配 | `*.tsx`, `*.go` | | `{PRIMARY_PATTERN}` | 主匹配模式 | `Modal\.\(success\|info\)` | | `{MITIGATION_PATTERN}` | 缓解模式(有则排除) | `onOk` | | `{FOLLOW_UP_BAD_PATTERN}` | 后续违规模式 | `set\w*Open\(true\)` | | `{CONTEXT_LINES}` | 上下文行数 | `25` | | `{LOOKAHEAD_LINES}` | 前瞻行数 | `20` | | `{BAD_PATTERN}` | Strategy A 主匹配模式 | `console\.log` | | `{FALSE_POSITIVE_PATTERN}` | Strategy A 排除模式(匹配到则非违规) | `// eslint-disable` | | `{VIOLATION_MESSAGE}` | 违规消息 | `Modal without onOk followed by setState` | | `{FIX_GUIDANCE}` | 修复指导 | `add onOk callback to Modal` | | `{CLAUDE_MD_SECTION}` | CLAUDE.md 章节名 | `Frontend: Modal 安全规则` | ## 两种检测策略 ### Strategy A: 文件级检测 适用于:整个文件不应出现某模式(或出现即违规)。 例子: - `console.log` 在生产代码中 - `TODO` / `FIXME` 计数 - 缺少 license header ### Strategy B: 行级 + 上下文检测 适用于:模式本身不违规,需要检查周围上下文。 例子: - `Modal.success()` 不违规,但后面紧跟 `setState` 才违规 - `db.Exec()` 不违规,但参数用字符串拼接才违规 - `fmt.Println()` 不违规,但在 handler 中输出敏感数据才违规