Skip to content

Commit f917eb6

Browse files
wip
1 parent 67445b0 commit f917eb6

8 files changed

+138
-58
lines changed

src/Attributes/LiteralTypeScriptType.php

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@
33
namespace Spatie\TypeScriptTransformer\Attributes;
44

55
use Attribute;
6-
use phpDocumentor\Reflection\Type;
6+
use ReflectionClass;
77
use Spatie\TypeScriptTransformer\Types\StructType;
88
use Spatie\TypeScriptTransformer\Types\TypeScriptType;
9+
use Spatie\TypeScriptTransformer\TypeScript\TypeScriptNode;
10+
use Spatie\TypeScriptTransformer\TypeScript\TypeScriptObject;
11+
use Spatie\TypeScriptTransformer\TypeScript\TypeScriptProperty;
12+
use Spatie\TypeScriptTransformer\TypeScript\TypeScriptRaw;
913

1014
#[Attribute]
11-
class LiteralTypeScriptType implements TypeScriptTransformableAttribute
15+
class LiteralTypeScriptType implements TypeScriptTypeAttributeContract
1216
{
1317
private string|array $typeScript;
1418

@@ -17,17 +21,19 @@ public function __construct(string|array $typeScript)
1721
$this->typeScript = $typeScript;
1822
}
1923

20-
public function getType(): Type
24+
public function getType(ReflectionClass $class): TypeScriptNode
2125
{
2226
if (is_string($this->typeScript)) {
23-
return new TypeScriptType($this->typeScript);
27+
return new TypeScriptRaw($this->typeScript);
2428
}
2529

26-
$types = array_map(
27-
fn (string $type) => new TypeScriptType($type),
28-
$this->typeScript
29-
);
30+
$properties = collect($this->typeScript)
31+
->map(fn (string $type, string $name) => new TypeScriptProperty(
32+
$name,
33+
new TypeScriptRaw($type)
34+
))
35+
->all();
3036

31-
return new StructType($types);
37+
return new TypeScriptObject($properties);
3238
}
3339
}

