1 #!/bin/bash
2 # Expo migration sanity check.
3 # Usage: bash expo_sanity_check.sh <app-name> <prefix>
4 # app-name: the artifact slug (e.g. "my-app")
5 # prefix: the code prefix detected in Phase 1 ("client" or ".")
6
7 set -euo pipefail
8
9 if [ $# -lt 2 ]; then
10 echo "Usage: bash expo_sanity_check.sh <app-name> <prefix>"
11 exit 1
12 fi
13
14 APP="$1"
15 PREFIX="$2"
16
17 echo "==== MIGRATION SANITY CHECK ===="
18 echo "App: $APP | Prefix: $PREFIX"
19 FAIL=0
20
21 # 1. app.json preserved
22 if diff -q .migration-backup/app.json "artifacts/$APP/app.json" >/dev/null 2>&1; then
23 echo "PASS: app.json matches original"
24 else
25 echo "FAIL: app.json differs from original"
26 diff .migration-backup/app.json "artifacts/$APP/app.json" || true
27 FAIL=1
28 fi
29
30 # 2. No app.config.ts
31 if [ -f "artifacts/$APP/app.config.ts" ]; then
32 echo "FAIL: app.config.ts exists — remove it and use static app.json"
33 FAIL=1
34 else
35 echo "PASS: no app.config.ts"
36 fi
37
38 # 3. Routing paradigm
39 if [ -f "artifacts/$APP/app/_layout.tsx" ]; then
40 echo "PASS: expo-router layout found"
41 else
42 echo "FAIL: app/_layout.tsx missing"
43 FAIL=1
44 fi
45
46 # 4. All source directories copied
47 # Skip directories that are migrated elsewhere (not into the expo artifact):
48 # node_modules — not copied
49 # server/ — migrated to artifacts/api-server (Phase 2)
50 # shared/ — migrated to lib/db (Phase 2)
51 SKIP_DIRS="node_modules server shared"
52 DIR_FAIL=0
53 for dir in .migration-backup/"$PREFIX"/*/; do
54 [ ! -d "$dir" ] && continue
55 name=$(basename "$dir")
56 echo "$SKIP_DIRS" | grep -qw "$name" && continue
57 if [ ! -d "artifacts/$APP/$name" ]; then
58 echo "FAIL: directory $name was NOT copied"
59 DIR_FAIL=1
60 FAIL=1
61 fi
62 done
63 [ $DIR_FAIL -eq 0 ] && echo "PASS: all source directories copied"
64
65 # 5. No broken @/ imports
66 BROKEN_IMPORTS=$({ grep -rn "from ['\"]@/" "artifacts/$APP/" --include="*.ts" --include="*.tsx" 2>/dev/null || true; } | while IFS= read -r line; do
67 file=$(echo "$line" | cut -d: -f1)
68 import_path=$(echo "$line" | sed -n "s/.*from ['\"]@\/\([^'\"]*\)['\"].*/\1/p")
69 base="artifacts/$APP/$import_path"
70 if [ ! -f "$base.ts" ] && [ ! -f "$base.tsx" ] && [ ! -f "$base/index.ts" ] && [ ! -f "$base/index.tsx" ] && [ ! -f "$base" ]; then
71 echo "$file → @/$import_path"
72 fi
73 done)
74 if [ -n "$BROKEN_IMPORTS" ]; then
75 echo "FAIL: broken @/ imports found:"
76 echo "$BROKEN_IMPORTS"
77 FAIL=1
78 else
79 echo "PASS: all @/ imports resolve"
80 fi
81
82 # 6. Design tokens copied
83 for f in constants/colors.ts constants/typography.ts; do
84 if [ -f ".migration-backup/$PREFIX/$f" ] || [ -f ".migration-backup/$f" ]; then
85 if [ -f "artifacts/$APP/$f" ]; then
86 echo "PASS: $f copied"
87 else
88 echo "FAIL: $f missing from artifact"
89 FAIL=1
90 fi
91 fi
92 done
93
94 # 7. Font loading pattern preserved
95 if grep -q "useFonts\|SplashScreen" "artifacts/$APP/app/_layout.tsx" 2>/dev/null; then
96 echo "PASS: font loading pattern present"
97 else
98 echo "FAIL: useFonts/SplashScreen missing from _layout.tsx"
99 FAIL=1
100 fi
101
102 # 8. No stale imports
103 if grep -rq "@shared/\|from ['\"]\.\.\/.*shared" "artifacts/$APP/" --include="*.ts" --include="*.tsx" 2>/dev/null; then
104 echo "FAIL: old @shared/ imports still present"
105 grep -rn "@shared/\|from ['\"]\.\.\/.*shared" "artifacts/$APP/" --include="*.ts" --include="*.tsx"
106 FAIL=1
107 else
108 echo "PASS: no old shared imports"
109 fi
110 if grep -rq "from ['\"]@workspace/db['\"]" "artifacts/$APP/" --include="*.ts" --include="*.tsx" 2>/dev/null; then
111 echo "FAIL: @workspace/db imported in frontend"
112 FAIL=1
113 else
114 echo "PASS: no server code imports in frontend"
115 fi
116
117 # 9. Native package versions — flag mismatches
118 for pkg in react-native-reanimated react-native-gesture-handler react-native-keyboard-controller; do
119 ART_VER=$(grep -o "\"$pkg\": *\"[^\"]*\"" "artifacts/$APP/package.json" 2>/dev/null || echo "")
120 ORIG_VER=$(grep -o "\"$pkg\": *\"[^\"]*\"" .migration-backup/package.json 2>/dev/null || echo "")
121 if [ -n "$ART_VER" ] && [ -n "$ORIG_VER" ]; then
122 if [ "$ART_VER" != "$ORIG_VER" ]; then
123 echo "FAIL: $pkg version mismatch — artifact has $ART_VER, original has $ORIG_VER. Use the original version."
124 FAIL=1
125 else
126 echo "PASS: $pkg version matches"
127 fi
128 elif [ -n "$ORIG_VER" ] && [ -z "$ART_VER" ]; then
129 echo "FAIL: $pkg present in original but missing from artifact"
130 FAIL=1
131 fi
132 done
133
134 # 10. Assets copied
135 if [ -d ".migration-backup/$PREFIX/assets" ] || [ -d ".migration-backup/assets" ]; then
136 MISSING_ASSETS=0
137 SOURCE_ASSETS=".migration-backup/$PREFIX/assets"
138 [ ! -d "$SOURCE_ASSETS" ] && SOURCE_ASSETS=".migration-backup/assets"
139 while IFS= read -r f; do
140 REL="${f#"$SOURCE_ASSETS"/}"
141 if [ ! -f "artifacts/$APP/assets/$REL" ]; then
142 echo "FAIL: missing asset assets/$REL"
143 MISSING_ASSETS=1
144 FAIL=1
145 fi
146 done < <(find "$SOURCE_ASSETS" -type f 2>/dev/null)
147 [ $MISSING_ASSETS -eq 0 ] && echo "PASS: all assets copied"
148 else
149 echo "PASS: no assets directory in original (skipped)"
150 fi
151
152 echo "==== END SANITY CHECK ===="
153 if [ $FAIL -ne 0 ]; then
154 echo "SANITY CHECK FAILED — fix all FAIL lines above before building."
155 exit 1
156 else
157 echo "ALL CHECKS PASSED"
158 fi