1#!/bin/bash
2
3# Pre-commit hook for Teal project
4# This script runs code formatting and linting checks before allowing commits
5
6set -e
7
8echo "🔍 Running pre-commit checks..."
9
10# Colors for output
11RED='\033[0;31m'
12GREEN='\033[0;32m'
13YELLOW='\033[1;33m'
14BLUE='\033[0;34m'
15NC='\033[0m' # No Color
16
17# Function to print colored output
18print_status() {
19 echo -e "${BLUE}[INFO]${NC} $1"
20}
21
22print_success() {
23 echo -e "${GREEN}[SUCCESS]${NC} $1"
24}
25
26print_warning() {
27 echo -e "${YELLOW}[WARNING]${NC} $1"
28}
29
30print_error() {
31 echo -e "${RED}[ERROR]${NC} $1"
32}
33
34# Get list of staged files
35STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
36
37if [ -z "$STAGED_FILES" ]; then
38 print_warning "No staged files found"
39 exit 0
40fi
41
42# Check if we have TypeScript/JavaScript files
43TS_JS_FILES=$(echo "$STAGED_FILES" | grep -E '\.(ts|tsx|js|jsx)$' || true)
44# Check if we have Rust files
45RUST_FILES=$(echo "$STAGED_FILES" | grep -E '\.rs$' || true)
46# Check if we have lexicon files
47LEXICON_FILES=$(echo "$STAGED_FILES" | grep -E 'lexicons/.*\.json$' || true)
48
49print_status "Staged files to check:"
50echo "$STAGED_FILES" | sed 's/^/ - /'
51
52# 1. TypeScript/JavaScript checks
53if [ -n "$TS_JS_FILES" ]; then
54 print_status "Running TypeScript/JavaScript checks..."
55
56 # Check if biome is available and run it
57 if command -v pnpm >/dev/null 2>&1; then
58 print_status "Running Biome formatting and linting..."
59 if ! pnpm biome check . --apply --no-errors-on-unmatched 2>/dev/null; then
60 print_error "Biome check failed. Please fix the issues and try again."
61 exit 1
62 fi
63
64 print_status "Running Prettier formatting..."
65 if ! pnpm prettier --write $TS_JS_FILES 2>/dev/null; then
66 print_error "Prettier formatting failed. Please fix the issues and try again."
67 exit 1
68 fi
69
70 # TypeScript checking temporarily disabled due to vendor compilation issues
71 # Re-enable once vendor code is fixed
72 else
73 print_warning "pnpm not found, skipping JS/TS checks"
74 fi
75fi
76
77# 2. Rust checks
78if [ -n "$RUST_FILES" ]; then
79 print_status "Running Rust checks..."
80
81 if command -v cargo >/dev/null 2>&1; then
82 RUST_ERRORS=0
83
84 # Check services workspace
85 if [ -f "services/Cargo.toml" ]; then
86 print_status "Running cargo fmt on services workspace..."
87 if ! (cd services && cargo fmt --check) 2>/dev/null; then
88 print_status "Auto-formatting Rust code in services..."
89 (cd services && cargo fmt) 2>/dev/null || true
90 fi
91
92 print_status "Running cargo clippy on services workspace..."
93 if (cd services && cargo check); then
94 if ! (cd services && cargo clippy -- -D warnings); then
95 print_warning "Cargo clippy found issues in services workspace. Please fix the warnings."
96 print_warning "Run 'pnpm rust:clippy:services' to see detailed errors."
97 # Don't fail the commit for clippy warnings, just warn
98 fi
99 else
100 print_warning "Services workspace has compilation errors. Skipping clippy."
101 print_warning "Run 'pnpm rust:clippy:services' to see detailed errors."
102 fi
103 fi
104
105 # Check individual Rust projects outside services
106 CHECKED_DIRS=""
107 for rust_file in $RUST_FILES; do
108 rust_dir=$(dirname "$rust_file")
109 # Find the nearest Cargo.toml going up the directory tree
110 check_dir="$rust_dir"
111 while [ "$check_dir" != "." ] && [ "$check_dir" != "/" ]; do
112 if [ -f "$check_dir/Cargo.toml" ] && [ "$check_dir" != "services" ]; then
113 # Skip if we already checked this directory
114 if echo "$CHECKED_DIRS" | grep -q "$check_dir"; then
115 break
116 fi
117 CHECKED_DIRS="$CHECKED_DIRS $check_dir"
118
119 # Found a Cargo.toml outside services workspace
120 print_status "Running cargo fmt on $check_dir..."
121 if ! (cd "$check_dir" && cargo fmt --check) 2>/dev/null; then
122 print_status "Auto-formatting Rust code in $check_dir..."
123 (cd "$check_dir" && cargo fmt) 2>/dev/null || true
124 fi
125
126 print_status "Running cargo clippy on $check_dir..."
127 if (cd "$check_dir" && cargo check); then
128 if ! (cd "$check_dir" && cargo clippy -- -D warnings); then
129 print_error "Cargo clippy found issues in $check_dir. Please fix the warnings and try again."
130 RUST_ERRORS=1
131 fi
132 else
133 print_warning "Project $check_dir has compilation errors. Skipping clippy."
134 print_warning "Run 'cd $check_dir && cargo check' to see detailed errors."
135 fi
136 break
137 fi
138 check_dir=$(dirname "$check_dir")
139 done
140 done
141
142 if [ $RUST_ERRORS -eq 1 ]; then
143 exit 1
144 fi
145 else
146 print_warning "Cargo not found, skipping Rust checks"
147 fi
148fi
149
150# 3. Lexicon checks
151if [ -n "$LEXICON_FILES" ]; then
152 print_status "Lexicon files changed, validating and regenerating..."
153
154 if command -v pnpm >/dev/null 2>&1; then
155 print_status "Validating lexicons..."
156 if ! pnpm lex:validate 2>/dev/null; then
157 print_error "Lexicon validation failed. Please fix the lexicon files and try again."
158 exit 1
159 fi
160
161 print_status "Regenerating lexicons..."
162 if ! pnpm lex:gen-server 2>/dev/null; then
163 print_error "Lexicon generation failed. Please check the lexicon files and try again."
164 exit 1
165 fi
166
167 # Note: Generated lexicon files are ignored by .gitignore and not added to staging
168 print_status "Generated lexicon files are ignored by .gitignore (as intended)"
169 else
170 print_warning "pnpm not found, skipping lexicon checks"
171 fi
172fi
173
174# 4. Re-add files that might have been formatted
175FORMATTED_FILES=""
176for file in $STAGED_FILES; do
177 if [ -f "$file" ]; then
178 # Check if file was modified by formatters
179 if [ -n "$(git diff "$file")" ]; then
180 FORMATTED_FILES="$FORMATTED_FILES $file"
181 git add "$file"
182 fi
183 fi
184done
185
186if [ -n "$FORMATTED_FILES" ]; then
187 print_success "Auto-formatted files have been re-staged:"
188 echo "$FORMATTED_FILES" | tr ' ' '\n' | sed 's/^/ - /'
189fi
190
191# 5. Final validation - ensure no syntax errors in staged files
192print_status "Running final validation..."
193
194# Check for common issues
195for file in $TS_JS_FILES; do
196 if [ -f "$file" ]; then
197 # Check for console.log statements (optional - remove if you want to allow them)
198 if grep -n "console\.log" "$file" >/dev/null 2>&1; then
199 print_warning "Found console.log statements in $file! yooo!!!"
200 # Uncomment the next two lines if you want to block commits with console.log
201 # print_error "Please remove console.log statements before committing"
202 # exit 1
203 fi
204
205 # Check for TODO/FIXME comments in committed code (optional)
206 if grep -n -i "TODO\|FIXME" "$file" >/dev/null 2>&1; then
207 print_warning "Found TODO/FIXME comments in $file"
208 fi
209 fi
210done
211
212print_success "All pre-commit checks passed! 🎉"
213exit 0