@@ -36,26 +36,40 @@ public function gen_all( $args, $assoc_args ) {
3636 }
3737
3838 self ::gen_api_docs ();
39+ self ::gen_behat_docs ();
3940 self ::gen_commands ( $ args , $ assoc_args );
4041 self ::gen_commands_manifest ();
4142 self ::gen_hb_manifest ();
4243 WP_CLI ::success ( 'Generated all doc pages. ' );
4344 }
4445
46+ private function prepare_api_slug ( $ full_name ) {
47+ $ replacements = [
48+ '\\w+ ' => '' ,
49+ '\\s ' => '' ,
50+ 's? ' => '' ,
51+ ':: ' => '- ' ,
52+ '_ ' => '- ' ,
53+ '\\' => '- ' ,
54+ ' ' => '- ' ,
55+ '. ' => '- ' ,
56+ '| ' => '- ' ,
57+ ];
58+ $ full_name = strtolower ( str_replace ( array_keys ( $ replacements ), array_values ( $ replacements ), $ full_name ) );
59+ $ full_name = preg_replace ( '/[^a-zA-Z0-9-]/ ' , '' , $ full_name );
60+ $ full_name = preg_replace ( '/-+/ ' , '- ' , $ full_name );
61+ $ full_name = trim ( $ full_name , '- ' );
62+ return $ full_name ;
63+ }
64+
4565 /**
4666 * Generates internal API doc pages.
4767 *
4868 * @subcommand gen-api-docs
4969 */
5070 public function gen_api_docs () {
51- $ apis = WP_CLI ::runcommand (
52- 'handbook api-dump ' ,
53- [
54- 'launch ' => false ,
55- 'return ' => 'stdout ' ,
56- 'parse ' => 'json ' ,
57- ]
58- );
71+ $ apis = $ this ->get_internal_apis ();
72+
5973 $ categories = [
6074 'Registration ' => [],
6175 'Output ' => [],
@@ -65,19 +79,9 @@ public function gen_api_docs() {
6579 'Misc ' => [],
6680 ];
6781
68- $ prepare_api_slug = function ( $ full_name ) {
69- $ replacements = [
70- '() ' => '' ,
71- ':: ' => '- ' ,
72- '_ ' => '- ' ,
73- '\\' => '- ' ,
74- ];
75- return strtolower ( str_replace ( array_keys ( $ replacements ), array_values ( $ replacements ), $ full_name ) );
76- };
77-
7882 foreach ( $ apis as $ api ) {
7983
80- $ api ['api_slug ' ] = $ prepare_api_slug ( $ api ['full_name ' ] );
84+ $ api ['api_slug ' ] = $ this -> prepare_api_slug ( $ api ['full_name ' ] );
8185
8286 if ( ! empty ( $ api ['phpdoc ' ]['parameters ' ]['category ' ][0 ][0 ] )
8387 && isset ( $ categories [ $ api ['phpdoc ' ]['parameters ' ]['category ' ][0 ][0 ] ] ) ) {
@@ -122,8 +126,9 @@ function ( $parameter ) {
122126 unset( $ api ['related ' ][ $ i ] );
123127 $ api ['related ' ] = array_values ( $ api ['related ' ] );
124128 $ api ['has_related ' ] = ! empty ( $ api ['related ' ] );
125- $ api_doc = self ::render ( 'internal-api.mustache ' , $ api );
126- $ path = WP_CLI_HANDBOOK_PATH . "/internal-api/ {$ api ['api_slug ' ]}.md " ;
129+
130+ $ api_doc = self ::render ( 'internal-api.mustache ' , $ api );
131+ $ path = WP_CLI_HANDBOOK_PATH . "/internal-api/ {$ api ['api_slug ' ]}.md " ;
127132 if ( ! is_dir ( dirname ( $ path ) ) ) {
128133 mkdir ( dirname ( $ path ) );
129134 }
@@ -136,6 +141,81 @@ function ( $parameter ) {
136141 WP_CLI ::success ( 'Generated internal-api/ ' );
137142 }
138143
144+ /**
145+ * Generates Behat steps doc pages.
146+ *
147+ * @subcommand gen-behat-docs
148+ */
149+ public function gen_behat_docs () {
150+ $ apis = $ this ->get_behat_steps ();
151+
152+ $ categories = [
153+ 'Given ' => [],
154+ 'When ' => [],
155+ 'Then ' => [],
156+ ];
157+
158+ foreach ( $ apis as $ api ) {
159+
160+ $ api ['api_slug ' ] = $ this ->prepare_api_slug ( $ api ['full_name ' ] );
161+
162+ if ( isset ( $ api ['phpdoc ' ]['parameters ' ]['Given ' ] ) ) {
163+ $ categories ['Given ' ][] = $ api ;
164+ } elseif ( isset ( $ api ['phpdoc ' ]['parameters ' ]['When ' ] ) ) {
165+ $ categories ['When ' ][] = $ api ;
166+ } elseif ( isset ( $ api ['phpdoc ' ]['parameters ' ]['Then ' ] ) ) {
167+ $ categories ['Then ' ][] = $ api ;
168+ }
169+ }
170+ $ out = <<<EOT
171+ # Behat Steps
172+
173+ WP-CLI makes use of a Behat-based testing framework and provides a set of custom step definitions to write feature tests.
174+
175+ *Behat steps documentation is generated from the WP-CLI codebase on every release. To suggest improvements, please submit a pull request.*
176+
177+ ***
178+
179+ EOT ;
180+
181+ self ::empty_dir ( WP_CLI_HANDBOOK_PATH . '/behat-steps/ ' );
182+
183+ foreach ( $ categories as $ name => $ apis ) {
184+ $ out .= '## ' . $ name . PHP_EOL . PHP_EOL ;
185+ $ out .= self ::render ( 'behat-steps-list.mustache ' , [ 'apis ' => $ apis ] );
186+ foreach ( $ apis as $ i => $ api ) {
187+ $ api ['category ' ] = $ name ;
188+ $ api ['related ' ] = $ apis ;
189+ $ api ['phpdoc ' ]['parameters ' ] = array_map (
190+ function ( $ parameter ) {
191+ foreach ( $ parameter as $ key => $ values ) {
192+ if ( isset ( $ values [2 ] ) ) {
193+ $ values [2 ] = str_replace ( array ( PHP_EOL ), array ( '<br /> ' ), $ values [2 ] );
194+ $ parameter [ $ key ] = $ values ;
195+ }
196+ }
197+ return $ parameter ;
198+ },
199+ $ api ['phpdoc ' ]['parameters ' ]
200+ );
201+ unset( $ api ['related ' ][ $ i ] );
202+ $ api ['related ' ] = array_values ( $ api ['related ' ] );
203+ $ api ['has_related ' ] = ! empty ( $ api ['related ' ] );
204+
205+ $ api_doc = self ::render ( 'behat-steps.mustache ' , $ api );
206+ $ path = WP_CLI_HANDBOOK_PATH . "/behat-steps/ {$ api ['api_slug ' ]}.md " ;
207+ if ( ! is_dir ( dirname ( $ path ) ) ) {
208+ mkdir ( dirname ( $ path ) );
209+ }
210+ file_put_contents ( $ path , $ api_doc );
211+ }
212+ $ out .= PHP_EOL . PHP_EOL ;
213+ }
214+
215+ file_put_contents ( WP_CLI_HANDBOOK_PATH . '/behat-steps.md ' , $ out );
216+ WP_CLI ::success ( 'Generated behat-steps/ ' );
217+ }
218+
139219 /**
140220 * Generates all command pages.
141221 *
@@ -176,7 +256,7 @@ public function gen_commands( $args, $assoc_args ) {
176256 $ verbose = Utils \get_flag_value ( $ assoc_args , 'verbose ' , false );
177257
178258 foreach ( $ wp ['subcommands ' ] as $ cmd ) {
179- if ( in_array ( $ cmd ['name ' ], [ 'website ' , 'api-dump ' , ' handbook ' ], true ) ) {
259+ if ( in_array ( $ cmd ['name ' ], [ 'website ' , 'handbook ' ], true ) ) {
180260 continue ;
181261 }
182262 self ::gen_cmd_pages ( $ cmd , [] /*parent*/ , $ verbose );
@@ -348,12 +428,7 @@ public function gen_hb_manifest() {
348428 WP_CLI ::success ( 'Generated bin/handbook-manifest.json ' );
349429 }
350430
351- /**
352- * Dumps internal API PHPDoc to JSON.
353- *
354- * @subcommand api-dump
355- */
356- public function api_dump () {
431+ private function get_internal_apis () {
357432 $ apis = [];
358433 $ functions = get_defined_functions ();
359434 foreach ( $ functions ['user ' ] as $ function ) {
@@ -364,11 +439,38 @@ public function api_dump() {
364439 }
365440 $ apis [] = self ::get_simple_representation ( $ reflection );
366441 }
442+
367443 $ classes = get_declared_classes ();
368444 foreach ( $ classes as $ class ) {
369445 if ( false === stripos ( $ class , 'WP_CLI ' ) ) {
370446 continue ;
371447 }
448+
449+ $ reflection = new \ReflectionClass ( $ class );
450+ foreach ( $ reflection ->getMethods () as $ method ) {
451+ $ method_reflection = new \ReflectionMethod ( $ method ->class , $ method ->name );
452+ $ phpdoc = $ method_reflection ->getDocComment ();
453+ if ( false === stripos ( $ phpdoc , '@access public ' ) ) {
454+ continue ;
455+ }
456+ $ apis [] = self ::get_simple_representation ( $ method_reflection );
457+ }
458+ }
459+
460+ return $ apis ;
461+ }
462+
463+ private function get_behat_steps () {
464+ $ apis = [];
465+ $ classes = [
466+ '\WP_CLI\Tests\Context\FeatureContext ' ,
467+ ];
468+
469+ foreach ( $ classes as $ class ) {
470+ if ( false === stripos ( $ class , 'WP_CLI ' ) ) {
471+ continue ;
472+ }
473+
372474 $ reflection = new \ReflectionClass ( $ class );
373475 foreach ( $ reflection ->getMethods () as $ method ) {
374476 $ method_reflection = new \ReflectionMethod ( $ method ->class , $ method ->name );
@@ -379,7 +481,8 @@ public function api_dump() {
379481 $ apis [] = self ::get_simple_representation ( $ method_reflection );
380482 }
381483 }
382- echo json_encode ( $ apis );
484+
485+ return $ apis ;
383486 }
384487
385488 private static function gen_cmd_pages ( $ cmd , $ parent = [], $ verbose = false ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.parentFound
@@ -569,7 +672,7 @@ private static function get_simple_representation( $reflection ) {
569672 } else {
570673 $ signature = $ signature . '() ' ;
571674 }
572- $ phpdoc = $ reflection ->getDocComment ();
675+ $ phpdoc = self :: parse_docblock ( $ reflection ->getDocComment () );
573676 $ type = strtolower ( str_replace ( 'Reflection ' , '' , get_class ( $ reflection ) ) );
574677 $ class = '' ;
575678 switch ( $ type ) {
@@ -584,8 +687,13 @@ private static function get_simple_representation( $reflection ) {
584687 $ full_name = $ reflection ->getName ();
585688 break ;
586689 }
690+
691+ if ( isset ( $ phpdoc ['behat_step ' ] ) ) {
692+ $ full_name = $ phpdoc ['behat_step ' ];
693+ }
694+
587695 return [
588- 'phpdoc ' => self :: parse_docblock ( $ phpdoc ) ,
696+ 'phpdoc ' => $ phpdoc ,
589697 'type ' => $ type ,
590698 'signature ' => $ signature ,
591699 'short_name ' => $ reflection ->getShortName (),
@@ -623,6 +731,11 @@ private static function parse_docblock( $docblock ) {
623731 preg_match ( '/@(\w+)/ ' , $ info , $ matches );
624732 $ param_name = $ matches [1 ];
625733 $ value = str_replace ( "@ $ param_name " , '' , $ info );
734+
735+ if ( in_array ( $ param_name , [ 'Given ' , 'Then ' , 'When ' ], true ) ) {
736+ $ ret ['behat_step ' ] = "$ param_name $ value " ;
737+ }
738+
626739 if ( ! isset ( $ ret ['parameters ' ][ $ param_name ] ) ) {
627740 $ ret ['parameters ' ][ $ param_name ] = [];
628741 }
0 commit comments