Skip to content

Commit 0e1d5fa

Browse files
committed
refactor: clean up ordering
1 parent 1b91214 commit 0e1d5fa

7 files changed

Lines changed: 37 additions & 159 deletions

File tree

src/Concerns/BuildsArray.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,31 @@ trait BuildsArray
1515
* and empty arrays, recursively unwrapping any Serializable children, and merging
1616
* any vendor extensions registered via HasExtensions.
1717
*
18+
* Keys listed in $alwaysInclude are emitted as-is, even when their value is
19+
* null or an empty array. This supports spec-allowed literal nulls (e.g.
20+
* Example::value, Parameter::example) and spec-allowed empty placeholders
21+
* (e.g. a PathItem operation key whose Operation has no fields yet).
22+
*
1823
* @param array<string, mixed> $fields
24+
* @param array<int, string> $alwaysInclude
1925
*
2026
* @return array<string, mixed>
2127
*/
22-
protected function buildArray(array $fields): array
28+
protected function buildArray(array $fields, array $alwaysInclude = []): array
2329
{
30+
$forced = array_flip($alwaysInclude);
2431
$output = [];
2532

2633
foreach ($fields as $key => $value) {
27-
if ($value === null) {
34+
$force = isset($forced[$key]);
35+
36+
if ($value === null && ! $force) {
2837
continue;
2938
}
3039

3140
$unwrapped = $this->unwrapValue($value);
3241

33-
if (is_array($unwrapped) && $unwrapped === []) {
42+
if (is_array($unwrapped) && $unwrapped === [] && ! $force) {
3443
continue;
3544
}
3645

src/Objects/Example.php

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -76,35 +76,11 @@ public function externalValue(?string $externalValue): self
7676
*/
7777
public function toArray(): array
7878
{
79-
$output = $this->buildArray([
79+
return $this->buildArray([
8080
'summary' => $this->summary,
8181
'description' => $this->description,
82+
'value' => $this->value,
8283
'externalValue' => $this->externalValue,
83-
]);
84-
85-
if ($this->hasValue) {
86-
// Inserted after buildArray so null literal values can be emitted.
87-
$output = [
88-
'value' => $this->value,
89-
] + $output;
90-
// Restore conventional key order: summary, description, value, externalValue.
91-
$ordered = [];
92-
93-
foreach (['summary', 'description', 'value', 'externalValue'] as $key) {
94-
if (array_key_exists($key, $output)) {
95-
$ordered[$key] = $output[$key];
96-
}
97-
}
98-
99-
foreach ($output as $k => $v) {
100-
if (! array_key_exists($k, $ordered)) {
101-
$ordered[$k] = $v;
102-
}
103-
}
104-
105-
return $ordered;
106-
}
107-
108-
return $output;
84+
], $this->hasValue ? ['value'] : []);
10985
}
11086
}

src/Objects/Header.php

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ public function content(MediaType ...$content): self
151151
*/
152152
public function toArray(): array
153153
{
154-
$output = $this->buildArray([
154+
return $this->buildArray([
155155
'description' => $this->description,
156156
'required' => $this->required,
157157
'deprecated' => $this->deprecated,
@@ -162,12 +162,7 @@ public function toArray(): array
162162
'schema' => $this->schema,
163163
'examples' => $this->examples,
164164
'content' => $this->content,
165-
]);
166-
167-
if ($this->hasExample) {
168-
$output['example'] = $this->example;
169-
}
170-
171-
return $output;
165+
'example' => $this->example,
166+
], $this->hasExample ? ['example'] : []);
172167
}
173168
}

src/Objects/Link.php

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -92,51 +92,13 @@ public function server(?Server $server): self
9292
*/
9393
public function toArray(): array
9494
{
95-
$output = $this->buildArray([
95+
return $this->buildArray([
9696
'operationRef' => $this->operationRef,
9797
'operationId' => $this->operationId,
9898
'parameters' => $this->parameters,
99+
'requestBody' => $this->requestBody,
99100
'description' => $this->description,
100101
'server' => $this->server,
101-
]);
102-
103-
if ($this->hasRequestBody) {
104-
// Insert requestBody after parameters (or before description/server) so the
105-
// conventional key order is preserved, even when the value is literal null.
106-
$reordered = [];
107-
108-
foreach ($output as $key => $value) {
109-
$reordered[$key] = $value;
110-
111-
if ($key === 'parameters' && ! array_key_exists('requestBody', $reordered)) {
112-
$reordered['requestBody'] = $this->requestBody;
113-
}
114-
}
115-
116-
if (! array_key_exists('requestBody', $reordered)) {
117-
// No parameters present — insert requestBody before description/server.
118-
$ordered = [];
119-
$inserted = false;
120-
121-
foreach ($reordered as $key => $value) {
122-
if (! $inserted && in_array($key, ['description', 'server'], true)) {
123-
$ordered['requestBody'] = $this->requestBody;
124-
$inserted = true;
125-
}
126-
127-
$ordered[$key] = $value;
128-
}
129-
130-
if (! $inserted) {
131-
$ordered['requestBody'] = $this->requestBody;
132-
}
133-
134-
return $ordered;
135-
}
136-
137-
return $reordered;
138-
}
139-
140-
return $output;
102+
], $this->hasRequestBody ? ['requestBody'] : []);
141103
}
142104
}

src/Objects/MediaType.php

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -146,34 +146,11 @@ public function encoding(array $encoding): self
146146
*/
147147
public function toArray(): array
148148
{
149-
$output = $this->buildArray([
149+
return $this->buildArray([
150150
'schema' => $this->schema,
151+
'example' => $this->example,
151152
'examples' => $this->examples,
152153
'encoding' => $this->encoding,
153-
]);
154-
155-
if ($this->hasExample) {
156-
// Insert example before examples/encoding so conventional key order
157-
// is preserved, even when the value is literal null.
158-
$reordered = [];
159-
160-
foreach ($output as $key => $value) {
161-
if (! array_key_exists('example', $reordered)
162-
&& in_array($key, ['examples', 'encoding'], true)
163-
) {
164-
$reordered['example'] = $this->example;
165-
}
166-
167-
$reordered[$key] = $value;
168-
}
169-
170-
if (! array_key_exists('example', $reordered)) {
171-
$reordered['example'] = $this->example;
172-
}
173-
174-
return $reordered;
175-
}
176-
177-
return $output;
154+
], $this->hasExample ? ['example'] : []);
178155
}
179156
}

