Setting the file. One moment.
Validate Conversion · Build On Base · base/skills · Skills Docs
ContentsBack to the top of the page def check_package_json
— line 181
This file
Number 4.35
Position 35 of 35
Type Python
Size 13 KB
Lines 336 scripts/ validate_conversion.py
Python · 336 lines · 13 KB
17
18 import os
19 import re
20 import json
21 import sys
22 from pathlib import Path
23 from typing import List, Tuple
24
25 class ValidationResult :
26 def __init__ (self):
27 self .errors: List[ str ] = []
28 self .warnings: List[ str ] = []
29 self .passed: List[ str ] = []
30
31 def add_error (self, msg: str ):
32 self .errors.append(msg)
33
34 def add_warning (self, msg: str ):
35 self .warnings.append(msg)
36
37 def add_pass (self, msg: str ):
38 self .passed.append(msg)
39
40 @ property
41 def is_valid (self) -> bool :
42 return len ( self .errors) == 0
43
44 # Patterns to check
45 MINIKIT_IMPORT = re.compile( r "from \s + [ ' \" ] @coinbase/onchainkit/minikit [ ' \" ] " )
46 ONCHAINKIT_IMPORT = re.compile( r "from \s + [ ' \" ] @coinbase/onchainkit [ ' \" ] " )
47 MINIKIT_HOOKS = re.compile( r ' \b( useMiniKit | useClose | useOpenUrl | useViewProfile | useViewCast | useComposeCast | useAddFrame | useAuthenticate | useNotification | usePrimaryButton )\s * \( ' )
48 MINIKIT_PROVIDER = re.compile( r '<MiniKitProvider | MiniKitProvider' )
49 ONCHAINKIT_PROVIDER = re.compile( r '<OnchainKitProvider | OnchainKitProvider' )
50 MINIKIT_PROP = re.compile( r 'miniKit \s * [ =: ] ' )
51 FARCASTER_IMPORT = re.compile( r "from \s + [ ' \" ] @farcaster/miniapp-sdk [ ' \" ] " )
52 FARCASTER_WAGMI_IMPORT = re.compile( r "from \s + [ ' \" ] @farcaster/miniapp-wagmi-connector [ ' \" ] " )
53 SDK_READY = re.compile( r 'sdk \. actions \. ready \s * \( ' )
54 MANIFEST_FRAME_KEY = re.compile( r ' [ " \' ] ? frame [ " \' ] ? \s * [ := ] ' )
55 MANIFEST_MINIAPP_KEY = re.compile( r ' [ " \' ] ? miniapp [ " \' ] ? \s * [ := ] ' )
56
57 def find_source_files (directory: str ) -> List[Path]:
58 """Find all source files."""
59 files = []
60 for root, _, filenames in os.walk(directory):
61 if 'node_modules' in root or '.next' in root:
62 continue
63 for filename in filenames:
64 if filename.endswith(( '.tsx' , '.ts' , '.jsx' , '.js' )):
65 files.append(Path(root) / filename)
66 return files
67
68 def check_no_minikit_imports (files: List[Path], project_path: Path, result: ValidationResult):
69 """Check that no MiniKit imports remain."""
70 minikit_found = []
71 onchainkit_found = []
72
73 for filepath in files:
74 try :
75 content = filepath.read_text( encoding = 'utf-8' )
76 rel_path = str (filepath.relative_to(project_path))
77
78 if MINIKIT_IMPORT .search(content):
79 minikit_found.append(rel_path)
80 if ONCHAINKIT_IMPORT .search(content):
81 onchainkit_found.append(rel_path)
82 except Exception :
83 pass
84
85 if minikit_found:
86 result.add_error( f "MiniKit imports still present in: { ', ' .join(minikit_found) } " )
87
88 if onchainkit_found:
89 result.add_error( f "OnchainKit imports still present in: { ', ' .join(onchainkit_found) } - replace with @farcaster/miniapp-sdk" )
90
91 if not minikit_found and not onchainkit_found:
92 result.add_pass( "No MiniKit/OnchainKit imports found" )
93
94 def check_no_minikit_hooks (files: List[Path], project_path: Path, result: ValidationResult):
95 """Check that no MiniKit hooks are being used."""
96 found = []
97 for filepath in files:
98 try :
99 content = filepath.read_text( encoding = 'utf-8' )
100 matches = MINIKIT_HOOKS .findall(content)
101 if matches:
102 rel_path = filepath.relative_to(project_path)
103 found.append( f " { rel_path } : { ', ' .join( set (matches)) } " )
104 except Exception :
105 pass
106
107 if found:
108 result.add_error( f "MiniKit hooks still in use: \n " + " \n " .join(found))
109 else :
110 result.add_pass( "No MiniKit hooks found" )
111
112 def check_no_provider (files: List[Path], project_path: Path, result: ValidationResult):
113 """Check that MiniKitProvider and OnchainKitProvider with miniKit are removed."""
114 minikit_provider_found = []
115 onchainkit_with_minikit_found = []
116
117 for filepath in files:
118 try :
119 content = filepath.read_text( encoding = 'utf-8' )
120 rel_path = str (filepath.relative_to(project_path))
121
122 if MINIKIT_PROVIDER .search(content):
123 minikit_provider_found.append(rel_path)
124
125 # Check for OnchainKitProvider with miniKit prop
126 if ONCHAINKIT_PROVIDER .search(content) and MINIKIT_PROP .search(content):
127 onchainkit_with_minikit_found.append(rel_path)
128 except Exception :
129 pass
130
131 if minikit_provider_found:
132 result.add_error( f "MiniKitProvider still present in: { ', ' .join(minikit_provider_found) } " )
133
134 if onchainkit_with_minikit_found:
135 result.add_error( f "OnchainKitProvider with miniKit prop found in: { ', ' .join(onchainkit_with_minikit_found) } - replace with WagmiProvider + farcasterMiniApp connector" )
136
137 if not minikit_provider_found and not onchainkit_with_minikit_found:
138 result.add_pass( "MiniKit providers removed" )
139
140 def check_farcaster_sdk_usage (files: List[Path], project_path: Path, result: ValidationResult):
141 """Check that Farcaster SDK is imported and ready() is called."""
142 has_sdk_import = False
143 has_wagmi_connector = False
144 has_ready = False
145 sdk_import_files = []
146 wagmi_connector_files = []
147 ready_files = []
148
149 for filepath in files:
150 try :
151 content = filepath.read_text( encoding = 'utf-8' )
152 rel_path = str (filepath.relative_to(project_path))
153
154 if FARCASTER_IMPORT .search(content):
155 has_sdk_import = True
156 sdk_import_files.append(rel_path)
157 if FARCASTER_WAGMI_IMPORT .search(content):
158 has_wagmi_connector = True
159 wagmi_connector_files.append(rel_path)
160 if SDK_READY .search(content):
161 has_ready = True
162 ready_files.append(rel_path)
163 except Exception :
164 pass
165
166 if has_sdk_import:
167 result.add_pass( f "Farcaster SDK imported in: { ', ' .join(sdk_import_files) } " )
168 else :
169 result.add_error( "Farcaster SDK not imported - add: import { sdk } from '@farcaster/miniapp-sdk'" )
170
171 if has_wagmi_connector:
172 result.add_pass( f "Farcaster wagmi connector imported in: { ', ' .join(wagmi_connector_files) } " )
173 else :
174 result.add_error( "Farcaster wagmi connector not imported - add: import { farcasterMiniApp } from '@farcaster/miniapp-wagmi-connector'" )
175
176 if has_ready:
177 result.add_pass( f "sdk.actions.ready() called in: { ', ' .join(ready_files) } " )
178 else :
179 result.add_error( "sdk.actions.ready() not found - add to your main page useEffect: await sdk.actions.ready()" )
180
181 def check_package_json (project_path: Path, result: ValidationResult):
182 """Check package.json for correct dependencies."""
183 package_json_path = project_path / 'package.json'
184
185 if not package_json_path.exists():
186 result.add_warning( "package.json not found" )
187 return
188
189 try :
190 with open (package_json_path) as f:
191 pkg = json.load(f)
192 except Exception as e:
193 result.add_error( f "Could not parse package.json: { e } " )
194 return
195
196 deps = { ** pkg.get( 'dependencies' , {}), ** pkg.get( 'devDependencies' , {})}
197
198 # Check for old OnchainKit - this should be removed
199 if '@coinbase/onchainkit' in deps:
200 result.add_error( "@coinbase/onchainkit still installed - run: npm uninstall @coinbase/onchainkit" )
201 else :
202 result.add_pass( "@coinbase/onchainkit removed" )
203
204 # Check for required Farcaster packages
205 required_packages = [
206 ( '@farcaster/miniapp-sdk' , 'npm install @farcaster/miniapp-sdk' ),
207 ( '@farcaster/miniapp-wagmi-connector' , 'npm install @farcaster/miniapp-wagmi-connector' ),
208 ( 'wagmi' , 'npm install wagmi' ),
209 ( '@tanstack/react-query' , 'npm install @tanstack/react-query' ),
210 ]
211
212 for package, install_cmd in required_packages:
213 if package in deps:
214 result.add_pass( f " { package } installed (version: { deps[package] } )" )
215 else :
216 result.add_error( f " { package } not installed - run: { install_cmd } " )
217
218 def check_env_variables (project_path: Path, result: ValidationResult):
219 """Check for old environment variables that should be removed."""
220 env_files = [ '.env' , '.env.local' , '.env.example' ]
221 old_vars = [ 'NEXT_PUBLIC_ONCHAINKIT_API_KEY' , 'NEXT_PUBLIC_ONCHAINKIT_PROJECT_NAME' ]
222
223 for env_file in env_files:
224 env_path = project_path / env_file
225 if env_path.exists():
226 try :
227 content = env_path.read_text()
228 found = [var for var in old_vars if var in content]
229 if found:
230 result.add_warning( f " { env_file } contains old MiniKit vars: { ', ' .join(found) } " )
231 except Exception :
232 pass
233
234 def check_manifest (project_path: Path, result: ValidationResult):
235 """Check farcaster.json manifest uses 'miniapp' instead of 'frame'."""
236 # Check for manifest route
237 manifest_paths = [
238 project_path / 'app' / '.well-known' / 'farcaster.json' / 'route.ts' ,
239 project_path / 'app' / '.well-known' / 'farcaster.json' / 'route.js' ,
240 project_path / 'pages' / 'api' / '.well-known' / 'farcaster.json.ts' ,
241 project_path / 'pages' / 'api' / '.well-known' / 'farcaster.json.js' ,
242 project_path / 'public' / '.well-known' / 'farcaster.json' ,
243 ]
244
245 manifest_found = False
246 for manifest_path in manifest_paths:
247 if manifest_path.exists():
248 manifest_found = True
249 try :
250 content = manifest_path.read_text()
251
252 # Check for old 'frame' key
253 if MANIFEST_FRAME_KEY .search(content):
254 result.add_error( f "Manifest uses 'frame' key - change to 'miniapp': { manifest_path.relative_to(project_path) } " )
255
256 # Check for new 'miniapp' key
257 if MANIFEST_MINIAPP_KEY .search(content):
258 result.add_pass( f "Manifest correctly uses 'miniapp' key: { manifest_path.relative_to(project_path) } " )
259 elif not MANIFEST_FRAME_KEY .search(content):
260 result.add_warning( f "Manifest found but no 'miniapp' or 'frame' key detected: { manifest_path.relative_to(project_path) } " )
261
262 except Exception as e:
263 result.add_warning( f "Could not read manifest: { e } " )
264 break
265
266 if not manifest_found:
267 result.add_warning( "No farcaster.json manifest found - create app/.well-known/farcaster.json/route.ts" )
268
269 def validate_project (project_dir: str ) -> ValidationResult:
270 """Run all validation checks."""
271 project_path = Path(project_dir).resolve()
272 result = ValidationResult()
273
274 if not project_path.exists():
275 result.add_error( f "Directory does not exist: { project_dir } " )
276 return result
277
278 files = find_source_files( str (project_path))
279
280 if not files:
281 result.add_warning( "No source files found" )
282 return result
283
284 # Run checks
285 check_no_minikit_imports(files, project_path, result)
286 check_no_minikit_hooks(files, project_path, result)
287 check_no_provider(files, project_path, result)
288 check_farcaster_sdk_usage(files, project_path, result)
289 check_package_json(project_path, result)
290 check_env_variables(project_path, result)
291 check_manifest(project_path, result)
292
293 return result
294
295 def print_result (result: ValidationResult):
296 """Print validation results."""
297 print ( " \n " + "=" * 60 )
298 print ( "CONVERSION VALIDATION REPORT" )
299 print ( "=" * 60 )
300
301 if result.passed:
302 print ( " \n ✅ PASSED:" )
303 for msg in result.passed:
304 print ( f " { msg } " )
305
306 if result.warnings:
307 print ( " \n ⚠️ WARNINGS:" )
308 for msg in result.warnings:
309 print ( f " { msg } " )
310
311 if result.errors:
312 print ( " \n ❌ ERRORS:" )
313 for msg in result.errors:
314 print ( f " { msg } " )
315
316 print ( " \n " + "-" * 60 )
317 if result.is_valid:
318 print ( "✅ VALIDATION PASSED - Conversion looks complete!" )
319 else :
320 print ( "❌ VALIDATION FAILED - Please fix the errors above" )
321 print ( "=" * 60 + " \n " )
322
323 def main ():
324 if len (sys.argv) < 2 :
325 print ( "Usage: python validate_conversion.py <project_dir>" )
326 print ( "Example: python validate_conversion.py ./my-converted-app" )
327 sys.exit( 1 )
328
329 project_dir = sys.argv[ 1 ]
330 result = validate_project(project_dir)
331 print_result(result)
332
333 sys.exit( 0 if result.is_valid else 1 )
334
335 if __name__ == '__main__' :
336 main()