Skip to content

Commit f753099

Browse files
committed
Generate code from file collection with current file AST support - Close #66
1 parent 0152269 commit f753099

File tree

2 files changed

+486
-0
lines changed

2 files changed

+486
-0
lines changed

src/FileCodeGenerator.php

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
<?php
2+
3+
/**
4+
* @see https://github.com/open-code-modeling/php-code-ast for the canonical source repository
5+
* @copyright https://github.com/open-code-modeling/php-code-ast/blob/master/COPYRIGHT.md
6+
* @license https://github.com/open-code-modeling/php-code-ast/blob/master/LICENSE.md MIT License
7+
*/
8+
9+
declare(strict_types=1);
10+
11+
namespace OpenCodeModeling\CodeAst;
12+
13+
use OpenCodeModeling\CodeAst\Builder\ClassBuilder;
14+
use OpenCodeModeling\CodeAst\Builder\ClassConstBuilder;
15+
use OpenCodeModeling\CodeAst\Builder\ClassMethodBuilder;
16+
use OpenCodeModeling\CodeAst\Builder\File;
17+
use OpenCodeModeling\CodeAst\Builder\FileCollection;
18+
use OpenCodeModeling\CodeAst\Code\ClassConstGenerator;
19+
use OpenCodeModeling\CodeAst\Package\ClassInfo;
20+
use OpenCodeModeling\CodeAst\Package\ClassInfoList;
21+
use PhpParser\NodeTraverser;
22+
use PhpParser\Parser;
23+
use PhpParser\PrettyPrinterAbstract;
24+
25+
final class FileCodeGenerator
26+
{
27+
private ClassInfoList $classInfoList;
28+
private Parser $parser;
29+
private PrettyPrinterAbstract $printer;
30+
31+
public function __construct(
32+
Parser $parser,
33+
PrettyPrinterAbstract $printer,
34+
ClassInfoList $classInfoList
35+
) {
36+
$this->parser = $parser;
37+
$this->printer = $printer;
38+
$this->classInfoList = $classInfoList;
39+
}
40+
41+
/**
42+
* Returns the generated code of provided file collection
43+
*
44+
* @param FileCollection $fileCollection
45+
* @param callable|null $currentFileAst Callable to return current file AST, if null, file will be overwritten
46+
* @return array<string, string> List of filename => code
47+
*/
48+
public function generateFiles(
49+
FileCollection $fileCollection,
50+
callable $currentFileAst = null
51+
): array {
52+
$files = [];
53+
54+
if ($currentFileAst === null) {
55+
$currentFileAst = static function (File $file, ClassInfo $classInfo) {
56+
return [];
57+
};
58+
}
59+
60+
$previousNamespace = '__invalid//namespace__';
61+
62+
foreach ($fileCollection as $classBuilder) {
63+
if ($previousNamespace !== $classBuilder->getNamespace()) {
64+
$previousNamespace = $classBuilder->getNamespace();
65+
$classInfo = $this->classInfoList->classInfoForNamespace($previousNamespace);
66+
$path = $classInfo->getPath($classBuilder->getNamespace() . '\\' . $classBuilder->getName());
67+
}
68+
$filename = $classInfo->getFilenameFromPathAndName($path, $classBuilder->getName());
69+
70+
$nodeTraverser = new NodeTraverser();
71+
$classBuilder->injectVisitors($nodeTraverser, $this->parser);
72+
73+
$files[$filename] = $this->printer->prettyPrintFile(
74+
$nodeTraverser->traverse($currentFileAst($classBuilder, $classInfo))
75+
);
76+
}
77+
78+
return $files;
79+
}
80+
81+
/**
82+
* Generation of getter methods. Use $skip callable to skip generation e. g. for value objects
83+
*
84+
* @param FileCollection $classBuilderCollection Only ClassBuilder objects are considered
85+
* @param bool $typed Should the generated code be typed
86+
* @param callable $methodNameFilter Filter the property name to your desired method name e.g. with "get" prefix
87+
* @param callable|null $skip Check method to skip getter methods e.g. for value objects
88+
*/
89+
public function addGetterMethodsForProperties(
90+
FileCollection $classBuilderCollection,
91+
bool $typed,
92+
callable $methodNameFilter,
93+
callable $skip = null
94+
): void {
95+
if ($skip === null) {
96+
$skip = static function (ClassBuilder $classBuilder) {
97+
return false;
98+
};
99+
}
100+
101+
foreach ($classBuilderCollection as $classBuilder) {
102+
if (! $classBuilder instanceof ClassBuilder) {
103+
continue;
104+
}
105+
foreach ($classBuilder->getProperties() as $classPropertyBuilder) {
106+
$methodName = ($methodNameFilter)($classPropertyBuilder->getName());
107+
108+
if (true === ($skip)($classBuilder)
109+
|| $classBuilder->hasMethod($methodName)) {
110+
continue 2;
111+
}
112+
$classBuilder->addMethod(
113+
ClassMethodBuilder::fromScratch($methodName, $typed)
114+
->setReturnType($classPropertyBuilder->getType())
115+
->setReturnTypeDocBlockHint($classPropertyBuilder->getTypeDocBlockHint())
116+
->setBody('return $this->' . $classPropertyBuilder->getName() . ';')
117+
);
118+
}
119+
}
120+
}
121+
122+
/**
123+
* Generation of constants for each property. Use $skip callable to skip generation e. g. for value objects
124+
*
125+
* @param FileCollection $fileCollection Only ClassBuilder objects are considered
126+
* @param callable $constantNameFilter Converts the name to a proper class constant name
127+
* @param callable $constantValueFilter Converts the name to a proper class constant value e.g. snake_case or camelCase
128+
* @param callable|null $skip Check method to skip getter methods e.g. for value objects
129+
* @param int $visibility Visibility of the class constant
130+
*/
131+
public function addClassConstantsForProperties(
132+
FileCollection $fileCollection,
133+
callable $constantNameFilter,
134+
callable $constantValueFilter,
135+
callable $skip = null,
136+
int $visibility = ClassConstGenerator::FLAG_PUBLIC
137+
): void {
138+
if ($skip === null) {
139+
$skip = static function (ClassBuilder $classBuilder) {
140+
return false;
141+
};
142+
}
143+
144+
foreach ($fileCollection as $classBuilder) {
145+
if (! $classBuilder instanceof ClassBuilder) {
146+
continue;
147+
}
148+
foreach ($classBuilder->getProperties() as $classPropertyBuilder) {
149+
$constantName = ($constantNameFilter)($classPropertyBuilder->getName());
150+
151+
if (true === ($skip)($classBuilder)
152+
|| $classBuilder->hasConstant($constantName)) {
153+
continue 2;
154+
}
155+
$classBuilder->addConstant(
156+
ClassConstBuilder::fromScratch(
157+
$constantName,
158+
($constantValueFilter)($classPropertyBuilder->getName()),
159+
$visibility
160+
)
161+
);
162+
}
163+
}
164+
}
165+
}

0 commit comments

Comments
 (0)