Setting the file. One moment.
Analyze Project · Build On Base · base/skills · Skills Docs
ContentsBack to the top of the page Previous
Reference Run Node
scripts/ analyze_project.py
Python · 290 lines · 9 KB
17 import sys
18 from pathlib import Path
19 from typing import TypedDict, List
20
21 class HookUsage ( TypedDict ):
22 hook: str
23 file : str
24 line: int
25 code: str
26
27 class ImportInfo ( TypedDict ):
28 file : str
29 line: int
30 imports: List[ str ]
31
32 class AnalysisReport ( TypedDict ):
33 project_dir: str
34 files_scanned: int
35 files_with_minikit: int
36 imports: List[ImportInfo]
37 hook_usages: List[HookUsage]
38 provider_locations: List[ dict ]
39 summary: dict
40
41 # MiniKit hooks to search for
42 MINIKIT_HOOKS = [
43 'useMiniKit' ,
44 'useClose' ,
45 'useOpenUrl' ,
46 'useViewProfile' ,
47 'useViewCast' ,
48 'useComposeCast' ,
49 'useAddFrame' ,
50 'useAuthenticate' ,
51 'useNotification' ,
52 'usePrimaryButton' ,
53 ]
54
55 # Import patterns - both @coinbase/onchainkit/minikit AND @coinbase/onchainkit
56 MINIKIT_IMPORT_PATTERN = re.compile(
57 r "from \s + [ ' \" ] @coinbase/onchainkit (?: /minikit ) ? [ ' \" ] "
58 )
59
60 # OnchainKitProvider with miniKit prop
61 ONCHAINKIT_PROVIDER_PATTERN = re.compile(
62 r "<OnchainKitProvider | OnchainKitProvider"
63 )
64
65 MINIKIT_PROVIDER_PATTERN = re.compile(
66 r "<MiniKitProvider | MiniKitProvider"
67 )
68
69 MINIKIT_PROP_PATTERN = re.compile(
70 r "miniKit \s * [ =:{ ] "
71 )
72
73 def find_files (directory: str , extensions: tuple = ( '.tsx' , '.ts' , '.jsx' , '.js' )) -> List[Path]:
74 """Find all relevant source files in directory."""
75 files = []
76 for root, _, filenames in os.walk(directory):
77 # Skip node_modules and .next
78 if 'node_modules' in root or '.next' in root:
79 continue
80 for filename in filenames:
81 if filename.endswith(extensions):
82 files.append(Path(root) / filename)
83 return files
84
85 def analyze_file (filepath: Path) -> dict :
86 """Analyze a single file for MiniKit usage."""
87 result = {
88 'imports' : [],
89 'hooks' : [],
90 'provider' : False ,
91 'provider_lines' : [],
92 'provider_type' : None
93 }
94
95 try :
96 content = filepath.read_text( encoding = 'utf-8' )
97 except Exception as e:
98 print ( f "Warning: Could not read { filepath } : { e } " , file = sys.stderr)
99 return result
100
101 lines = content.split( ' \n ' )
102
103 for i, line in enumerate (lines, 1 ):
104 # Check for imports from @coinbase/onchainkit or @coinbase/onchainkit/minikit
105 if MINIKIT_IMPORT_PATTERN .search(line):
106 # Extract what's being imported
107 import_match = re.search( r "import \s + \{ ([ ^} ] + ) \} " , line)
108 if import_match:
109 imports = [s.strip() for s in import_match.group( 1 ).split( ',' )]
110 result[ 'imports' ].append({
111 'line' : i,
112 'imports' : imports
113 })
114
115 # Check for hook usages
116 for hook in MINIKIT_HOOKS :
117 hook_pattern = re.compile( rf '\b { hook } \s*\(' )
118 if hook_pattern.search(line):
119 result[ 'hooks' ].append({
120 'hook' : hook,
121 'line' : i,
122 'code' : line.strip()
123 })
124
125 # Check for OnchainKitProvider (may have miniKit prop)
126 if ONCHAINKIT_PROVIDER_PATTERN .search(line):
127 result[ 'provider' ] = True
128 result[ 'provider_type' ] = 'OnchainKitProvider'
129 result[ 'provider_lines' ].append({
130 'line' : i,
131 'code' : line.strip()
132 })
133
134 # Check for MiniKitProvider
135 if MINIKIT_PROVIDER_PATTERN .search(line):
136 result[ 'provider' ] = True
137 result[ 'provider_type' ] = 'MiniKitProvider'
138 result[ 'provider_lines' ].append({
139 'line' : i,
140 'code' : line.strip()
141 })
142
143 # Check for miniKit prop
144 if MINIKIT_PROP_PATTERN .search(line):
145 result[ 'provider_lines' ].append({
146 'line' : i,
147 'code' : line.strip(),
148 'is_minikit_prop' : True
149 })
150
151 return result
152
153 def analyze_project (project_dir: str ) -> AnalysisReport:
154 """Analyze entire project for MiniKit usage."""
155 project_path = Path(project_dir).resolve()
156
157 if not project_path.exists():
158 print ( f "Error: Directory { project_dir } does not exist" , file = sys.stderr)
159 sys.exit( 1 )
160
161 files = find_files( str (project_path))
162
163 report: AnalysisReport = {
164 'project_dir' : str (project_path),
165 'files_scanned' : len (files),
166 'files_with_minikit' : 0 ,
167 'imports' : [],
168 'hook_usages' : [],
169 'provider_locations' : [],
170 'summary' : {}
171 }
172
173 hook_counts = {hook: 0 for hook in MINIKIT_HOOKS }
174
175 for filepath in files:
176 result = analyze_file(filepath)
177 rel_path = str (filepath.relative_to(project_path))
178
179 has_minikit = bool (result[ 'imports' ] or result[ 'hooks' ] or result[ 'provider' ])
180
181 if has_minikit:
182 report[ 'files_with_minikit' ] += 1
183
184 # Collect imports
185 for imp in result[ 'imports' ]:
186 report[ 'imports' ].append({
187 'file' : rel_path,
188 'line' : imp[ 'line' ],
189 'imports' : imp[ 'imports' ]
190 })
191
192 # Collect hook usages
193 for hook_usage in result[ 'hooks' ]:
194 report[ 'hook_usages' ].append({
195 'hook' : hook_usage[ 'hook' ],
196 'file' : rel_path,
197 'line' : hook_usage[ 'line' ],
198 'code' : hook_usage[ 'code' ]
199 })
200 hook_counts[hook_usage[ 'hook' ]] += 1
201
202 # Collect provider locations
203 if result[ 'provider' ]:
204 for provider_info in result[ 'provider_lines' ]:
205 report[ 'provider_locations' ].append({
206 'file' : rel_path,
207 'line' : provider_info[ 'line' ],
208 'code' : provider_info[ 'code' ]
209 })
210
211 # Build summary
212 report[ 'summary' ] = {
213 'total_hook_usages' : sum (hook_counts.values()),
214 'hooks_by_type' : {k: v for k, v in hook_counts.items() if v > 0 },
215 'has_provider' : len (report[ 'provider_locations' ]) > 0 ,
216 'unique_hooks_used' : [k for k, v in hook_counts.items() if v > 0 ]
217 }
218
219 return report
220
221 def print_report (report: AnalysisReport):
222 """Print human-readable report."""
223 print ( " \n " + "=" * 60 )
224 print ( "MINIKIT ANALYSIS REPORT" )
225 print ( "=" * 60 )
226 print ( f " \n Project: { report[ 'project_dir' ] } " )
227 print ( f "Files scanned: { report[ 'files_scanned' ] } " )
228 print ( f "Files with MiniKit: { report[ 'files_with_minikit' ] } " )
229
230 print ( " \n --- IMPORTS ---" )
231 if report[ 'imports' ]:
232 for imp in report[ 'imports' ]:
233 print ( f " { imp[ 'file' ] } : { imp[ 'line' ] } " )
234 print ( f " Imports: { ', ' .join(imp[ 'imports' ]) } " )
235 else :
236 print ( " No MiniKit imports found" )
237
238 print ( " \n --- HOOK USAGES ---" )
239 if report[ 'hook_usages' ]:
240 for usage in report[ 'hook_usages' ]:
241 print ( f " { usage[ 'file' ] } : { usage[ 'line' ] } " )
242 print ( f " Hook: { usage[ 'hook' ] } " )
243 print ( f " Code: { usage[ 'code' ][: 80 ] } ..." )
244 else :
245 print ( " No hook usages found" )
246
247 print ( " \n --- PROVIDER LOCATIONS ---" )
248 if report[ 'provider_locations' ]:
249 for loc in report[ 'provider_locations' ]:
250 print ( f " { loc[ 'file' ] } : { loc[ 'line' ] } " )
251 print ( f " { loc[ 'code' ][: 80 ] } " )
252 else :
253 print ( " No MiniKitProvider found" )
254
255 print ( " \n --- SUMMARY ---" )
256 summary = report[ 'summary' ]
257 print ( f " Total hook usages: { summary[ 'total_hook_usages' ] } " )
258 print ( f " Unique hooks: { ', ' .join(summary[ 'unique_hooks_used' ]) or 'None' } " )
259 print ( f " Has provider: { 'Yes' if summary[ 'has_provider' ] else 'No' } " )
260
261 if summary[ 'hooks_by_type' ]:
262 print ( " \n Hooks by frequency:" )
263 for hook, count in sorted (summary[ 'hooks_by_type' ].items(), key =lambda x: - x[ 1 ]):
264 print ( f " { hook } : { count } " )
265
266 print ( " \n " + "=" * 60 )
267
268 def main ():
269 if len (sys.argv) < 2 :
270 print ( "Usage: python analyze_project.py <project_dir> [--json]" )
271 print ( "Example: python analyze_project.py ./my-minikit-app" )
272 sys.exit( 1 )
273
274 project_dir = sys.argv[ 1 ]
275 output_json = '--json' in sys.argv
276
277 report = analyze_project(project_dir)
278
279 if output_json:
280 print (json.dumps(report, indent = 2 ))
281 else :
282 print_report(report)
283 # Also save JSON report
284 report_path = Path(project_dir) / 'minikit-analysis.json'
285 with open (report_path, 'w' ) as f:
286 json.dump(report, f, indent = 2 )
287 print ( f " \n JSON report saved to: { report_path } " )
288
289 if __name__ == '__main__' :
290 main()