1919use Lkrms \Support \ProviderContext ;
2020use Lkrms \Support \TokenExtractor ;
2121use Lkrms \Utility \Arr ;
22- use Lkrms \Utility \Convert ;
2322use Lkrms \Utility \File ;
2423use Lkrms \Utility \Get ;
2524use Lkrms \Utility \Package ;
25+ use Lkrms \Utility \Pcre ;
2626use Lkrms \Utility \Reflect ;
2727use Lkrms \Utility \Str ;
2828use Lkrms \Utility \Test ;
@@ -383,25 +383,56 @@ protected function resolveTemplates(string $type, array $templates, ?PhpDocTempl
383383 */
384384 protected function getPhpDocTypeAlias ($ type , array $ templates , string $ namespace , ?string $ filename = null , array &$ inputClassTemplates = []): string
385385 {
386- return PhpDocTag::normaliseType (preg_replace_callback (
386+ /** @var string */
387+ $ subject = $ type instanceof PhpDocTag
388+ ? Str::coalesce ($ type ->Type , '' )
389+ : $ type ;
390+
391+ return PhpDocTag::normaliseType (Pcre::replaceCallback (
387392 '/(?<!\$)([a-z_]+(-[a-z0-9_]+)+|(?= \\\\?\b) ' . Regex::PHP_TYPE . ')\b/i ' ,
388- function ($ match ) use ($ type , $ namespace , $ templates , $ filename , &$ inputClassTemplates ) {
389- $ t = $ this ->resolveTemplates ($ match [0 ], $ templates , $ template , $ inputClassTemplates );
393+ function ($ match ) use (
394+ $ type ,
395+ $ templates ,
396+ $ namespace ,
397+ $ filename ,
398+ &$ inputClassTemplates ,
399+ $ subject
400+ ) {
401+ $ t = $ this ->resolveTemplates ($ match [0 ][0 ], $ templates , $ template , $ inputClassTemplates );
390402 $ type = $ template ?: $ type ;
391- if ($ type instanceof PhpDocTag && $ type ->Class ) {
403+ if ($ type instanceof PhpDocTag && $ type ->Class !== null ) {
392404 $ class = new ReflectionClass ($ type ->Class );
393405 $ namespace = $ class ->getNamespaceName ();
394406 $ filename = $ class ->getFileName ();
395407 }
396408 // Recurse if template expansion occurred
397- if ($ t !== $ match [0 ]) {
409+ if ($ t !== $ match [0 ][ 0 ] ) {
398410 return $ this ->getPhpDocTypeAlias ($ t , $ templates , $ namespace , $ filename );
399411 }
400412 // Leave reserved words and PHPDoc types (e.g. `class-string`)
401413 // alone
402414 if (Test::isPhpReservedWord ($ t ) || strpos ($ t , '- ' ) !== false ) {
403415 return $ t ;
404416 }
417+ // Leave `min` and `max` (lowercase) alone if they appear
418+ // between angle brackets after `int` (not case sensitive)
419+ if ($ t === 'min ' || $ t === 'max ' ) {
420+ // - before: `'array < int < 1, max > >'`
421+ // - after: `['array', '<', 'int', '<', '1']`
422+ $ before = substr ($ subject , 0 , $ match [0 ][1 ]);
423+ $ before = Pcre::split ('/(?=(?<![-a-z0-9$ \\\\_])int\s*<)|(?=<)|(?<=<)|,/i ' , $ before );
424+ $ before = Arr::trim ($ before );
425+ while ($ before ) {
426+ $ last = array_pop ($ before );
427+ if ($ last === 'min ' || $ last === 'max ' || Test::isIntValue ($ last )) {
428+ continue ;
429+ }
430+ if ($ last === '< ' && $ before && Str::lower (array_pop ($ before )) === 'int ' ) {
431+ return $ t ;
432+ }
433+ break ;
434+ }
435+ }
405436 // Don't waste time trying to find a FQCN in $InputFileUseMaps
406437 if (($ t [0 ] ?? null ) === '\\' ) {
407438 return $ this ->getTypeAlias ($ t );
@@ -412,9 +443,10 @@ function ($match) use ($type, $namespace, $templates, $filename, &$inputClassTem
412443 $ filename
413444 );
414445 },
415- $ type instanceof PhpDocTag
416- ? ($ type ->Type ?: '' )
417- : $ type
446+ $ subject ,
447+ -1 ,
448+ $ count ,
449+ \PREG_OFFSET_CAPTURE ,
418450 ));
419451 }
420452
@@ -812,7 +844,7 @@ protected function handleOutput($lines): void
812844 */
813845 protected function code ($ value ): string
814846 {
815- return Convert:: valueToCode ($ value , ', ' . \PHP_EOL , ' => ' , null , self ::TAB );
847+ return Get:: code ($ value , ', ' . \PHP_EOL , ' => ' , null , self ::TAB );
816848 }
817849
818850 /**
0 commit comments