11import os
22import sys
3+ import re
34from bs4 import BeautifulSoup
45
6+ debug = False
7+
58def extract_method_info (soup ):
69 method_section = soup .find ('h1' )
710 class_name_tag = method_section .find_next ()
@@ -105,6 +108,62 @@ def extract_argument_name_opt(argument_name):
105108 argument_optional_value = optional_part
106109 return argument_name , argument_optional , argument_optional_value
107110
111+ def extract_table (soup ):
112+ # Extract the header row
113+ header = soup .find ('thead' )
114+ if header is None :
115+ return []
116+
117+ header_row = header .find_all ('th' )
118+ if not header_row :
119+ return []
120+
121+ # Extract the column names (keys) from the header
122+ headers = [header .get_text (strip = True ) for header in header_row ]
123+
124+ # Find all the table rows, skipping the header
125+ rows = soup .find_all ('tr' )[1 :]
126+ if not rows :
127+ return []
128+
129+ row_list = []
130+
131+ for row in rows :
132+ cells = row .find_all ('td' )
133+ if not cells :
134+ return []
135+
136+ # Ensure the row has the same number of columns as the header
137+ if len (cells ) != len (headers ):
138+ continue # Skip rows that don't match the header
139+
140+ cell_data = {}
141+ for idx , cell in enumerate (cells ):
142+ # Check if the cell contains any <span> elements
143+ if cell .find_all ('span' ):
144+ cell_data [headers [idx ]] = extract_parameters (cell )
145+ else :
146+ cell_data [headers [idx ]] = cell .get_text (strip = True )
147+
148+ row_list .append (cell_data )
149+
150+ return row_list
151+
152+ def extract_parameters (cell ):
153+ parameters = {}
154+
155+ # Find all <span> tags in the 'cell'
156+ spans = cell .find_all ('span' )
157+
158+ # Extract the 'title' as the key and text as the value
159+ for span in spans :
160+ title = span .get ('title' )
161+ text = span .get_text (strip = True )
162+ if title :
163+ parameters [text ] = title
164+
165+ return parameters
166+
108167def extract_return_values (soup ):
109168 returns_section = soup .find ('h2' , id = 'returns' )
110169 if returns_section is None :
@@ -143,9 +202,9 @@ def extract_return_values(soup):
143202 return_values_list .append ({'type' : return_type , 'name' : return_name , 'description' : return_description })
144203 return return_values_list
145204
146- def write_lua_stub (class_name , method_string , arguments_list , return_values_list , output_directory ):
205+ def write_lua_stub (class_name , method_string , arguments_list , table_list , return_values_list , output_directory ):
147206 with open (os .path .join (output_directory , class_name + ".lua" ), "a" ) as lua_file :
148- # Write the parameter and return values
207+ # Write the parameter definitions
149208 for argument in arguments_list :
150209 lua_file .write ("---@param " + argument ['name' ])
151210 if argument ['optional' ]:
@@ -157,6 +216,27 @@ def write_lua_stub(class_name, method_string, arguments_list, return_values_list
157216 lua_file .write (" Default value: (" + argument ['optional_val' ] + ")" )
158217
159218 lua_file .write (" " + argument ['description' ] + "\n " )
219+
220+ # Hard code table parsing for register events for now (function overload definitions)
221+ if (class_name == "Global" ) and re .match (r"^Register\w+Event$" , method_string ):
222+ for row in table_list :
223+ # Only create function overloads for properly formatted parameter data
224+ if 'Parameters' in row and isinstance (row ['Parameters' ], dict ):
225+ lua_file .write ("---@overload fun(event: " + row ['ID' ] + ", func: fun(" )
226+
227+ # Loop through parameters and check for 'event', we want to define this as the event ID and not a type
228+ params = []
229+ for key , value in row ['Parameters' ].items ():
230+ if key == 'event' :
231+ params .append (f'{ key } : { row ["ID" ]} ' )
232+ else :
233+ params .append (f'{ key } : { value } ' )
234+
235+ # Join the parameters and write to the file
236+ lua_file .write (', ' .join (params ))
237+ lua_file .write ("), shots?: number): function\n " )
238+
239+ # Write the return value definitions
160240 for return_value in return_values_list :
161241 lua_file .write ("---@return " + return_value ['type' ] + " " + return_value ['name' ] + " " + return_value ['description' ] + "\n " )
162242
@@ -173,7 +253,9 @@ def write_lua_stub(class_name, method_string, arguments_list, return_values_list
173253
174254 lua_file .write (") end\n \n " )
175255
176- print (f"'{ method_string } ' stubs appended to '{ class_name } .lua'" )
256+ global debug
257+ if debug :
258+ print (f"'{ method_string } ' stubs appended to '{ class_name } .lua'" )
177259
178260def write_lua_class (class_name , inherited_objects , output_directory ):
179261 with open (os .path .join (output_directory , class_name + ".lua" ), "w" ) as lua_file :
@@ -184,8 +266,10 @@ def write_lua_class(class_name, inherited_objects, output_directory):
184266 lua_file .write (f": { ', ' .join (inherited_objects )} " )
185267
186268 lua_file .write (f"\n { class_name } = {{}}\n \n " )
187-
188- print (f"'{ class_name } ' class information appended to '{ class_name } .lua'" )
269+
270+ global debug
271+ if debug :
272+ print (f"'{ class_name } ' class information appended to '{ class_name } .lua'" )
189273
190274def process_html_file (html_file , filename , output_directory ):
191275 with open (html_file , "r" ) as f :
@@ -202,19 +286,25 @@ def process_html_file(html_file, filename, output_directory):
202286 # Otherwise process like normal
203287 class_name , method_string = extract_method_info (soup )
204288 arguments_list = extract_arguments (soup )
289+ table_list = extract_table (soup )
205290 return_values_list = extract_return_values (soup )
206291
207- write_lua_stub (class_name , method_string , arguments_list , return_values_list , output_directory )
292+ write_lua_stub (class_name , method_string , arguments_list , table_list , return_values_list , output_directory )
208293
209294def main ():
210295 # Check if command-line arguments are provided
211- if len (sys .argv ) != 3 :
212- print ("Usage: python parser.py <html_input_directory> <output_directory>" )
296+ if len (sys .argv ) < 3 :
297+ print ("Usage: python parser.py <html_input_directory> <output_directory> <debug=false> " )
213298 sys .exit (1 )
214299
215300 directory = sys .argv [1 ]
216301 output_directory = sys .argv [2 ]
217302
303+ # Debug (Optional) - Default to false if not provided
304+ if (sys .argv [3 ]):
305+ global debug
306+ debug = True if sys .argv [3 ].lower () == 'true' else False
307+
218308 # Special case to process our class definitions
219309 html_file = os .path .join (directory , "index.html" )
220310 process_html_file (html_file , "index.html" , output_directory )
0 commit comments