99use OpenApi \Analysers \AttributeAnnotationFactory ;
1010use OpenApi \Analysers \DocBlockAnnotationFactory ;
1111use OpenApi \Analysers \ReflectionAnalyser ;
12+ use OpenApi \Annotations \OpenApi ;
1213use OpenApi \Generator ;
1314use OpenApi \SourceFinder ;
1415use Symfony \Component \Console \Attribute \AsCommand ;
1516use Symfony \Component \Console \Attribute \MapInput ;
1617use Symfony \Component \Console \Logger \ConsoleLogger ;
18+ use Symfony \Component \Console \Style \SymfonyStyle ;
1719
1820#[AsCommand(
19- name: 'generate ' ,
21+ name: 'openapi ' ,
2022 description: 'Generate OpenAPI documentation ' ,
2123)]
22- final class GenerateCommand
24+ class GenerateCommand
2325{
2426 public function __construct (
2527 private ConsoleLogger $ logger ,
2628 ) {
2729 }
2830
29- public function __invoke (#[MapInput] GenerateInput $ input ): int
31+ public function __invoke (#[MapInput] GenerateInput $ input, SymfonyStyle $ io ): int
3032 {
31- // Bootstrap
32- foreach ($ input ->bootstrap as $ bootstrapPattern ) {
33- $ filenames = glob ($ bootstrapPattern );
34- if (false === $ filenames ) {
35- $ this ->logger ->error ('Invalid `--bootstrap` value: " ' . $ bootstrapPattern . '" ' );
36-
37- return 1 ;
38- }
39- foreach ($ filenames as $ filename ) {
40- if ($ input ->debug ) {
41- $ this ->logger ->debug ('Bootstrapping: ' . $ filename );
42- }
43- require_once ($ filename );
33+ foreach ($ input ->getBootstrapFilenames () as $ filename ) {
34+ if ($ io ->isVerbose ()) {
35+ $ io ->info ('Bootstrapping: ' . $ filename );
4436 }
37+
38+ require_once ($ filename );
4539 }
4640
47- // Defaults
4841 if ($ input ->defaults ) {
49- $ this -> logger -> info ('Default config ' );
50- $ this -> logger -> info (json_encode ((new Generator ())->getDefaultConfig (), JSON_PRETTY_PRINT ));
42+ $ io -> title ('Default config ' );
43+ $ io -> writeln (json_encode ((new Generator ())->getDefaultConfig (), JSON_PRETTY_PRINT ));
5144
52- return 1 ;
45+ return 0 ;
5346 }
5447
55- // Exclude with comma-deprecation check
56- $ exclude = $ input ->exclude ?: null ;
57- if ($ exclude && str_contains ((string ) $ exclude [0 ], ', ' )) {
58- $ exploded = explode (', ' , (string ) $ exclude [0 ]);
59- $ this ->logger ->error ('Comma-separated exclude paths are deprecated, use multiple --exclude statements: --exclude ' . $ exploded [0 ] . ' --exclude ' . $ exploded [1 ]);
60- $ exclude [0 ] = array_shift ($ exploded );
61- $ exclude = array_merge ($ exclude , $ exploded );
48+ $ openapi = $ this ->generate ($ input );
49+
50+ if (!$ input ->output ) {
51+ if (strtolower ($ input ->format ) === 'json ' ) {
52+ echo $ openapi ->toJson ();
53+ } else {
54+ echo $ openapi ->toYaml ();
55+ }
56+ echo "\n" ;
57+ } else {
58+ $ outputPath = $ input ->output ;
59+ if (is_dir ($ outputPath )) {
60+ $ outputPath .= '/openapi.yaml ' ;
61+ }
62+ $ openapi ->saveAs ($ outputPath , $ input ->format );
6263 }
6364
64- // Generator
65+ return $ this ->logger ->hasErrored () ? 1 : 0 ;
66+ }
67+
68+ private function generate (GenerateInput $ input ): OpenApi
69+ {
6570 $ generator = new Generator ($ this ->logger );
71+
6672 foreach ($ input ->addProcessor as $ processor ) {
6773 $ class = '\OpenApi\Processors \\' . ucfirst ((string ) $ processor );
6874 if (class_exists ($ class )) {
@@ -72,43 +78,45 @@ public function __invoke(#[MapInput] GenerateInput $input): int
7278 }
7379 $ generator ->getProcessorPipeline ()->add ($ processor );
7480 }
81+
7582 foreach ($ input ->removeProcessor as $ processor ) {
7683 $ class = class_exists ($ processor )
77- ? $ class
84+ ? $ processor
7885 : '\OpenApi\Processors \\' . ucfirst ((string ) $ processor );
7986 $ generator ->getProcessorPipeline ()->remove ($ class );
8087 }
8188
82- // Analyser
8389 $ analyser = new ReflectionAnalyser ([
8490 new AttributeAnnotationFactory (),
8591 new DocBlockAnnotationFactory (),
8692 ]);
8793 $ analyser ->setGenerator ($ generator );
8894
89- // Generate
90- $ openapi = $ generator
95+ return $ generator
9196 ->setVersion ($ input ->version )
9297 ->setConfig ($ input ->config )
9398 ->setAnalyser ($ analyser )
94- ->generate (new SourceFinder ($ input ->paths , $ exclude , $ input ->pattern ));
99+ ->generate (new SourceFinder ($ input ->paths , $ this ->normalizeExcludePaths ($ input ->exclude ), $ input ->pattern ));
100+ }
95101
96- // Output
97- if (!$ input ->output ) {
98- if (strtolower ($ input ->format ) === 'json ' ) {
99- echo $ openapi ->toJson ();
100- } else {
101- echo $ openapi ->toYaml ();
102- }
103- echo "\n" ;
104- } else {
105- $ outputPath = $ input ->output ;
106- if (is_dir ($ outputPath )) {
107- $ outputPath .= '/openapi.yaml ' ;
108- }
109- $ openapi ->saveAs ($ outputPath , $ input ->format );
102+ /**
103+ * @param list<string> $exclude
104+ *
105+ * @return list<string>
106+ */
107+ private function normalizeExcludePaths (array $ exclude ): array
108+ {
109+ if (!$ exclude ) {
110+ return [];
110111 }
111112
112- return $ this ->logger ->hasErrored () ? 1 : 0 ;
113+ if (str_contains ($ exclude [0 ], ', ' )) {
114+ $ exploded = explode (', ' , $ exclude [0 ]);
115+ $ this ->logger ->error ('Comma-separated exclude paths are deprecated, use multiple --exclude statements: --exclude ' . $ exploded [0 ] . ' --exclude ' . $ exploded [1 ]);
116+ $ exclude [0 ] = array_shift ($ exploded );
117+ $ exclude = array_merge ($ exclude , $ exploded );
118+ }
119+
120+ return $ exclude ;
113121 }
114122}
0 commit comments