Skip to content

Commit 9ce3d1c

Browse files
committed
Feature: Add the ability to specify a file path for a comment header
New arguments are introduced: - `comment_header` - `text` - `path` - `class` - `type`
1 parent dc0dd90 commit 9ce3d1c

File tree

7 files changed

+172
-55
lines changed

7 files changed

+172
-55
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,11 @@ This parameter accepts an array holding options.
8383
- `exclude_substrings`: (array) sub-strings of paths to exclude from the list. e.g. `[ '.min', '_del', 'temp', 'library', 'vendor' ]`
8484
- `is_recursive`: (boolean) whether to scan sub-directories.
8585
- `ignore_note_file_names`: (array) ignore note file names that tell the parser to skip the directory. When one of the files exist in the parsing directory, the directory will be skipped. Default: `[ 'ignore-class-map.txt' ]`,
86-
86+
- `comment_header` : (array, optional) what header comment to insert at the top of the generated file
87+
- `text` : (string, optional) the header comment to set
88+
- `path` : (string, optional) the file path to extract the comment from
89+
- `class` : (string, optional) the class name to use its doc-block as the header comment
90+
- `type` : (string, optional) indicates what type of data to collect. Accepted values are `DOCBLOCK`, `CONSTANT`.
8791
##### Example
8892

8993
##### Generating a class map in the script directory.

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Change Log
22

33
## 1.3.0 - 2022/02/22
4+
- Added the ability to specify a comment header of a specified file.
45

56
## 1.2.2 - 2022/02/17
67
- Fixed a bug that caused an undefined index notice when the `header_class_name` argument was set.

source/Header/HeaderGenerator.php

