Skip to content

Commit b577efd

Browse files
committed
Add support for doc block comments for properties and methods - Close #9
1 parent 6cde304 commit b577efd

File tree

7 files changed

+399
-6
lines changed

7 files changed

+399
-6
lines changed

src/Code/MethodGenerator.php

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
namespace OpenCodeModeling\CodeAst\Code;
1212

1313
use OpenCodeModeling\CodeAst\Exception;
14+
use PhpParser\Comment\Doc;
1415
use PhpParser\Node\Stmt\ClassMethod;
1516

1617
/**
@@ -38,6 +39,16 @@ final class MethodGenerator extends AbstractMemberGenerator
3839
*/
3940
private $returnType;
4041

42+
/**
43+
* @var bool
44+
*/
45+
private $typed = false;
46+
47+
/**
48+
* @var string|null
49+
*/
50+
private $docBlockComment;
51+
4152
/**
4253
* @param string $name
4354
* @param array $parameters
@@ -143,9 +154,70 @@ public function getReturnType(): ?TypeGenerator
143154
return $this->returnType;
144155
}
145156

157+
public function docBlockComment(): ?string
158+
{
159+
return $this->docBlockComment;
160+
}
161+
162+
public function setDocBlockComment(?string $docBlockComment): void
163+
{
164+
$this->docBlockComment = $docBlockComment;
165+
}
166+
167+
/**
168+
* @return bool
169+
*/
170+
public function typed(): bool
171+
{
172+
return $this->typed;
173+
}
174+
175+
/**
176+
* @param bool $typed
177+
*/
178+
public function setTyped(bool $typed): void
179+
{
180+
$this->typed = $typed;
181+
}
182+
146183
public function generate(): ClassMethod
147184
{
148-
return new ClassMethod($this->getName(),
185+
$docBlockTypes = [];
186+
187+
foreach ($this->getParameters() as $parameter) {
188+
$type = $parameter->getType()->isNullable()
189+
? $parameter->getType()->type() . '|null'
190+
: $parameter->getType()->type();
191+
192+
if ($typeHint = $parameter->getTypeDocBlockHint()) {
193+
$type = $typeHint;
194+
}
195+
196+
$docBlockTypes[] = '@var ' . $type . ' $' . $parameter->getName();
197+
}
198+
199+
$methodComment = "/**\n";
200+
201+
if ($this->docBlockComment) {
202+
$multiLineDocBlockComment = \trim(\preg_replace("/\n/", "\n * ", $this->docBlockComment));
203+
204+
$methodComment .= " * {$multiLineDocBlockComment}\n *";
205+
}
206+
207+
foreach ($docBlockTypes as $docBlockType) {
208+
$methodComment .= "\n * " . $docBlockType;
209+
}
210+
211+
$methodComment = \preg_replace("/ \* \n/", " *\n", $methodComment) . "\n */";
212+
213+
$attributes = [];
214+
215+
if ($this->typed === false || $this->docBlockComment) {
216+
$attributes = ['comments' => [new Doc($methodComment)]];
217+
}
218+
219+
return new ClassMethod(
220+
$this->getName(),
149221
[
150222
'flags' => $this->flags,
151223
'params' => \array_map(
@@ -156,7 +228,8 @@ static function (ParameterGenerator $parameter) {
156228
),
157229
'stmts' => $this->body ? $this->body->generate() : null,
158230
'returnType' => $this->returnType ? $this->returnType->generate() : null,
159-
]
231+
],
232+
$attributes
160233
);
161234
}
162235

src/Code/ParameterGenerator.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ final class ParameterGenerator
4747
*/
4848
private $variadic = false;
4949

50+
/**
51+
* @var string
52+
*/
53+
private $typeDocBlockHint;
54+
5055
/**
5156
* @param string $name
5257
* @param string|null $type
@@ -172,6 +177,22 @@ public function getVariadic(): bool
172177
return $this->variadic;
173178
}
174179

180+
/**
181+
* @return string
182+
*/
183+
public function getTypeDocBlockHint(): ?string
184+
{
185+
return $this->typeDocBlockHint;
186+
}
187+
188+
/**
189+
* @param string $typeDocBlockHint
190+
*/
191+
public function setTypeDocBlockHint(string $typeDocBlockHint): void
192+
{
193+
$this->typeDocBlockHint = $typeDocBlockHint;
194+
}
195+
175196
public function generate(): Node\Param
176197
{
177198
return new Node\Param(

src/Code/PropertyGenerator.php

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,17 @@ final class PropertyGenerator extends AbstractMemberGenerator
3737
/**
3838
* @var bool
3939
*/
40-
private $typed = false;
40+
private $typed;
41+
42+
/**
43+
* @var string|null
44+
*/
45+
private $docBlockComment;
46+
47+
/**
48+
* @var string
49+
*/
50+
private $typeDocBlockHint;
4151

4252
public function __construct(
4353
string $name = null,
@@ -77,6 +87,16 @@ public function getType(): TypeGenerator
7787
return $this->type;
7888
}
7989

90+
public function docBlockComment(): ?string
91+
{
92+
return $this->docBlockComment;
93+
}
94+
95+
public function setDocBlockComment(?string $docBlockComment): void
96+
{
97+
$this->docBlockComment = $docBlockComment;
98+
}
99+
80100
/**
81101
* @param ValueGenerator|mixed $defaultValue
82102
* @param string $defaultValueType
@@ -104,20 +124,52 @@ public function getDefaultValue(): ValueGenerator
104124
return $this->defaultValue;
105125
}
106126

127+
/**
128+
* @return string
129+
*/
130+
public function getTypeDocBlockHint(): ?string
131+
{
132+
return $this->typeDocBlockHint;
133+
}
134+
135+
/**
136+
* @param string $typeDocBlockHint
137+
*/
138+
public function setTypeDocBlockHint(string $typeDocBlockHint): void
139+
{
140+
$this->typeDocBlockHint = $typeDocBlockHint;
141+
}
142+
107143
public function generate(): Property
108144
{
109145
$docBlockType = $this->type->isNullable()
110-
? $this->type->type()
111-
: $this->type->type() . '|null';
146+
? $this->type->type() . '|null'
147+
: $this->type->type();
148+
149+
if ($typeHint = $this->getTypeDocBlockHint()) {
150+
$docBlockType = $typeHint;
151+
}
112152

113153
$propComment = <<<EOF
114154
/**
115155
* @var {$docBlockType}
116156
*/
117157
EOF;
158+
if ($this->docBlockComment) {
159+
$multiLineDocBlockComment = \trim(\preg_replace("/\n/", "\n * ", $this->docBlockComment));
160+
161+
$propComment = <<<EOF
162+
/**
163+
* {$multiLineDocBlockComment}
164+
*
165+
* @var {$docBlockType}
166+
*/
167+
EOF;
168+
}
169+
118170
$attributes = [];
119171

120-
if ($this->typed === false) {
172+
if ($this->typed === false || $this->docBlockComment) {
121173
$attributes = ['comments' => [new Doc($propComment)]];
122174
}
123175

tests/Code/MethodGeneratorTest.php

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenCodeModelingTest\CodeAst\Code;
6+
7+
use OpenCodeModeling\CodeAst\Code\MethodGenerator;
8+
use OpenCodeModeling\CodeAst\Code\ParameterGenerator;
9+
use PhpParser\Parser;
10+
use PhpParser\ParserFactory;
11+
use PhpParser\PrettyPrinter\Standard;
12+
use PHPUnit\Framework\TestCase;
13+
14+
final class MethodGeneratorTest extends TestCase
15+
{
16+
/**
17+
* @var Parser
18+
*/
19+
private $parser;
20+
21+
/**
22+
* @var Standard
23+
*/
24+
private $printer;
25+
26+
public function setUp(): void
27+
{
28+
$this->parser = (new ParserFactory())->create(ParserFactory::ONLY_PHP7);
29+
$this->printer = new Standard(['shortArraySyntax' => true]);
30+
}
31+
32+
/**
33+
* @test
34+
*/
35+
public function it_generates_method_with_doc_block(): void
36+
{
37+
$method = new MethodGenerator(
38+
'setType',
39+
[
40+
new ParameterGenerator('type', '?string'),
41+
]
42+
);
43+
$method->setDocBlockComment('Sets an awesome type');
44+
45+
$expectedOutput = <<<'EOF'
46+
<?php
47+
48+
/**
49+
* Sets an awesome type
50+
*
51+
* @var string|null $type
52+
*/
53+
public function setType(?string $type);
54+
EOF;
55+
56+
$this->assertSame($expectedOutput, $this->printer->prettyPrintFile([$method->generate()]));
57+
}
58+
59+
/**
60+
* @test
61+
*/
62+
public function it_generates_method_with_array_type_doc_block(): void
63+
{
64+
$parameter = new ParameterGenerator('items', 'array');
65+
$parameter->setTypeDocBlockHint('array<string, \stdClass>');
66+
67+
$method = new MethodGenerator(
68+
'setItems',
69+
[
70+
$parameter,
71+
]
72+
);
73+
$method->setDocBlockComment('Sets awesome items');
74+
75+
$expectedOutput = <<<'EOF'
76+
<?php
77+
78+
/**
79+
* Sets awesome items
80+
*
81+
* @var array<string, \stdClass> $items
82+
*/
83+
public function setItems(array $items);
84+
EOF;
85+
86+
$this->assertSame($expectedOutput, $this->printer->prettyPrintFile([$method->generate()]));
87+
}
88+
89+
/**
90+
* @test
91+
*/
92+
public function it_generates_method_with_long_doc_block(): void
93+
{
94+
$docBlockComment = <<<'EOF'
95+
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's
96+
standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a
97+
type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting,
98+
remaining essentially unchanged.
99+
100+
It is a long established fact that a reader will be distracted by the readable content of a page when looking at
101+
its layout.
102+
EOF;
103+
104+
105+
$method = new MethodGenerator(
106+
'setType',
107+
[
108+
new ParameterGenerator('type', 'string'),
109+
new ParameterGenerator('value', '?int'),
110+
]
111+
);
112+
$method->setDocBlockComment($docBlockComment);
113+
114+
$expectedOutput = <<<'EOF'
115+
<?php
116+
117+
/**
118+
* Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's
119+
* standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a
120+
* type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting,
121+
* remaining essentially unchanged.
122+
*
123+
* It is a long established fact that a reader will be distracted by the readable content of a page when looking at
124+
* its layout.
125+
*
126+
* @var string $type
127+
* @var int|null $value
128+
*/
129+
public function setType(string $type, ?int $value);
130+
EOF;
131+
132+
$this->assertSame($expectedOutput, $this->printer->prettyPrintFile([$method->generate()]));
133+
}
134+
}

0 commit comments

Comments
 (0)