Skip to content

Commit 895b174

Browse files
committed
Make as many unit tests as possible pass
1 parent a39ed4d commit 895b174

File tree

152 files changed

+7367
-1428
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

152 files changed

+7367
-1428
lines changed

composer.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"jawira/case-converter": "^3.5",
2222
"kwn/number-to-words": "^2.6",
2323
"league/openapi-psr7-validator": "^0.21",
24+
"league/uri": "^6.8 || ^7.3",
2425
"nikic/php-parser": "^4.15",
2526
"nunomaduro/termwind": "^1.15",
2627
"ondram/ci-detector": "^4.1",
@@ -55,10 +56,10 @@
5556
],
5657
"config": {
5758
"allow-plugins": {
58-
"wyrihaximus/composer-update-bin-autoload-path": true,
59-
"infection/extension-installer": true,
6059
"dealerdirect/phpcodesniffer-composer-installer": true,
61-
"ergebnis/composer-normalize": true
60+
"ergebnis/composer-normalize": true,
61+
"infection/extension-installer": true,
62+
"wyrihaximus/composer-update-bin-autoload-path": true
6263
},
6364
"platform": {
6465
"php": "8.2.13"

composer.lock

Lines changed: 360 additions & 286 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/templates/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"devizzent/cebe-php-openapi": "^1",
2121
"eventsauce/object-hydrator": "^1.1",
2222
"league/openapi-psr7-validator": "^0.21",
23+
"league/uri": "^7.3 || ^6.8",
2324
"psr/http-message": "^1.0",
2425
"react/http": "^1.8",
2526
"react/async": "^4.0",

src/Gatherer/CompositSchema.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ApiClients\Tools\OpenApiClientGenerator\Gatherer;
6+
7+
use ApiClients\Tools\OpenApiClientGenerator\ClassString;
8+
use ApiClients\Tools\OpenApiClientGenerator\Configuration\Namespace_;
9+
use ApiClients\Tools\OpenApiClientGenerator\Registry\CompositSchema as CompositSchemaRegistry;
10+
use ApiClients\Tools\OpenApiClientGenerator\Registry\Contract as ContractRegistry;
11+
use ApiClients\Tools\OpenApiClientGenerator\Registry\Schema as SchemaRegistry;
12+
use ApiClients\Tools\OpenApiClientGenerator\Representation\Schema;
13+
use ApiClients\Tools\OpenApiClientGenerator\Utils;
14+
use cebe\openapi\spec\Schema as baseSchema;
15+
16+
use function array_key_exists;
17+
use function in_array;
18+
use function is_array;
19+
use function property_exists;
20+
21+
final class CompositSchema
22+
{
23+
public static function gather(
24+
Namespace_ $baseNamespace,
25+
string $className,
26+
baseSchema $schema,
27+
SchemaRegistry $schemaRegistry,
28+
ContractRegistry $contractRegistry,
29+
CompositSchemaRegistry $compositSchemaRegistry,
30+
): Schema {
31+
$className = Utils::className($className);
32+
$isArray = $schema->type === 'array';
33+
$properties = [];
34+
$example = [];
35+
36+
if ($isArray) {
37+
$schema = $schema->items;
38+
}
39+
40+
foreach ($schema->properties as $propertyName => $property) {
41+
$gatheredProperty = Property::gather(
42+
$baseNamespace,
43+
$className,
44+
(string) $propertyName,
45+
in_array(
46+
(string) $propertyName,
47+
$schema->required ?? [],
48+
false,
49+
),
50+
$property,
51+
$schemaRegistry,
52+
$contractRegistry,
53+
$compositSchemaRegistry,
54+
);
55+
$properties[] = $gatheredProperty;
56+
57+
foreach (['examples', 'example'] as $examplePropertyName) {
58+
if (array_key_exists($gatheredProperty->sourceName, $example)) {
59+
break;
60+
}
61+
62+
if (! property_exists($schema, $examplePropertyName) || ! is_array($schema->$examplePropertyName) || ! array_key_exists($gatheredProperty->sourceName, $schema->$examplePropertyName)) {
63+
continue;
64+
}
65+
66+
$example[$gatheredProperty->sourceName] = $schema->$examplePropertyName[$gatheredProperty->sourceName];
67+
}
68+
69+
$example[$gatheredProperty->sourceName] = $gatheredProperty->example->raw;
70+
71+
foreach ($property->enum ?? [] as $value) {
72+
$example[$gatheredProperty->sourceName] = $value;
73+
break;
74+
}
75+
}
76+
77+
return new Schema(
78+
ClassString::factory($baseNamespace, 'Schema\\' . $className),
79+
ClassString::factory($baseNamespace, 'Contract\\' . $className),
80+
ClassString::factory($baseNamespace, 'Error\\' . $className),
81+
ClassString::factory($baseNamespace, 'ErrorSchemas\\' . $className),
82+
$schema->title ?? '',
83+
$schema->description ?? '',
84+
$example,
85+
$properties,
86+
$schema,
87+
$isArray,
88+
($schema->type === null ? ['object'] : (is_array($schema->type) ? $schema->type : [$schema->type])),
89+
);
90+
}
91+
}

src/Gatherer/ExampleData.php

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,20 @@
1414
use ReverseRegex\Lexer;
1515
use ReverseRegex\Parser;
1616

17+
use function explode;
1718
use function gettype;
1819
use function is_array;
1920
use function is_string;
2021
use function Safe\date;
2122
use function Safe\json_encode;
2223
use function strlen;
24+
use function strpos;
2325

2426
final class ExampleData
2527
{
2628
public static function gather(mixed $exampleData, PropertyType $type, string $propertyName): Representation\ExampleData
2729
{
28-
if ($type->type === 'array') {
30+
if ($type->type === 'array' || $type->type === 'union') {
2931
if ($type->payload instanceof Schema) {
3032
$exampleData = ArrayMerger::doMerge(
3133
$type->payload->example,
@@ -34,6 +36,11 @@ public static function gather(mixed $exampleData, PropertyType $type, string $pr
3436
);
3537
} elseif ($type->payload instanceof PropertyType) {
3638
return self::gather($exampleData, $type->payload, $propertyName);
39+
40+
// } elseif (is_array($type->payload)) {
41+
// $exampleData = [
42+
// self::gather($exampleData, $type->payload[0], $propertyName),
43+
// ];
3744
}
3845

3946
return new Representation\ExampleData($exampleData, $exampleData instanceof Node\Expr ? $exampleData : self::turnArrayIntoNode((array) $exampleData));
@@ -90,6 +97,12 @@ public static function determiteType(mixed $exampleData): Representation\Example
9097
/** @phpstan-ignore-next-line */
9198
public static function scalarData(int $seed, string $type, string|null $format, string|null $pattern = null): Representation\ExampleData
9299
{
100+
if (strpos($type, '|') !== false) {
101+
[$firstType] = explode('|', $type);
102+
103+
return self::scalarData($seed, $firstType, $format, $pattern);
104+
}
105+
93106
if ($type === 'int' || $type === '?int') {
94107
return new Representation\ExampleData($seed, new Node\Scalar\LNumber($seed));
95108
}
@@ -149,6 +162,23 @@ public static function scalarData(int $seed, string $type, string|null $format,
149162
return new Representation\ExampleData('generated', new Node\Scalar\String_('generated'));
150163
}
151164

165+
if ($type === 'array' || $type === '?array') {
166+
$string = self::scalarData($seed, 'string', $format, $pattern);
167+
168+
return new Representation\ExampleData(
169+
[
170+
$string->raw,
171+
],
172+
new Node\Expr\Array_(
173+
[
174+
new Node\Expr\ArrayItem(
175+
$string->node,
176+
),
177+
],
178+
),
179+
);
180+
}
181+
152182
return new Representation\ExampleData(
153183
null,
154184
new Node\Expr\ConstFetch(

src/Gatherer/IntersectionSchema.php

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ApiClients\Tools\OpenApiClientGenerator\Gatherer;
6+
7+
use ApiClients\Tools\OpenApiClientGenerator\ClassString;
8+
use ApiClients\Tools\OpenApiClientGenerator\Configuration\Namespace_;
9+
use ApiClients\Tools\OpenApiClientGenerator\Registry\CompositSchema as CompositSchemaRegistry;
10+
use ApiClients\Tools\OpenApiClientGenerator\Registry\Contract as ContractRegistry;
11+
use ApiClients\Tools\OpenApiClientGenerator\Registry\Schema as SchemaRegistry;
12+
use ApiClients\Tools\OpenApiClientGenerator\Representation\Contract;
13+
use ApiClients\Tools\OpenApiClientGenerator\Representation\Schema;
14+
use ApiClients\Tools\OpenApiClientGenerator\Utils;
15+
use cebe\openapi\spec\Schema as baseSchema;
16+
17+
use function array_key_exists;
18+
use function in_array;
19+
use function is_array;
20+
use function property_exists;
21+
use function serialize;
22+
23+
use const PHP_EOL;
24+
25+
final class IntersectionSchema
26+
{
27+
public static function gather(
28+
Namespace_ $baseNamespace,
29+
string $className,
30+
baseSchema $baseProperty,
31+
SchemaRegistry $schemaRegistry,
32+
ContractRegistry $contractRegistry,
33+
CompositSchemaRegistry $compositSchemaRegistry,
34+
): Schema {
35+
$className = Utils::className($className);
36+
$contracts = [];
37+
$properties = [];
38+
$example = [];
39+
40+
foreach ($baseProperty->allOf as $schema) {
41+
$gatheredProperties = [];
42+
foreach ($schema->properties as $propertyName => $property) {
43+
$gatheredProperty = Property::gather(
44+
$baseNamespace,
45+
$className,
46+
(string) $propertyName,
47+
in_array(
48+
(string) $propertyName,
49+
$schema->required ?? [],
50+
false,
51+
),
52+
$property,
53+
$schemaRegistry,
54+
$contractRegistry,
55+
$compositSchemaRegistry,
56+
);
57+
$gatheredProperties[] = $gatheredProperty;
58+
59+
foreach (['examples', 'example'] as $examplePropertyName) {
60+
if (array_key_exists($gatheredProperty->sourceName, $example)) {
61+
break;
62+
}
63+
64+
if (! property_exists($schema, $examplePropertyName) || ! is_array($schema->$examplePropertyName) || ! array_key_exists($gatheredProperty->sourceName, $schema->$examplePropertyName)) {
65+
continue;
66+
}
67+
68+
$example[$gatheredProperty->sourceName] = $schema->$examplePropertyName[$gatheredProperty->sourceName];
69+
}
70+
71+
$example[$gatheredProperty->sourceName] = $gatheredProperty->example->raw;
72+
73+
foreach ($property->enum ?? [] as $value) {
74+
$example[$gatheredProperty->sourceName] = $value;
75+
break;
76+
}
77+
}
78+
79+
$contracts[] = new Contract(
80+
ClassString::factory(
81+
$baseNamespace,
82+
$contractRegistry->get($schema, 'Contract\\' . $className . '\\' . $schema->title),
83+
),
84+
$gatheredProperties,
85+
);
86+
87+
$properties = [...$properties, ...$gatheredProperties];
88+
}
89+
90+
return new Schema(
91+
ClassString::factory($baseNamespace, 'Schema\\' . $className),
92+
$contracts,
93+
ClassString::factory($baseNamespace, 'Error\\' . $className),
94+
ClassString::factory($baseNamespace, 'ErrorSchemas\\' . $className),
95+
$schema->title ?? '',
96+
$schema->description ?? '',
97+
$example,
98+
$properties,
99+
$baseProperty,
100+
false,
101+
($schema->type === null ? ['object'] : (is_array($schema->type) ? $schema->type : [$schema->type])),
102+
);
103+
}
104+
}

src/Gatherer/Operation.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
use ApiClients\Tools\OpenApiClientGenerator\ClassString;
88
use ApiClients\Tools\OpenApiClientGenerator\Configuration\Namespace_;
9+
use ApiClients\Tools\OpenApiClientGenerator\Registry\CompositSchema as CompositSchemaRegistry;
10+
use ApiClients\Tools\OpenApiClientGenerator\Registry\Contract as ContractRegistry;
911
use ApiClients\Tools\OpenApiClientGenerator\Registry\Schema as SchemaRegistry;
1012
use ApiClients\Tools\OpenApiClientGenerator\Registry\ThrowableSchema;
1113
use ApiClients\Tools\OpenApiClientGenerator\Representation\Header;
@@ -45,11 +47,21 @@ public static function gather(
4547
openAPIOperation $operation,
4648
ThrowableSchema $throwableSchemaRegistry,
4749
SchemaRegistry $schemaRegistry,
50+
ContractRegistry $contractRegistry,
51+
CompositSchemaRegistry $compositSchemaRegistry,
4852
): \ApiClients\Tools\OpenApiClientGenerator\Representation\Operation {
4953
$returnType = [];
5054
$parameters = [];
5155
$empties = [];
5256
foreach ($operation->parameters as $parameter) {
57+
$types = is_array($parameter->schema->type) ? $parameter->schema->type : [$parameter->schema->type];
58+
if (count($parameter->schema->oneOf ?? []) > 0) {
59+
$types = [];
60+
foreach ($parameter->schema->oneOf as $oneOfSchema) {
61+
$types[] = $oneOfSchema->type;
62+
}
63+
}
64+
5365
$parameterType = str_replace([
5466
'integer',
5567
'any',
@@ -58,7 +70,7 @@ public static function gather(
5870
'int',
5971
'string|object',
6072
'bool',
61-
], implode('|', is_array($parameter->schema->type) ? $parameter->schema->type : [$parameter->schema->type]));
73+
], implode('|', $types));
6274

6375
$parameters[] = new Parameter(
6476
(new Convert($parameter->name))->toCamel(),
@@ -82,7 +94,7 @@ public static function gather(
8294
);
8395
$requestBody[] = new OperationRequestBody(
8496
$contentType,
85-
Schema::gather($baseNamespace, $requestBodyClassname, $requestBodyDetails->schema, $schemaRegistry),
97+
Schema::gather($baseNamespace, $requestBodyClassname, $requestBodyDetails->schema, $schemaRegistry, $contractRegistry, $compositSchemaRegistry),
8698
);
8799
}
88100
}
@@ -115,6 +127,8 @@ public static function gather(
115127
$contentTypeMediaType->schema,
116128
true,
117129
$schemaRegistry,
130+
$contractRegistry,
131+
$compositSchemaRegistry,
118132
),
119133
);
120134
if ($isError) {
@@ -139,6 +153,8 @@ public static function gather(
139153
),
140154
$headerSpec->schema,
141155
$schemaRegistry,
156+
$contractRegistry,
157+
$compositSchemaRegistry,
142158
), ExampleData::determiteType($headerSpec->example));
143159
}
144160

0 commit comments

Comments
 (0)