src/Objects/Parameter.php

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ public function content(MediaType ...$content): self
197197
*/
198198
public function toArray(): array
199199
{
200-
$output = $this->buildArray([
200+
return $this->buildArray([
201201
'name' => $this->name,
202202
'in' => $this->in->value,
203203
'description' => $this->description,
@@ -207,33 +207,10 @@ public function toArray(): array
207207
'style' => $this->style,
208208
'explode' => $this->explode,
209209
'allowReserved' => $this->allowReserved,
210+
'example' => $this->example,
210211
'examples' => $this->examples,
211212
'schema' => $this->schema,
212213
'content' => $this->content,
213-
]);
214-
215-
if ($this->hasExample) {
216-
// Insert example before examples/schema/content so conventional order is preserved,
217-
// even when the example value is literal null (which buildArray would otherwise drop).
218-
$reordered = [];
219-
220-
foreach ($output as $key => $value) {
221-
if (! array_key_exists('example', $reordered)
222-
&& in_array($key, ['examples', 'schema', 'content'], true)
223-
) {
224-
$reordered['example'] = $this->example;
225-
}
226-
227-
$reordered[$key] = $value;
228-
}
229-
230-
if (! array_key_exists('example', $reordered)) {
231-
$reordered['example'] = $this->example;
232-
}
233-
234-
return $reordered;
235-
}
236-
237-
return $output;
214+
], $this->hasExample ? ['example'] : []);
238215
}
239216
}

src/Objects/PathItem.php

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -96,38 +96,20 @@ public function parameters(Parameter|Reference ...$parameters): self
9696
*/
9797
public function toArray(): array
9898
{
99-
$output = [];
100-
101-
if ($this->summary !== null) {
102-
$output['summary'] = $this->summary;
103-
}
104-
105-
if ($this->description !== null) {
106-
$output['description'] = $this->description;
107-
}
99+
$fields = [
100+
'summary' => $this->summary,
101+
'description' => $this->description,
102+
];
108103

109104
foreach ($this->operations as $method => $operation) {
110-
$output[$method] = $operation->toArray();
105+
$fields[$method] = $operation;
111106
}
112107

113-
if ($this->parameters !== []) {
114-
$output['parameters'] = array_map(
115-
fn(Parameter|Reference $parameter): array => $parameter->toArray(),
116-
$this->parameters,
117-
);
118-
}
119-
120-
if ($this->servers !== []) {
121-
$output['servers'] = array_map(
122-
fn(Server $server): array => $server->toArray(),
123-
$this->servers,
124-
);
125-
}
126-
127-
foreach ($this->getExtensions() as $key => $value) {
128-
$output[$key] = $value;
129-
}
108+
$fields['parameters'] = $this->parameters;
109+
$fields['servers'] = $this->servers;
130110

131-
return $output;
111+
// Operations are always emitted even when the underlying Operation has no
112+
// fields (e.g. Operation::post() with nothing set should still render 'post' => []).
113+
return $this->buildArray($fields, array_keys($this->operations));
132114
}
133115
}

0 commit comments

Comments
 (0)