Skip to content

Commit 90bd20b

Browse files
authored
Dart factory + equitable generation (Close #24) (#40)
* Dart factory + equitable generation (Close #24)
1 parent 1238e95 commit 90bd20b

24 files changed

+1473
-327
lines changed

src/Dto/DtoType.php

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,6 @@ public function __construct(
1414
) {
1515
}
1616

17-
public function isNumericEnum(): bool
18-
{
19-
foreach ($this->properties as $property) {
20-
if (!($property instanceof DtoEnumProperty && $property->isNumeric())) {
21-
return false;
22-
}
23-
}
24-
25-
return true;
26-
}
27-
2817
public function getName(): string
2918
{
3019
return $this->name;
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
namespace Riverwaysoft\DtoConverter\Language\Dart;
4+
5+
use Riverwaysoft\DtoConverter\Dto\DtoEnumProperty;
6+
use Riverwaysoft\DtoConverter\Dto\DtoList;
7+
use Riverwaysoft\DtoConverter\Dto\DtoType;
8+
use Riverwaysoft\DtoConverter\Dto\PhpType\PhpListType;
9+
use Riverwaysoft\DtoConverter\Dto\PhpType\PhpTypeInterface;
10+
use Riverwaysoft\DtoConverter\Dto\PhpType\PhpUnionType;
11+
use Riverwaysoft\DtoConverter\Dto\PhpType\PhpUnknownType;
12+
use Webmozart\Assert\Assert;
13+
14+
class DartClassFactoryGenerator
15+
{
16+
public function __construct(private string|null $includePattern = null)
17+
{
18+
19+
}
20+
21+
public function generateClassFactory(DtoType $dto, DtoList $dtoList): string
22+
{
23+
if (empty($dtoList->getList())) {
24+
return '';
25+
}
26+
27+
if ($this->includePattern && !preg_match(pattern: $this->includePattern, subject: $dto->getName())) {
28+
return '';
29+
}
30+
31+
$factoryProperties = '';
32+
33+
foreach ($dto->getProperties() as $property) {
34+
Assert::false($property instanceof DtoEnumProperty, "Dart factories only work in a class context, not enum");
35+
$propertyValue = $this->resolveFactoryProperty($property->getName(), $property->getType(), $dtoList);
36+
$factoryProperties .= sprintf(" %s: %s,\n", $property->getName(), $propertyValue);
37+
}
38+
39+
return sprintf("\n factory %s.fromJson(Map<String, dynamic> json) {
40+
return %s(\n%s );
41+
}\n",
42+
$dto->getName(),
43+
$dto->getName(),
44+
$factoryProperties,
45+
);
46+
}
47+
48+
private function resolveFactoryProperty(string $propertyName, PhpTypeInterface $type, DtoList $dtoList): string
49+
{
50+
if ($type instanceof PhpUnionType && $type->isNullable()) {
51+
return sprintf("json['{$propertyName}'] != null ? %s : null", $this->resolveFactoryProperty($propertyName, $type->getFirstNotNullType(), $dtoList));
52+
}
53+
54+
if ($type instanceof PhpListType) {
55+
$collectionType = $type->getType();
56+
if (!($collectionType instanceof PhpUnknownType)) {
57+
throw new \Exception('Only class instance can be converted to collection');
58+
}
59+
$class = $collectionType->getName();
60+
return sprintf("List<%s>.from(json['%s'].map((e) => %s.fromJson(e)))", $class, $propertyName, $class);
61+
}
62+
63+
if ($type instanceof PhpUnknownType) {
64+
if ($type->getName() === 'DateTime' || $type->getName() === 'DateTimeImmutable') {
65+
return sprintf("DateTime.parse(json['%s'])", $propertyName);
66+
}
67+
68+
if ($dtoList->getDtoByType($type->getName())?->getExpressionType()->isAnyEnum()) {
69+
return sprintf("%s.values[json['%s']]", $type->getName(), $propertyName);
70+
}
71+
72+
return sprintf("%s.fromJson(json['%s'])", $type->getName(), $propertyName);
73+
}
74+
75+
return sprintf("json['%s']", $propertyName);
76+
}
77+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace Riverwaysoft\DtoConverter\Language\Dart;
4+
5+
use Riverwaysoft\DtoConverter\Dto\DtoClassProperty;
6+
use Riverwaysoft\DtoConverter\Dto\DtoType;
7+
8+
class DartEquitableGenerator
9+
{
10+
public function __construct(private string|null $includePattern = null)
11+
{
12+
13+
}
14+
15+
public function generateEquitableHeader(DtoType $dto): string
16+
{
17+
if ($this->doesntMatch($dto)) {
18+
return '';
19+
}
20+
21+
return ' extends Equatable';
22+
}
23+
24+
private function doesntMatch(DtoType $dto): bool
25+
{
26+
return $this->includePattern && !preg_match(pattern: $this->includePattern, subject: $dto->getName());
27+
}
28+
29+
public function generateEquitableId(DtoType $dto): string
30+
{
31+
if ($this->doesntMatch($dto)) {
32+
return '';
33+
}
34+
35+
$properties = $dto->getProperties();
36+
$propertiesNames = array_map(fn(DtoClassProperty $property) => $property->getName(), $properties);
37+
$propertiesString = implode(separator: ', ', array: $propertiesNames);
38+
39+
return sprintf("\n @override
40+
List<dynamic> get props => [%s];\n", $propertiesString);
41+
}
42+
}

src/Language/Dart/DartGenerator.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ public function __construct(
2727
private OutputWriterInterface $outputWriter,
2828
/** @var UnknownTypeResolverInterface[] */
2929
private array $unknownTypeResolvers = [],
30-
private ?OutputFilesProcessor $outputFilesProcessor = null
30+
private ?OutputFilesProcessor $outputFilesProcessor = null,
31+
private ?DartClassFactoryGenerator $classFactoryGenerator = null,
32+
private ?DartEquitableGenerator $equitableGenerator = null,
3133
) {
3234
$this->outputFilesProcessor = $this->outputFilesProcessor ?? new OutputFilesProcessor();
3335
}
@@ -44,15 +46,20 @@ public function generate(DtoList $dtoList): array
4446
return $this->outputFilesProcessor->process($this->outputWriter->getTypes());
4547
}
4648

49+
50+
4751
private function convertToDartType(DtoType $dto, DtoList $dtoList): string
4852
{
4953
if ($dto->getExpressionType()->equals(ExpressionType::class())) {
5054
return sprintf(
51-
"class %s {%s\n\n %s({%s\n }) {}\n}",
55+
"class %s%s {%s\n\n %s({%s\n }) {}\n%s%s}",
5256
$dto->getName(),
57+
$this->equitableGenerator ? $this->equitableGenerator->generateEquitableHeader($dto) : '',
5358
$this->convertToDartProperties($dto, $dtoList),
5459
$dto->getName(),
5560
$this->generateConstructor($dto->getProperties()),
61+
$this->classFactoryGenerator ? $this->classFactoryGenerator->generateClassFactory($dto, $dtoList) : '',
62+
$this->equitableGenerator ? $this->equitableGenerator->generateEquitableId($dto) : '',
5663
);
5764
}
5865

src/Language/TypeScript/TypeScriptGenerator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ public function __construct(
3030
private OutputWriterInterface $outputWriter,
3131
/** @var UnknownTypeResolverInterface[] $unknownTypeResolvers */
3232
private array $unknownTypeResolvers = [],
33+
private ?OutputFilesProcessor $outputFilesProcessor = null,
3334
?TypeScriptGeneratorOptions $options = null,
34-
private ?OutputFilesProcessor $outputFilesProcessor = null
3535
) {
3636
$this->options = $options ?? new TypeScriptGeneratorOptions(useTypesInsteadOfEnums: false);
3737
$this->outputFilesProcessor = $this->outputFilesProcessor ?? new OutputFilesProcessor();

0 commit comments

Comments
 (0)