src/Attributes/TypeScript.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
#[Attribute]
88
class TypeScript
99
{
10-
public ?string $name;
11-
12-
public function __construct(?string $name = null)
13-
{
14-
$this->name = $name;
10+
/**
11+
* @param array<string>|null $location
12+
*/
13+
public function __construct(
14+
public ?string $name = null,
15+
public ?array $location = null,
16+
) {
1517
}
1618
}

src/Attributes/TypeScriptTransformableAttribute.php

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/Attributes/TypeScriptTransformer.php

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/Attributes/TypeScriptType.php

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
namespace Spatie\TypeScriptTransformer\Attributes;
44

55
use Attribute;
6-
use phpDocumentor\Reflection\Type;
7-
use phpDocumentor\Reflection\TypeResolver;
6+
use ReflectionClass;
7+
use Spatie\TypeScriptTransformer\Actions\TranspilePhpStanTypeToTypeScriptTypeAction;
88
use Spatie\TypeScriptTransformer\Exceptions\UnableToTransformUsingAttribute;
9+
use Spatie\TypeScriptTransformer\TypeResolvers\DocTypeResolver;
910
use Spatie\TypeScriptTransformer\Types\StructType;
11+
use Spatie\TypeScriptTransformer\TypeScript\TypeScriptNode;
12+
use Spatie\TypeScriptTransformer\TypeScript\TypeScriptObject;
13+
use Spatie\TypeScriptTransformer\TypeScript\TypeScriptProperty;
1014

1115
#[Attribute]
12-
class TypeScriptType implements TypeScriptTransformableAttribute
16+
class TypeScriptType implements TypeScriptTypeAttributeContract
1317
{
1418
private array|string $type;
1519

@@ -18,17 +22,22 @@ public function __construct(string|array $type)
1822
$this->type = $type;
1923
}
2024

21-
public function getType(): Type
25+
public function getType(ReflectionClass $class): TypeScriptNode
2226
{
27+
$docResolver = new DocTypeResolver();
28+
$transpiler = new TranspilePhpStanTypeToTypeScriptTypeAction();
29+
2330
if (is_string($this->type)) {
24-
return (new TypeResolver())->resolve($this->type);
31+
return $transpiler->execute($docResolver->type($this->type), $class);
2532
}
2633

27-
/** @psalm-suppress RedundantCondition */
28-
if (is_array($this->type)) {
29-
return StructType::fromArray($this->type);
30-
}
34+
$properties = collect($this->type)
35+
->map(fn (string $type, string $name) => new TypeScriptProperty(
36+
$name,
37+
$transpiler->execute($docResolver->type($type), $class)
38+
))
39+
->all();
3140

32-
throw UnableToTransformUsingAttribute::create($this->type);
41+
return new TypeScriptObject($properties);
3342
}
3443
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Spatie\TypeScriptTransformer\Attributes;
4+
5+
use ReflectionClass;
6+
use Spatie\TypeScriptTransformer\TypeScript\TypeScriptNode;
7+
8+
interface TypeScriptTypeAttributeContract
9+
{
10+
public function getType(ReflectionClass $class): TypeScriptNode;
11+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace Spatie\TypeScriptTransformer\Transformers;
4+
5+
use ReflectionClass;
6+
use Spatie\TypeScriptTransformer\Attributes\TypeScript;
7+
use Spatie\TypeScriptTransformer\Support\TransformationContext;
8+
use Spatie\TypeScriptTransformer\Transformed\Transformed;
9+
use Spatie\TypeScriptTransformer\Transformed\Untransformable;
10+
11+
class AttributeTransformer extends ClassTransformer
12+
{
13+
public function shouldTransform(ReflectionClass $reflection): bool
14+
{
15+
return count($reflection->getAttributes(TypeScript::class)) > 0;
16+
}
17+
18+
public function transform(ReflectionClass $reflectionClass, TransformationContext $context): Transformed|Untransformable
19+
{
20+
$transformed = parent::transform($reflectionClass, $context);
21+
22+
if ($transformed instanceof Untransformable) {
23+
return $transformed;
24+
}
25+
26+
/** @var TypeScript $attribute */
27+
$attribute = $reflectionClass->getAttributes(TypeScript::class)[0]->newInstance();
28+
29+
if ($attribute->name !== null) {
30+
$transformed->name = $attribute->name;
31+
}
32+
33+
if ($attribute->location !== null) {
34+
$transformed->location = $attribute->location;
35+
}
36+
37+
return $transformed;
38+
}
39+
}

src/Transformers/ClassTransformer.php

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Spatie\TypeScriptTransformer\Actions\TranspilePhpStanTypeToTypeScriptTypeAction;
99
use Spatie\TypeScriptTransformer\Actions\TranspileReflectionTypeToTypeScriptTypeAction;
1010
use Spatie\TypeScriptTransformer\Attributes\Optional;
11+
use Spatie\TypeScriptTransformer\Attributes\TypeScriptTypeAttributeContract;
1112
use Spatie\TypeScriptTransformer\References\ReflectionClassReference;
1213
use Spatie\TypeScriptTransformer\Support\TransformationContext;
1314
use Spatie\TypeScriptTransformer\Transformed\Transformed;
@@ -38,6 +39,30 @@ public function transform(ReflectionClass $reflectionClass, TransformationContex
3839
return Untransformable::create();
3940
}
4041

42+
43+
return new Transformed(
44+
new TypeScriptExport(
45+
new TypeScriptAlias(
46+
new TypeScriptIdentifier($context->name),
47+
$this->getTypeScriptNode($reflectionClass)
48+
)
49+
),
50+
new ReflectionClassReference($reflectionClass),
51+
$context->name,
52+
true,
53+
$context->nameSpaceSegments,
54+
);
55+
}
56+
57+
abstract public function shouldTransform(ReflectionClass $reflection): bool;
58+
59+
protected function getTypeScriptNode(
60+
ReflectionClass $reflectionClass
61+
): TypeScriptNode {
62+
if ($resolvedAttributeType = $this->resolveTypeByAttribute($reflectionClass)) {
63+
return $resolvedAttributeType;
64+
}
65+
4166
$classAnnotations = $this->docTypeResolver->class($reflectionClass)?->properties ?? [];
4267

4368
$constructorAnnotations = $reflectionClass->hasMethod('__construct')
@@ -55,16 +80,26 @@ public function transform(ReflectionClass $reflectionClass, TransformationContex
5580
);
5681
}
5782

58-
return new Transformed(
59-
new TypeScriptExport(new TypeScriptAlias(new TypeScriptIdentifier($context->name), new TypeScriptObject($properties))),
60-
new ReflectionClassReference($reflectionClass),
61-
$context->name,
62-
true,
63-
$context->nameSpaceSegments,
64-
);
83+
return new TypeScriptObject($properties);
6584
}
6685

67-
abstract public function shouldTransform(ReflectionClass $reflection): bool;
86+
protected function resolveTypeByAttribute(
87+
ReflectionClass $reflectionClass,
88+
?ReflectionProperty $property = null,
89+
): ?TypeScriptNode {
90+
$subject = $property ?? $reflectionClass;
91+
92+
foreach ($subject->getAttributes() as $attribute) {
93+
if (is_a($attribute->getName(), TypeScriptTypeAttributeContract::class, true)) {
94+
/** @var TypeScriptTypeAttributeContract $attributeInstance */
95+
$attributeInstance = $attribute->newInstance();
96+
97+
return $attributeInstance->getType($reflectionClass);
98+
}
99+
}
100+
101+
return null;
102+
}
68103

69104
protected function getProperties(ReflectionClass $reflection): array
70105
{
@@ -103,6 +138,10 @@ protected function resolveTypeForProperty(
103138
ReflectionProperty $reflectionProperty,
104139
?ParsedNameAndType $annotation,
105140
): TypeScriptNode {
141+
if ($resolvedAttributeType = $this->resolveTypeByAttribute($reflectionClass, $reflectionProperty)) {
142+
return $resolvedAttributeType;
143+
}
144+
106145
if ($annotation) {
107146
return $this->transpilePhpStanTypeToTypeScriptTypeAction->execute(
108147
$annotation->type,

0 commit comments

Comments
 (0)