Skip to content

Commit 3f1bd1c

Browse files
committed
Optimize union handling with enum for all-literal unions and set additionalItems to false for array schemas
1 parent 8de3203 commit 3f1bd1c

2 files changed

Lines changed: 25 additions & 3 deletions

File tree

src/Schema/JsonSchemaGenerator.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,27 @@ private static function convert(SchemaType $schema): array
132132
return [
133133
'type' => 'array',
134134
'items' => \array_map(fn(SchemaType $s) => self::convert($s), $schema->elements),
135+
'additionalItems' => false,
135136
'minItems' => \count($schema->elements),
136137
'maxItems' => \count($schema->elements),
137138
];
138139
}
139140

140141
// $schema is UnionType at this point
141142
/** @var UnionType $schema */
143+
// Detect all-literal unions and emit compact "enum" keyword
144+
$allLiterals = true;
145+
foreach ($schema->branches as $branch) {
146+
if (!($branch instanceof LiteralType)) {
147+
$allLiterals = false;
148+
break;
149+
}
150+
}
151+
if ($allLiterals) {
152+
return [
153+
'enum' => \array_map(fn(SchemaType $s) => ($s instanceof LiteralType) ? $s->value : null, $schema->branches),
154+
];
155+
}
142156
return [
143157
'oneOf' => \array_map(fn(SchemaType $s) => self::convert($s), $schema->branches),
144158
];

tests/Schema/JsonSchemaTest.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ public function testTuple(): void
303303
['type' => 'string'],
304304
['type' => 'boolean'],
305305
],
306+
'additionalItems' => false,
306307
'minItems' => 3,
307308
'maxItems' => 3,
308309
],
@@ -324,10 +325,17 @@ public function testUnion(): void
324325
public function testEnum(): void
325326
{
326327
$this->assertJsonSchema(S::enum('fast', 'safe', 'auto'), [
328+
'enum' => ['fast', 'safe', 'auto'],
329+
]);
330+
}
331+
332+
public function testUnionMixedNotEnum(): void
333+
{
334+
// Union of non-literals still uses oneOf
335+
$this->assertJsonSchema(S::union(S::string(), S::null()), [
327336
'oneOf' => [
328-
['const' => 'fast'],
329-
['const' => 'safe'],
330-
['const' => 'auto'],
337+
['type' => 'string'],
338+
['type' => 'null'],
331339
],
332340
]);
333341
}

0 commit comments

Comments
 (0)