Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
59 / 59 |
|
100.00% |
9 / 9 |
CRAP | |
100.00% |
1 / 1 |
BasicGenerationHelper | |
100.00% |
59 / 59 |
|
100.00% |
9 / 9 |
21 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
return | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
addVisibility | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
1 | |||
createDocComment | |
100.00% |
14 / 14 |
|
100.00% |
1 / 1 |
6 | |||
createArguments | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
createArray | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
convertToAstNode | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
2 | |||
isValidDefault | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
1 | |||
generateFile | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
3 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace quintenmbusiness\PhpAstCodeGenerationHelper\GeneratorHelpers; |
6 | |
7 | use PhpParser\Builder\Namespace_; |
8 | use PhpParser\Node\Arg; |
9 | use PhpParser\Node\Expr; |
10 | use PhpParser\Builder\Method; |
11 | use PhpParser\BuilderFactory; |
12 | use PhpParser\Builder\Property; |
13 | use PhpParser\Node\Expr\Array_; |
14 | use PhpParser\Node\Expr\ArrayItem; |
15 | use PhpParser\Node\Expr\Cast\Bool_; |
16 | use PhpParser\Node\Expr\ConstFetch; |
17 | use PhpParser\Node\Expr\Variable; |
18 | use PhpParser\Node\Name; |
19 | use PhpParser\Node\Scalar\String_; |
20 | use PhpParser\Node\Scalar\LNumber; |
21 | use PhpParser\Node\Stmt\Return_; |
22 | use PhpParser\Builder\Class_; |
23 | use PhpParser\Builder\Interface_; |
24 | use PhpParser\PrettyPrinter\Standard; |
25 | |
26 | class BasicGenerationHelper |
27 | { |
28 | /** |
29 | * @var BuilderFactory |
30 | */ |
31 | public BuilderFactory $factory; |
32 | |
33 | /** |
34 | * @param BuilderFactory $factory |
35 | */ |
36 | public function __construct(BuilderFactory $factory) |
37 | { |
38 | $this->factory = $factory; |
39 | } |
40 | |
41 | /** |
42 | * Creates a return statement using a passed Expr |
43 | * |
44 | * @param Expr $expr |
45 | * @return Return_ |
46 | */ |
47 | public function return(Expr $expr): Return_ |
48 | { |
49 | return new Return_($expr); |
50 | } |
51 | |
52 | /** |
53 | * @param Method|Property $stmt |
54 | * @param string $visibility |
55 | * @return Method|Property |
56 | */ |
57 | public function addVisibility(Method|Property $stmt, string $visibility = 'public'): Method|Property |
58 | { |
59 | match ($visibility) { |
60 | 'public' => $stmt->makePublic(), |
61 | 'protected' => $stmt->makeProtected(), |
62 | 'private' => $stmt->makePrivate(), |
63 | 'static' => $stmt->makeStatic(), |
64 | 'abstract' => $stmt->makeAbstract(), |
65 | 'final' => $stmt->makeFinal(), |
66 | default => $stmt, |
67 | }; |
68 | |
69 | return $stmt; |
70 | } |
71 | |
72 | /** |
73 | * Adds a PHPDoc comment to the given Method or Property. |
74 | * |
75 | * @param Method|Property $method |
76 | * @param array<int, array<string, string>> $params Array of parameters, where each element has 'type' and 'name'. |
77 | * @param null|string $returnType The return type to document. |
78 | * @param null|string $throws The exception type to document in @throws. |
79 | * @param null|string $deprecated Marks the method/property as deprecated with an optional message. |
80 | * @param array<string, string> $additional Additional tags, where the key is the tag (e.g., 'author') and the value is the tag's content. |
81 | * @return Method|Property |
82 | */ |
83 | public function createDocComment( |
84 | Method|Property $method, |
85 | array $params = [], |
86 | ?string $returnType = null, |
87 | ?string $throws = null, |
88 | ?string $deprecated = null, |
89 | array $additional = [] |
90 | ): Method|Property { |
91 | $comment = "\n" . '/**'; |
92 | |
93 | // Add @param tags |
94 | foreach ($params as $param) { |
95 | $comment .= "\n" . ' * @param ' . $param['type'] . ' $' . $param['name']; |
96 | } |
97 | |
98 | // Add @return tag |
99 | if (!empty($returnType)) { |
100 | $comment .= "\n * \n" . ' * @return ' . $returnType; |
101 | } |
102 | |
103 | // Add @throws tag |
104 | if (!empty($throws)) { |
105 | $comment .= "\n" . ' * @throws ' . $throws; |
106 | } |
107 | |
108 | // Add @deprecated tag |
109 | if (!empty($deprecated)) { |
110 | $comment .= "\n" . ' * @deprecated ' . $deprecated; |
111 | } |
112 | |
113 | // Add any additional tags |
114 | foreach ($additional as $tag => $content) { |
115 | $comment .= "\n" . ' * @' . $tag . ' ' . $content; |
116 | } |
117 | |
118 | $comment .= "\n" . ' */'; |
119 | |
120 | $method->setDocComment($comment); |
121 | |
122 | return $method; |
123 | } |
124 | |
125 | /** |
126 | * Creates an array of arguments for a method call. |
127 | * |
128 | * @param array<int|string, mixed> $args |
129 | * @return array<int, Arg> |
130 | */ |
131 | public function createArguments(array $args): array |
132 | { |
133 | $arguments = []; |
134 | foreach ($args as $value) { |
135 | $arguments[] = new Arg($value instanceof Expr ? $value : $this->convertToAstNode($value)); |
136 | } |
137 | return $arguments; |
138 | } |
139 | |
140 | /** |
141 | * Creates an array node from a PHP array. |
142 | * |
143 | * @param array<int|string, mixed> $items |
144 | * @return Expr\Array_ |
145 | */ |
146 | public function createArray(array $items): Array_ |
147 | { |
148 | $arrayItems = []; |
149 | foreach ($items as $key => $value) { |
150 | $keyNode = is_int($key) ? null : $this->convertToAstNode($key); |
151 | $arrayItems[] = new ArrayItem($this->convertToAstNode($value), $keyNode); |
152 | } |
153 | |
154 | return new Array_($arrayItems); |
155 | } |
156 | |
157 | /** |
158 | * Converts a PHP value to an AST node. |
159 | * |
160 | * @param mixed $value |
161 | * @return Array_|LNumber|String_|ConstFetch|Variable |
162 | * @throws \InvalidArgumentException |
163 | */ |
164 | public function convertToAstNode(mixed $value): Array_|LNumber|String_|ConstFetch|Variable |
165 | { |
166 | return match (true) { |
167 | is_int($value) => new LNumber($value), |
168 | is_string($value) => new String_($value), |
169 | is_array($value) => $this->createArray($value), |
170 | is_bool($value) => new ConstFetch(new Name($value ? 'true' : 'false')), |
171 | $value instanceof Variable => $value, |
172 | $value === null => new ConstFetch(new Name('null')), // Handle null as ConstFetch |
173 | default => throw new \InvalidArgumentException('Unsupported value type for AST conversion: ' . gettype($value)), |
174 | }; |
175 | } |
176 | |
177 | /** |
178 | * @param string|null $type |
179 | * @param mixed $default |
180 | * @return bool |
181 | */ |
182 | public function isValidDefault(?string $type, mixed $default): bool |
183 | { |
184 | return match ($type) { |
185 | 'int' => is_int($default), |
186 | 'string' => is_string($default), |
187 | 'bool' => is_bool($default), |
188 | 'float' => is_float($default), |
189 | 'array' => is_array($default), |
190 | default => false, |
191 | }; |
192 | } |
193 | |
194 | /** |
195 | * Generates a PHP file for a given class, interface, or namespace. |
196 | * |
197 | * @param Class_|Interface_|Namespace_ $definition The class, interface, or namespace to generate. |
198 | * @param string|null $namespace The namespace of the class/interface (if $definition is not already a Namespace_). |
199 | * @param string $outputPath The file path where the generated file should be saved. |
200 | * @return void |
201 | */ |
202 | public function generateFile(Class_|Interface_|Namespace_ $definition, ?string $namespace, string $outputPath): void |
203 | { |
204 | $prettyPrinter = new Standard(); |
205 | |
206 | // Convert builder to node if necessary |
207 | $node = $definition instanceof Namespace_ |
208 | ? $definition->getNode() |
209 | : $this->factory->namespace($namespace)->addStmt($definition)->getNode(); |
210 | |
211 | // Generate the PHP code |
212 | $code = $prettyPrinter->prettyPrintFile([$node]); |
213 | |
214 | // Ensure the directory exists |
215 | $directory = dirname($outputPath); |
216 | if (!is_dir($directory)) { |
217 | mkdir($directory, 0755, true); |
218 | } |
219 | |
220 | // Save the generated code to the file |
221 | file_put_contents($outputPath, $code); |
222 | } |
223 | } |