Lines changed: 74 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,18 @@ class HeaderGenerator {
99
use traitCodeParser;
1010

1111
public $aItems = [];
12-
public $aOptions = [];
12+
public $aOptions = [
13+
'text' => null, // the direct comment content text
14+
'class' => null, // the class name tha has the header comment
15+
'type' => null, // the type of header comment to extract, accepts `DOCBLOCK`, `CONSTANTS`, `COMMENT`
16+
'path' => null, // the file path where the header comment to extract from
17+
'wrap' => true, // whether to enclose the comment in the PHP multi-line comment syntax /* */.
18+
19+
// legacy options
20+
'header_class_name' => null,
21+
'header_class_path' => null,
22+
'header_type' => null,
23+
];
1324

1425
/**
1526
* HeaderGenerator constructor.
@@ -18,17 +29,42 @@ class HeaderGenerator {
1829
*/
1930
public function __construct( array $aItems, array $aOptions ) {
2031
$this->aItems = $aItems;
21-
$this->aOptions = $aOptions;
32+
$this->aOptions = $this->___getOptionsFormatted( $aOptions );
2233
}
34+
private function ___getOptionsFormatted( array $aOptions ) {
35+
$_aOptions = $aOptions + $this->aOptions;
36+
// Backward-compatibility
37+
$_aLegacyArgumentsToConvert = [
38+
'header_class_path' => 'path',
39+
'header_class_name' => 'class',
40+
'header_type' => 'type',
41+
];
42+
foreach( $_aLegacyArgumentsToConvert as $_sLegacyKey => $_sCurrentVersionKey ) {
43+
if ( ! empty( $_aOptions[ $_sLegacyKey ] ) && empty( $_aOptions[ $_sCurrentVersionKey ] ) ) {
44+
$_aOptions[ $_sCurrentVersionKey ] = $_aOptions[ $_sLegacyKey ];
45+
}
46+
}
47+
return $_aOptions;
48+
}
2349

2450
/**
2551
*
2652
* @return string
2753
* @throws \ReflectionException
2854
*/
2955
public function get() {
30-
return $this->___getProjectHeaderComment( $this->aItems, $this->aOptions );
56+
57+
if ( ! empty( $this->aOptions[ 'text' ] ) ) {
58+
return $this->aOptions[ 'wrap' ]
59+
? $this->getMultilineCommentWrapped( $this->aOptions[ 'text' ] )
60+
: $this->aOptions[ 'text' ];
61+
}
62+
63+
$_sMultilineComment = $this->___getProjectHeaderComment( $this->aItems, $this->aOptions );
64+
return $this->aOptions[ 'wrap' ] ? $_sMultilineComment : $this->getMultiLineCommentUnwrapped( $_sMultilineComment );
65+
3166
}
67+
3268
/**
3369
* Generates the heading comment from the given path or class name.
3470
* @param array $aItems
@@ -38,36 +74,42 @@ public function get() {
3874
*/
3975
private function ___getProjectHeaderComment( array $aItems, array $aOptions ) {
4076

41-
if ( $aOptions[ 'header_class_path' ] && $aOptions[ 'header_class_name' ] ) {
77+
// A pass and a class name is given
78+
if ( ! empty( $aOptions[ 'path' ] ) && ! empty( $aOptions[ 'class' ] ) ) {
79+
return $this->___getProjectHeaderCommentGenerated($aOptions[ 'path' ], $aOptions[ 'class' ], $aOptions[ 'type' ]);
80+
}
81+
// A class name is given
82+
if ( ! empty( $aOptions[ 'class' ] ) ) {
4283
return $this->___getProjectHeaderCommentGenerated(
43-
$aOptions[ 'header_class_path' ],
44-
$aOptions[ 'header_class_name' ],
45-
$aOptions[ 'header_type' ]
84+
isset( $aItems[ $aOptions[ 'class' ] ] )
85+
? $aItems[ $aOptions[ 'class' ] ][ 'path' ]
86+
: $aOptions[ 'path' ],
87+
$aOptions[ 'class' ],
88+
$aOptions[ 'type' ]
4689
);
4790
}
4891

49-
if ( $aOptions[ 'header_class_name' ] ) {
50-
return $this->___getProjectHeaderCommentGenerated(
51-
isset( $aItems[ $aOptions[ 'header_class_name' ] ] )
52-
? $aItems[ $aOptions['header_class_name'] ][ 'path' ]
53-
: $aOptions[ 'header_class_path' ],
54-
$aOptions[ 'header_class_name' ],
55-
$aOptions[ 'header_type' ]
56-
);
92+
if ( empty( $aOptions[ 'path' ] ) ) {
93+
return '';
5794
}
5895

59-
if ( $aOptions[ 'header_class_path' ] ) {
60-
$_aConstructs = $this->_getDefinedObjectConstructs( '<?php ' . $this->_getPHPCode( $aOptions[ 'header_class_path' ] ) );
61-
$_aDefinedClasses = $_aConstructs[ 'classes' ];
62-
$_sHeaderClassName = isset( $_aDefinedClasses[ 0 ] ) ? $_aDefinedClasses[ 0 ] : '';
63-
return $this->___getProjectHeaderCommentGenerated(
64-
$aOptions[ 'header_class_path' ],
65-
$_sHeaderClassName,
66-
$aOptions[ 'header_type' ]
67-
);
96+
// A pass is given.
97+
98+
/// Get first found comment block from a file.
99+
$_sCommentBlock = $this->getFirstFoundMultilineComment( file_get_contents( $aOptions[ 'path' ] ) );
100+
if ( ! empty( $_sCommentBlock ) ) {
101+
return $_sCommentBlock;
68102
}
69103

70-
return '';
104+
/// Extract a comment block from a fist found class doc-block.
105+
$_aConstructs = $this->_getDefinedObjectConstructs( '<?php ' . $this->_getPHPCode( $aOptions[ 'path' ] ) );
106+
$_aDefinedClasses = $_aConstructs[ 'classes' ];
107+
$_sHeaderClassName = isset( $_aDefinedClasses[ 0 ] ) ? $_aDefinedClasses[ 0 ] : '';
108+
return $this->___getProjectHeaderCommentGenerated(
109+
$aOptions[ 'path' ],
110+
$_sHeaderClassName,
111+
$aOptions[ 'type' ]
112+
);
71113

72114
}
73115
/**
@@ -95,7 +137,7 @@ private function ___getProjectHeaderCommentGenerated( $sFilePath, $sClassName, $
95137
}
96138
return 'DOCBLOCK' === $sHeaderType
97139
? $this->_getClassDocBlock( $_sClassName )
98-
: $this->___generateHeaderComment( $_sClassName );
140+
: $this->getMultilineCommentWrapped( $this->___generateHeaderComment( $_sClassName ) );
99141
}
100142
return '';
101143

@@ -117,16 +159,15 @@ private function ___generateHeaderComment( $sClassName ) {
117159
'COPYRIGHT' => '', 'LICENSE' => '', 'CONTRIBUTORS' => '',
118160
];
119161
$_aOutputs = [];
120-
$_aOutputs[] = '/**';
121-
$_aOutputs[] = ( $_aConstants[ 'NAME' ] ? " " . $_aConstants[ 'NAME' ] . ' ' : '' )
162+
$_aOutputs[] = ( $_aConstants[ 'NAME' ] ? $_aConstants[ 'NAME' ] . ' ' : '' )
122163
. ( $_aConstants[ 'VERSION' ] ? 'v' . $_aConstants[ 'VERSION' ] . ' ' : '' )
123164
. ( $_aConstants[ 'AUTHOR' ] ? 'by ' . $_aConstants[ 'AUTHOR' ] . ' ' : '' );
124-
$_aOutputs[] = $_aConstants[ 'DESCRIPTION' ] ? " ". $_aConstants[ 'DESCRIPTION' ] : '';
125-
$_aOutputs[] = $_aConstants[ 'URI' ] ? " ". '<' . $_aConstants[ 'URI' ] . '>' : '';
126-
$_aOutputs[] = ( $_aConstants[ 'COPYRIGHT' ] ? " " . $_aConstants[ 'COPYRIGHT' ] : '' )
165+
$_aOutputs[] = $_aConstants[ 'DESCRIPTION' ] ? $_aConstants[ 'DESCRIPTION' ] : '';
166+
$_aOutputs[] = $_aConstants[ 'URI' ] ? '<' . $_aConstants[ 'URI' ] . '>' : '';
167+
$_aOutputs[] = ( $_aConstants[ 'COPYRIGHT' ] ? $_aConstants[ 'COPYRIGHT' ] : '' )
127168
. ( $_aConstants[ 'LICENSE' ] ? '; Licensed under ' . $_aConstants[ 'LICENSE' ] : '' );
128-
$_aOutputs[] = ' */';
129-
return implode( PHP_EOL, array_filter( $_aOutputs ) ) . PHP_EOL;
169+
return implode( PHP_EOL, array_filter( $_aOutputs ) );
170+
130171
}
131172

132173
}

source/PHPClassMapGenerator.php

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
<?php
22
/**
3-
* Helps to generate class maps.
4-
*
5-
* @author Michael Uno <michael@michaeluno.jp>
6-
* @copyright 2020- (c) Michael Uno
7-
* @license MIT <http://opensource.org/licenses/MIT>
3+
* PHP Class Map Generator
4+
*
5+
* Helps generate class maps of PHP files. The feature includes generating path lists of specified file types.
6+
*
7+
* @url https://github.com/michaeluno/php-classmap-generator
8+
* @author Michael Uno <michael@michaeluno.jp>
9+
* @copyright 2020- (c) Michael Uno
10+
* @license MIT <http://opensource.org/licenses/MIT>
11+
* @version 1.3.0
812
*/
913

1014
namespace PHPClassMapGenerator;
@@ -16,8 +20,7 @@
1620
*
1721
* This is meant to be used for the callback function for the spl_autoload_register() function.
1822
*
19-
* @remark The parsed class file must have a name of the class defined in the file.
20-
* @version 1.2.2
23+
* @remark The parsed class file must have a name of the class defined in the file.
2124
*/
2225
class PHPClassMapGenerator implements interfacePHPClassMapGenerator {
2326

@@ -126,7 +129,18 @@ public function __construct( $sBaseDirPath, $asScanDirPaths, $sOutputFilePath, a
126129
'ignore_note_file_names' => ['ignore-class-map.txt'] // 1.1.0 When this option is present and the parsing directory contains a file matching one of the set names, the directory will be skipped.
127130
],
128131

129-
);
132+
// Comment header
133+
'comment_header' => [
134+
'text' => '', // the direct comment content text
135+
'class' => '', // the class name tha has the header comment
136+
'type' => 'DOCBLOCK', // the type of header comment to extract, accepts `DOCBLOCK`, `CONSTANT`, `COMMENT`
137+
'path' => '', // the file path where the header comment to extract from
138+
],
139+
// legacy @deprecated 1.3.0
140+
'header_class_name' => null,
141+
'header_class_path' => null,
142+
'header_type' => null,
143+
];
130144

131145
/**
132146
*
@@ -151,7 +165,7 @@ public function getMap() {
151165
$_sOpening = $this->aOptions[ 'short_array_syntax' ] ? '[' : 'array(';
152166
$_sClosing = $this->aOptions[ 'short_array_syntax' ] ? ']' : ')';
153167
$_aData = array(
154-
mb_convert_encoding( '<?php ' . PHP_EOL . $this->sHeaderComment, 'UTF-8', 'auto' ),
168+
mb_convert_encoding( '<?php ' . PHP_EOL . trim( $this->sHeaderComment ) . PHP_EOL, 'UTF-8', 'auto' ),
155169
'return' === $this->aOptions[ 'output_var_name' ]
156170
? "return {$_sOpening}" . PHP_EOL
157171
: $this->aOptions[ 'output_var_name' ] . " = {$_sOpening} " . PHP_EOL,
@@ -250,8 +264,6 @@ private function ___getFileArrayFormatted( array $aFilePaths ) {
250264

251265
}
252266

253-
254-
255267
/**
256268
* @param string $sBaseDirPath
257269
* @param array|string $asScanDirPaths
@@ -274,8 +286,25 @@ protected function _setProperties( $sBaseDirPath, $asScanDirPaths, $sOutputFileP
274286
* @since 1.1.0
275287
*/
276288
private function ___getOptionsFormatted( array $aOptions ) {
289+
277290
$aOptions = $aOptions + self::$_aStructure_Options;
278291
$aOptions[ 'search' ] = $aOptions[ 'search' ] + self::$_aStructure_Options[ 'search' ];
292+
293+
// Backward compat
294+
/// Handle header comment arguments
295+
$_aLegacyKeys = [
296+
'header_class_name' => 'class',
297+
'header_class_path' => 'path',
298+
'header_type' => 'type',
299+
];
300+
foreach( $_aLegacyKeys as $_sLegacyKey => $_sNewKey ) {
301+
if ( empty( $aOptions[ $_sLegacyKey ] ) ) {
302+
continue;
303+
}
304+
$aOptions[ 'comment_header' ][ $_sNewKey ] = $aOptions[ $_sLegacyKey ];
305+
unset( $aOptions[ $_sLegacyKey ] );
306+
}
307+
279308
return $aOptions;
280309
}
281310
/**
@@ -294,7 +323,7 @@ private function ___setItems() {
294323
}
295324
private function ___setProjectHeaderComment() {
296325
try {
297-
$_oHeaderGenerator = new HeaderGenerator( $this->aItems, $this->aOptions );
326+
$_oHeaderGenerator = new HeaderGenerator( $this->aItems, $this->aOptions[ 'comment_header' ] );
298327
$this->sHeaderComment = $_oHeaderGenerator->get();
299328
if ( ! $this->sHeaderComment ) {
300329
throw new \ReflectionException( 'No header comment generated.' );

source/Utility/traitCodeParser.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,45 @@
66

77
trait traitCodeParser {
88

9+
/**
10+
* @param $sCode
11+
* @return string
12+
* @since 1.3.0
13+
*/
14+
static public function getFirstFoundMultilineComment( $sCode ) {
15+
preg_match( '/\/\*+?(.*)\*\//Us', $sCode, $_aMatches );
16+
return isset( $_aMatches[ 0 ] ) ? ( string ) $_aMatches[ 0 ] : '';
17+
}
18+
19+
/**
20+
* @param string $sMultiLineComment
21+
* @return string
22+
* @since 1.3.0
23+
*/
24+
static public function getMultiLineCommentUnwrapped( $sMultiLineComment ) {
25+
$_sText = '';
26+
preg_match( '/\/\*+?(.*)\*\//Us', $sMultiLineComment, $_aMatches );
27+
foreach( preg_split("/\r\n|\n|\r/", trim( $_aMatches[ 1 ], '\t\n\r\0\x0B' ) ) as $_i => $_sLine ) {
28+
$_sText .= preg_replace( '/^(\s|\/)+\*+(\s|$)/', '', $_sLine ) . PHP_EOL;
29+
}
30+
return trim( $_sText );
31+
}
32+
33+
/**
34+
* @param string $sMultilineComment
35+
* @param string $sBlockNotation The first character set to mark the type of block. /** indicates a PHP doc-block. /*! is an important comment not to minify in JavaScript.
36+
* @return string
37+
* @since 1.3.0
38+
*/
39+
static public function getMultilineCommentWrapped( $sMultilineComment, $sBlockNotation='*' ) {
40+
$_sComment = '/*' . $sBlockNotation . PHP_EOL;
41+
foreach( preg_split("/\r\n|\n|\r/", $sMultilineComment ) as $_i => $_sLine ) {
42+
$_sComment .= ' * ' . $_sLine . PHP_EOL;
43+
}
44+
$_sComment .= ' */' . PHP_EOL;
45+
return $_sComment;
46+
}
47+
948
/**
1049
* Returns the docblock of the specified class
1150
* @param string $sClassName

source/class-map.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
<?php
22
/**
3-
PHP Class Map Generator v1.1.1 by Michael Uno
4-
Generates PHP class maps for auto-load.
5-
<https://en.michaeluno.jp>
6-
Michael Uno <2020>; Licensed under MIT
3+
* Helps generate class maps of PHP files.
4+
*
5+
* The feature includes generating path lists of specified file types.
6+
*
7+
* @author Michael Uno <michael@michaeluno.jp>
8+
* @copyright 2020- (c) Michael Uno
9+
* @license MIT <http://opensource.org/licenses/MIT>
10+
* @version 1.3.0
711
*/
812
return array(
913
"PHPClassMapGenerator\\PHPClassMapGenerator" => __DIR__ . "/PHPClassMapGenerator.php",

test/generate-map-this-project-class.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,19 @@
22

33
include( dirname( __DIR__ ) . '/source/autoload.php' );
44

5-
65
new \PHPClassMapGenerator\PHPClassMapGenerator(
76
dirname( __DIR__ ) . '/source', // base dir
87
dirname( __DIR__ ) . '/source', // scan dir name
98
dirname( __DIR__ ) . '/source/class-map.php',
109
[
11-
12-
'header_class_path' => __DIR__ . '/ProjectHeader.php',
13-
'header_type' => 'CONSTANT', // or 'CONSTANT
1410
'exclude_classes' => [ 'ProjectHeader' ],
1511
'base_dir_var' => '__DIR__',
1612
'output_var_name' => 'return',
1713
'search' => [
1814
'exclude_dir_names' => [ 'test' ],
19-
]
15+
],
16+
'comment_header' => [
17+
'path' => dirname( __DIR__ ) . '/source/PHPClassMapGenerator.php',
18+
],
2019
]
2120
);

0 commit comments

Comments
 (0)