44
55namespace App ;
66
7+ /**
8+ * @phpstan-type AnnotationData array{lineNr: int, classAnnotation: string, annotated: string}
9+ */
710class LuaFileParser
811{
912 /** @var array<string, array<string, array{lineNr: int, classAnnotation: string, annotated: string}> [filename => [mixin name => mixin data]] */
1013 private array $ mixins = [];
14+ /** @var array<string, list<array{lineNr: int, enumAnnotation: null|string, typeAnnotation: string}>> [filename => list of enum data] */
15+ private array $ enums = [];
1116 /** @var array<string, array<string, string> [filename => [function name => function data]] */
1217 private array $ functions = [];
1318
@@ -21,7 +26,9 @@ public function parse(string $filename, string $prefixToStrip, ?string $linkPref
2126 $ fileContents = file_get_contents ($ filename );
2227 if (str_starts_with ($ filename , $ prefixToStrip )) {
2328 $ linkFilename = substr ($ filename , strlen ($ prefixToStrip ));
24- $ linkPrefix = $ linkPrefix ? str_replace ('// ' , '/ ' , $ linkPrefix . '/ ' . $ linkFilename ) : null ;
29+ $ linkPrefix = $ linkPrefix
30+ ? sprintf ('%s/%s ' , rtrim ($ linkPrefix , '/ ' ), ltrim ($ linkFilename , '/ ' ))
31+ : null ;
2532 }
2633
2734 $ mixins = $ this ->extractMixins ($ fileContents , $ linkPrefix );
@@ -30,6 +37,8 @@ public function parse(string $filename, string $prefixToStrip, ?string $linkPref
3037 if (!$ this ->mixAnnotationsIntoSource ) {
3138 $ functions = $ this ->extractFunctions ($ fileContents , $ mixins , $ linkPrefix );
3239 $ this ->functions [$ filename ] = $ functions ;
40+ } else {
41+ $ this ->enums [$ filename ] = $ this ->extractEnums ($ fileContents , $ linkPrefix );
3342 }
3443 }
3544
@@ -41,6 +50,9 @@ public function writeAnnotationsToFile(string $filename, string $outDir, string
4150 foreach ($ this ->mixins [$ filename ] ?? [] as $ funcInfo ) {
4251 $ byLine [$ funcInfo ['lineNr ' ] - 1 ] .= $ funcInfo ['classAnnotation ' ];
4352 }
53+ foreach ($ this ->enums [$ filename ] ?? [] as $ enumInfo ) {
54+ $ byLine [$ enumInfo ['lineNr ' ] - 1 ] .= $ enumInfo ['typeAnnotation ' ];
55+ }
4456 $ data = implode ("\n" , $ byLine );
4557 } else {
4658 if (empty ($ this ->mixins [$ filename ]) && empty ($ this ->functions [$ filename ])) {
@@ -62,6 +74,25 @@ public function writeAnnotationsToFile(string $filename, string $outDir, string
6274 file_put_contents ($ targetFile , $ data );
6375 }
6476
77+ public function writeEnumsFile (string $ filename , string $ outDir ): void
78+ {
79+ $ targetFile = $ outDir . '/ ' . $ filename . '.annotated.lua ' ;
80+ if (!is_dir (dirname ($ targetFile ))) {
81+ mkdir ($ outDir . '/ ' . dirname ($ filename ), recursive: true );
82+ }
83+
84+ $ data = "--- @meta _ \n\n" ;
85+ foreach ($ this ->enums as $ enums ) {
86+ foreach ($ enums as $ enumInfo ) {
87+ if ($ enumInfo ['enumAnnotation ' ]) {
88+ $ data .= $ enumInfo ['enumAnnotation ' ] . "\n\n" ;
89+ }
90+ }
91+ }
92+
93+ file_put_contents ($ targetFile , $ data );
94+ }
95+
6596 private function extractMixins (string $ fileContents , ?string $ linkPrefix ): array
6697 {
6798 $ mixins = [];
@@ -194,6 +225,88 @@ private function extractFunctions(string $fileContents, array $mixins, ?string $
194225 return $ functions ;
195226 }
196227
228+ private function extractEnums (string $ fileContents , ?string $ linkPrefix ): array
229+ {
230+ $ enums = [];
231+ // e.g. `local foo = EnumUtil.MakeEnum("firstValue", "secondValue", "Value3")`
232+ // e.g. `foo = EnumUtil.MakeEnum("firstValue", "secondValue", "Value3")`
233+ // e.g. `Something.Foo = EnumUtil.MakeEnum("firstValue", "secondValue", "Value3")`
234+ $ regex = '/^(?<local>local )?(?<name>\S+) = EnumUtil\.MakeEnum\((?<values>(?:\s*"[^",]+?",?\s*(?:--\s*(?<comment>[^\n]+\n))?)+)\)/m ' ;
235+ $ valueRegex = '/(?<value>"[^",]+?"),?\s*(?:--\s*(?<comment>[^\n]+))?/m ' ;
236+ $ matches = [];
237+ preg_match_all (
238+ $ regex ,
239+ $ fileContents ,
240+ $ matches ,
241+ PREG_SET_ORDER | PREG_OFFSET_CAPTURE ,
242+ );
243+ foreach ($ matches as $ match ) {
244+ $ isLocal = $ match ['local ' ][1 ] !== -1 ;
245+ $ enumName = $ match ['name ' ][0 ];
246+ $ enumValuesRaw = $ match ['values ' ][0 ];
247+ $ enumValues = [];
248+ $ valueComments = [];
249+ $ valueMatches = [];
250+ preg_match_all ($ valueRegex , $ enumValuesRaw , $ valueMatches , PREG_SET_ORDER | PREG_OFFSET_CAPTURE );
251+ foreach ($ valueMatches as $ valueMatch ) {
252+ $ value = $ valueMatch ['value ' ][0 ];
253+ if (isset ($ valueMatch ['comment ' ]) && $ valueMatch ['comment ' ][1 ] !== -1 ) {
254+ $ valueComments [] = ' -- ' . $ valueMatch ['comment ' ][0 ];
255+ } else {
256+ $ valueComments [] = '' ;
257+ }
258+ $ enumValues [] = $ value ;
259+ }
260+
261+ // --- @type {["firstValue"] = 1, ["secondValue"] = 2, ["value3"] = 3}
262+ $ typeAnnotation = sprintf (
263+ '--- @type {%s} ' ,
264+ implode (
265+ ', ' ,
266+ array_map (
267+ fn (string $ v , int $ i ) => sprintf (
268+ '[%s]: %d ' ,
269+ str_replace ("\n" , ' ' , $ v ),
270+ $ i + 1 ,
271+ ),
272+ $ enumValues ,
273+ array_keys ($ enumValues ),
274+ ),
275+ ),
276+ );
277+ $ lineNr = $ this ->getLineNrFromOffset ($ fileContents , $ match ['name ' ][1 ]);
278+ if ($ isLocal ) {
279+ $ enumAnnotation = null ;
280+ } else {
281+ $ typeAnnotation .= sprintf (' See [%s](lua://%s) ' , $ enumName , $ enumName );
282+ $ enumAnnotation = sprintf (
283+ "--- @enum %s \nlocal %s = { \n %s \n} " ,
284+ $ enumName ,
285+ str_replace ('. ' , '_ ' , $ enumName ),
286+ implode (
287+ "\n " ,
288+ array_map (
289+ fn (string $ v , int $ i , string $ comment ) => sprintf ('[%s] = %d,%s ' , $ v , $ i + 1 , $ comment ),
290+ $ enumValues ,
291+ array_keys ($ enumValues ),
292+ $ valueComments ,
293+ ),
294+ ),
295+ );
296+ if ($ linkPrefix ) {
297+ $ enumAnnotation = "--- [Source]( $ linkPrefix#L $ lineNr) \n$ enumAnnotation " ;
298+ }
299+ }
300+ $ enums [] = [
301+ 'lineNr ' => $ lineNr ,
302+ 'enumAnnotation ' => $ enumAnnotation ,
303+ 'typeAnnotation ' => $ typeAnnotation ,
304+ ];
305+ }
306+
307+ return $ enums ;
308+ }
309+
197310 private function getLineNrFromOffset (string $ file , int $ offset ): int
198311 {
199312 return substr_count ($ file , "\n" , 0 , $ offset ) + 1 ;
0 commit comments