|
1
|
#!/bin/bash |
|
2
|
# Discover the shape of a fullstack_js project before migration. |
|
3
|
# Usage: bash fullstack_detect.sh |
|
4
|
# |
|
5
|
# Outputs key=value pairs describing the project structure. |
|
6
|
# The agent reads this output to decide what to pass to the copy scripts. |
|
7
|
|
|
8
|
set -euo pipefail |
|
9
|
|
|
10
|
BACKUP=".migration-backup" |
|
11
|
|
|
12
|
if [ ! -d "$BACKUP" ]; then |
|
13
|
echo "ERROR: $BACKUP directory not found" |
|
14
|
exit 1 |
|
15
|
fi |
|
16
|
|
|
17
|
echo "==== PROJECT DETECTION ====" |
|
18
|
|
|
19
|
# --- Tailwind version --- |
|
20
|
# v3 uses @tailwind directives; v4 uses @import "tailwindcss" |
|
21
|
TW_VERSION="v4" |
|
22
|
for css in "$BACKUP"/client/src/index.css "$BACKUP"/src/index.css "$BACKUP"/index.css; do |
|
23
|
if [ -f "$css" ] && grep -q '@tailwind base' "$css" 2>/dev/null; then |
|
24
|
TW_VERSION="v3" |
|
25
|
break |
|
26
|
fi |
|
27
|
done |
|
28
|
echo "TAILWIND_VERSION=$TW_VERSION" |
|
29
|
|
|
30
|
# --- Theme system --- |
|
31
|
HAS_THEME_JSON="false" |
|
32
|
if [ -f "$BACKUP/theme.json" ]; then |
|
33
|
HAS_THEME_JSON="true" |
|
34
|
fi |
|
35
|
echo "HAS_THEME_JSON=$HAS_THEME_JSON" |
|
36
|
|
|
37
|
# --- Client directory --- |
|
38
|
# Most fullstack_js projects use client/, but some use src/ or root |
|
39
|
CLIENT_DIR="" |
|
40
|
if [ -d "$BACKUP/client/src" ]; then |
|
41
|
CLIENT_DIR="client" |
|
42
|
elif [ -d "$BACKUP/src/components" ] || [ -d "$BACKUP/src/pages" ] || [ -f "$BACKUP/src/App.tsx" ] || [ -f "$BACKUP/src/main.tsx" ]; then |
|
43
|
CLIENT_DIR="src" |
|
44
|
fi |
|
45
|
echo "CLIENT_DIR=$CLIENT_DIR" |
|
46
|
|
|
47
|
# --- Route layout --- |
|
48
|
ROUTE_LAYOUT="none" |
|
49
|
if [ -d "$BACKUP/server/routes" ]; then |
|
50
|
ROUTE_LAYOUT="directory" |
|
51
|
elif [ -f "$BACKUP/server/routes.ts" ]; then |
|
52
|
ROUTE_LAYOUT="single" |
|
53
|
fi |
|
54
|
echo "ROUTE_LAYOUT=$ROUTE_LAYOUT" |
|
55
|
|
|
56
|
# --- Schema discovery --- |
|
57
|
# Try common locations in order of likelihood |
|
58
|
SCHEMA_PATH="" |
|
59
|
for candidate in \ |
|
60
|
"$BACKUP/shared/schema.ts" \ |
|
61
|
"$BACKUP/shared/schema/index.ts" \ |
|
62
|
"$BACKUP/db/schema.ts" \ |
|
63
|
"$BACKUP/server/db/schema.ts" \ |
|
64
|
"$BACKUP/src/shared/schema.ts"; do |
|
65
|
if [ -f "$candidate" ]; then |
|
66
|
SCHEMA_PATH="${candidate#"$BACKUP/"}" |
|
67
|
break |
|
68
|
fi |
|
69
|
done |
|
70
|
if [ -z "$SCHEMA_PATH" ]; then |
|
71
|
# Broader search: any file named schema.ts outside node_modules |
|
72
|
FOUND=$(find "$BACKUP" -name "schema.ts" -not -path "*/node_modules/*" -not -path "*/.git/*" 2>/dev/null | head -1) |
|
73
|
if [ -n "$FOUND" ]; then |
|
74
|
SCHEMA_PATH="${FOUND#"$BACKUP/"}" |
|
75
|
fi |
|
76
|
fi |
|
77
|
echo "SCHEMA_PATH=$SCHEMA_PATH" |
|
78
|
|
|
79
|
# --- Storage file --- |
|
80
|
HAS_STORAGE="false" |
|
81
|
if [ -f "$BACKUP/server/storage.ts" ]; then |
|
82
|
HAS_STORAGE="true" |
|
83
|
fi |
|
84
|
echo "HAS_STORAGE=$HAS_STORAGE" |
|
85
|
|
|
86
|
# --- Attached assets --- |
|
87
|
HAS_ATTACHED_ASSETS="false" |
|
88
|
if [ -d "$BACKUP/attached_assets" ]; then |
|
89
|
HAS_ATTACHED_ASSETS="true" |
|
90
|
fi |
|
91
|
echo "HAS_ATTACHED_ASSETS=$HAS_ATTACHED_ASSETS" |
|
92
|
|
|
93
|
# --- Custom queryClient --- |
|
94
|
HAS_CUSTOM_QUERYCLIENT="false" |
|
95
|
for candidate in \ |
|
96
|
"$BACKUP/client/src/lib/queryClient.ts" \ |
|
97
|
"$BACKUP/client/src/lib/queryClient.tsx" \ |
|
98
|
"$BACKUP/client/src/queryClient.ts" \ |
|
99
|
"$BACKUP/src/lib/queryClient.ts" \ |
|
100
|
"$BACKUP/src/queryClient.ts"; do |
|
101
|
if [ -f "$candidate" ]; then |
|
102
|
HAS_CUSTOM_QUERYCLIENT="true" |
|
103
|
break |
|
104
|
fi |
|
105
|
done |
|
106
|
echo "HAS_CUSTOM_QUERYCLIENT=$HAS_CUSTOM_QUERYCLIENT" |
|
107
|
|
|
108
|
# --- Server files --- |
|
109
|
echo "" |
|
110
|
echo "SERVER_FILES:" |
|
111
|
if [ -d "$BACKUP/server" ]; then |
|
112
|
find "$BACKUP/server" -maxdepth 2 -name "*.ts" -not -path "*/node_modules/*" 2>/dev/null | sort | while read -r f; do |
|
113
|
echo " ${f#"$BACKUP/"}" |
|
114
|
done |
|
115
|
fi |
|
116
|
|
|
117
|
# --- Client directories --- |
|
118
|
echo "" |
|
119
|
echo "CLIENT_DIRS:" |
|
120
|
if [ -n "$CLIENT_DIR" ] && [ -d "$BACKUP/$CLIENT_DIR/src" ]; then |
|
121
|
for entry in "$BACKUP/$CLIENT_DIR/src/"*; do |
|
122
|
[ -e "$entry" ] || continue |
|
123
|
echo " $CLIENT_DIR/src/$(basename "$entry")" |
|
124
|
done |
|
125
|
fi |
|
126
|
|
|
127
|
# --- Tailwind config location --- |
|
128
|
TW_CONFIG="" |
|
129
|
for candidate in \ |
|
130
|
"$BACKUP/tailwind.config.ts" \ |
|
131
|
"$BACKUP/tailwind.config.js" \ |
|
132
|
"$BACKUP/tailwind.config.cjs" \ |
|
133
|
"$BACKUP/client/tailwind.config.ts" \ |
|
134
|
"$BACKUP/client/tailwind.config.js"; do |
|
135
|
if [ -f "$candidate" ]; then |
|
136
|
TW_CONFIG="${candidate#"$BACKUP/"}" |
|
137
|
break |
|
138
|
fi |
|
139
|
done |
|
140
|
echo "" |
|
141
|
echo "TAILWIND_CONFIG=$TW_CONFIG" |
|
142
|
|
|
143
|
# --- Vite plugins in use --- |
|
144
|
# Known scaffold plugins that don't need manual porting |
|
145
|
SCAFFOLD_PLUGINS="@vitejs/plugin-react @tailwindcss/vite @replit/vite-plugin-runtime-error-modal @replit/vite-plugin-cartographer @replit/vite-plugin-dev-banner" |
|
146
|
|
|
147
|
echo "" |
|
148
|
echo "VITE_PLUGINS:" |
|
149
|
VITE_CONFIG="" |
|
150
|
for candidate in "$BACKUP/vite.config.ts" "$BACKUP/client/vite.config.ts" "$BACKUP/vite.config.js" "$BACKUP/client/vite.config.js"; do |
|
151
|
if [ -f "$candidate" ]; then |
|
152
|
VITE_CONFIG="$candidate" |
|
153
|
break |
|
154
|
fi |
|
155
|
done |
|
156
|
ALL_PLUGINS="" |
|
157
|
if [ -n "$VITE_CONFIG" ]; then |
|
158
|
ALL_PLUGINS=$(sed -n 's/.*from ["\x27]\([^"\x27]*\)["\x27].*/\1/p' "$VITE_CONFIG" 2>/dev/null | grep -iv "^vite$\|^path$\|^express\|^http\|^url" || true) |
|
159
|
echo "$ALL_PLUGINS" | while read -r p; do |
|
160
|
[ -z "$p" ] && continue |
|
161
|
echo " $p" |
|
162
|
done |
|
163
|
fi |
|
164
|
|
|
165
|
# --- Custom Vite plugins (not in scaffold) --- |
|
166
|
echo "" |
|
167
|
echo "CUSTOM_VITE_PLUGINS:" |
|
168
|
if [ -n "$ALL_PLUGINS" ]; then |
|
169
|
echo "$ALL_PLUGINS" | while read -r p; do |
|
170
|
[ -z "$p" ] && continue |
|
171
|
IS_SCAFFOLD="false" |
|
172
|
for sp in $SCAFFOLD_PLUGINS; do |
|
173
|
if [ "$p" = "$sp" ]; then |
|
174
|
IS_SCAFFOLD="true" |
|
175
|
break |
|
176
|
fi |
|
177
|
done |
|
178
|
if [ "$IS_SCAFFOLD" = "false" ]; then |
|
179
|
echo " $p" |
|
180
|
fi |
|
181
|
done |
|
182
|
fi |
|
183
|
# Also detect local/relative plugin imports |
|
184
|
if [ -n "$VITE_CONFIG" ]; then |
|
185
|
LOCAL_PLUGINS=$(grep -oE 'from ["\x27]\./[^"\x27]+["\x27]' "$VITE_CONFIG" 2>/dev/null | sed "s/from [\"']//;s/[\"']//" || true) |
|
186
|
if [ -n "$LOCAL_PLUGINS" ]; then |
|
187
|
echo "$LOCAL_PLUGINS" | while read -r p; do |
|
188
|
[ -z "$p" ] && continue |
|
189
|
echo " $p (local file)" |
|
190
|
done |
|
191
|
fi |
|
192
|
fi |
|
193
|
|
|
194
|
# --- Potential conflicts --- |
|
195
|
echo "" |
|
196
|
echo "CONFLICTS:" |
|
197
|
HAS_CONFLICTS="false" |
|
198
|
|
|
199
|
# PostCSS config + Tailwind v4 = build failure |
|
200
|
if [ "$TW_VERSION" = "v4" ]; then |
|
201
|
for candidate in "$BACKUP/postcss.config.js" "$BACKUP/postcss.config.cjs" "$BACKUP/postcss.config.mjs"; do |
|
202
|
if [ -f "$candidate" ]; then |
|
203
|
echo " WARNING: $(basename "$candidate") exists but Tailwind v4 detected — will conflict with @tailwindcss/vite" |
|
204
|
HAS_CONFLICTS="true" |
|
205
|
break |
|
206
|
fi |
|
207
|
done |
|
208
|
fi |
|
209
|
|
|
210
|
# Old vite plugins that won't exist in the scaffold |
|
211
|
if [ -n "$VITE_CONFIG" ]; then |
|
212
|
if grep -q "vite-plugin-shadcn-theme-json" "$VITE_CONFIG" 2>/dev/null && [ "$HAS_THEME_JSON" = "false" ]; then |
|
213
|
echo " WARNING: vite.config uses shadcn-theme-json plugin but no theme.json found" |
|
214
|
HAS_CONFLICTS="true" |
|
215
|
fi |
|
216
|
fi |
|
217
|
|
|
218
|
# Custom Vite plugins that will be silently dropped |
|
219
|
# Note: avoid piped while loops — they run in subshells and can't update HAS_CONFLICTS |
|
220
|
if [ -n "$ALL_PLUGINS" ]; then |
|
221
|
while read -r p; do |
|
222
|
[ -z "$p" ] && continue |
|
223
|
IS_SCAFFOLD="false" |
|
224
|
for sp in $SCAFFOLD_PLUGINS; do |
|
225
|
if [ "$p" = "$sp" ]; then IS_SCAFFOLD="true"; break; fi |
|
226
|
done |
|
227
|
if [ "$IS_SCAFFOLD" = "false" ]; then |
|
228
|
echo " WARNING: custom Vite plugin '$p' will be DROPPED unless manually ported" |
|
229
|
HAS_CONFLICTS="true" |
|
230
|
fi |
|
231
|
done <<< "$ALL_PLUGINS" |
|
232
|
fi |
|
233
|
if [ -n "${LOCAL_PLUGINS:-}" ]; then |
|
234
|
while read -r p; do |
|
235
|
[ -z "$p" ] && continue |
|
236
|
echo " WARNING: local Vite plugin '$p' will be DROPPED unless manually ported" |
|
237
|
HAS_CONFLICTS="true" |
|
238
|
done <<< "$LOCAL_PLUGINS" |
|
239
|
fi |
|
240
|
|
|
241
|
[ "$HAS_CONFLICTS" = "false" ] && echo " none" |
|
242
|
|
|
243
|
echo "" |
|
244
|
echo "==== END DETECTION ====" |