@@ -907,8 +907,12 @@ protected function expandTypeOption(string $option, int $indent): string
907907 * Render a model property, breaking a parenthesised union array type across
908908 * lines when the declaration overflows the print width.
909909 */
910- protected function formatModelProperty (string $ label , string $ type , int $ indent ): string
910+ protected function formatModelProperty (string $ label , string $ type , int $ indent, bool $ nullable = false ): string
911911 {
912+ if ($ nullable ) {
913+ return $ this ->formatNullableModelProperty ($ label , $ type , $ indent );
914+ }
915+
912916 $ pad = str_repeat (' ' , $ indent );
913917 if (mb_strlen ($ pad . $ label . ': ' . $ type . '; ' ) <= self ::PRINT_WIDTH ) {
914918 return $ label . ': ' . $ type . '; ' ;
@@ -936,6 +940,34 @@ protected function formatModelProperty(string $label, string $type, int $indent)
936940 . implode ("\n" . $ inner . '| ' , $ options ) . "\n" . $ pad . ')[]; ' ;
937941 }
938942
943+ protected function formatNullableModelProperty (string $ label , string $ type , int $ indent ): string
944+ {
945+ $ pad = str_repeat (' ' , $ indent );
946+ $ union = $ type . ' | null ' ;
947+ if (mb_strlen ($ pad . $ label . ': ' . $ union . '; ' ) <= self ::PRINT_WIDTH ) {
948+ return $ label . ': ' . $ union . '; ' ;
949+ }
950+
951+ $ inner = $ pad . str_repeat (' ' , 4 );
952+ if (!str_contains ($ type , '< ' ) && mb_strlen ($ inner . $ union . '; ' ) <= self ::PRINT_WIDTH ) {
953+ return $ label . ": \n" . $ inner . $ union . '; ' ;
954+ }
955+
956+ if (preg_match ('/^\((.+)\)\[\]$/ ' , $ type , $ match ) === 1 ) {
957+ if (mb_strlen ($ inner . '| ' . $ type ) <= self ::PRINT_WIDTH ) {
958+ return $ label . ": \n" . $ inner . '| ' . $ type . "\n" . $ inner . '| null; ' ;
959+ }
960+
961+ $ options = $ this ->splitTopLevel ($ match [1 ], '| ' , trackGenerics: true );
962+ $ member = $ inner . str_repeat (' ' , 6 ) . '| ' ;
963+
964+ return $ label . ": \n" . $ inner . "| ( \n" . $ member . implode ("\n" . $ member , $ options )
965+ . "\n" . $ inner . ' )[] ' . "\n" . $ inner . '| null; ' ;
966+ }
967+
968+ return $ label . ': ' . $ union . '; ' ;
969+ }
970+
939971 /**
940972 * Break a union return type across lines when the closing `): Type` line
941973 * overflows, matching Prettier's leading-pipe layout inside the generic.
@@ -1096,7 +1128,7 @@ public function getFilters(): array
10961128
10971129 return $ lhs . ' ' . $ this ->wrapConditionalType ($ type , $ indent );
10981130 }, ['is_safe ' => ['html ' ]]),
1099- new TwigFilter ('tsModelProperty ' , fn (string $ label , string $ type , int $ indent = 8 ): string => $ this ->formatModelProperty ($ label , $ type , $ indent ), ['is_safe ' => ['html ' ]]),
1131+ new TwigFilter ('tsModelProperty ' , fn (string $ label , string $ type , int $ indent = 8 , bool $ nullable = false ): string => $ this ->formatModelProperty ($ label , $ type , $ indent, $ nullable ), ['is_safe ' => ['html ' ]]),
11001132 new TwigFilter ('tsArgument ' , fn (Operation $ method , ?Parameter $ parameter = null ): string => $ this ->formatArgument ($ method , $ parameter ), ['is_safe ' => ['html ' ]]),
11011133 new TwigFilter ('tsRestTuple ' , fn (Operation $ method , Specification $ spec ): string => $ this ->formatRestTuple ($ method , $ spec ), ['is_safe ' => ['html ' ]]),
11021134 new TwigFilter ('tsTypeAlias ' , fn (string $ name , string $ generics , string $ tail , int $ indent = 4 ): string => $ this ->formatTypeAlias ($ name , $ generics , $ tail , $ indent ), ['is_safe ' => ['html ' ]]),
0 commit comments