Skip to content

Commit

Permalink
added an api to traverse an openapi document
Browse files Browse the repository at this point in the history
  • Loading branch information
romalytvynenko committed Jun 4, 2024
1 parent 2106fc6 commit 921cc6c
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 10 deletions.
14 changes: 14 additions & 0 deletions src/AbstractOpenAPIObjectVisitor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Dedoc\Scramble;

class AbstractOpenAPIObjectVisitor implements OpenAPIObjectVisitor
{
public function enter(mixed $object, array $path = [])
{
}

public function leave(mixed $object, array $path = [])
{
}
}
22 changes: 22 additions & 0 deletions src/OpenAPIObjectVisitor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Dedoc\Scramble;

interface OpenAPIObjectVisitor
{
/**
* Called when entering an object for traversal.
*
* @param mixed $object OpenAPI object being entered for traversal.
* @param (string|int)[] $path The path from the root to the object being entered. When an object is a part of an array, its index is used.
*/
public function enter(mixed $object, array $path = []);

/**
* Called when completed traversing an object.
*
* @param mixed $object OpenAPI object being left after traversal.
* @param (string|int)[] $path The path from the root to the object being left. When an object is a part of an array, its index is used.
*/
public function leave(mixed $object, array $path = []);
}
20 changes: 10 additions & 10 deletions src/OpenAPITraverser.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,42 @@ public function __construct(
) {
}

public function traverse($type): void
public function traverse($type, $path = ['#']): void
{
if (is_scalar($type) || $type === null) {
return;
}

$this->enterType($type);
$this->enterType($type, $path);

$propertiesWithNodes = $this->getNodes($type);

foreach ($propertiesWithNodes as $propertyWithNode) {
$node = $type->$propertyWithNode;

if (! is_array($node)) {
$this->traverse($node);
$this->traverse($node, [...$path, $propertyWithNode]);
} else {
foreach ($node as $item) {
$this->traverse($item);
foreach ($node as $i => $item) {
$this->traverse($item, [...$path, $propertyWithNode, $i]);
}
}
}

$this->leaveType($type);
$this->leaveType($type, $path);
}

private function enterType($type): void
private function enterType($type, $path): void
{
foreach ($this->visitors as $visitor) {
$visitor->enter($type);
$visitor->enter($type, $path);
}
}

private function leaveType($type): void
private function leaveType($type, $path): void
{
foreach ($this->visitors as $visitor) {
$visitor->leave($type);
$visitor->leave($type, $path);
}
}

Expand Down
35 changes: 35 additions & 0 deletions tests/OpenAPITraverserTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

use Dedoc\Scramble\AbstractOpenAPIObjectVisitor;
use Dedoc\Scramble\Support\Generator\InfoObject;
use Dedoc\Scramble\Support\Generator\OpenApi;
use Dedoc\Scramble\Support\Generator\Operation;
use Dedoc\Scramble\Support\Generator\Path;

it('traverses open api document', function () {
$document = new OpenApi(version: '3.1.0');
$document->setInfo(new InfoObject(title: 'app'));
$document->addPath($path = new Path('/test'));
$path->addOperation(new Operation('GET'));

$traverser = new \Dedoc\Scramble\OpenAPITraverser([
$visitor = new class extends AbstractOpenAPIObjectVisitor {
public array $paths = [];
/** @inheritdoc */
public function enter($object, $path = [])
{
$this->paths[] = join('.', $path);
}
}
]);

$traverser->traverse($document);

expect($visitor->paths)->toBe([
'#',
'#.info',
'#.components',
'#.paths.0',
'#.paths.0.operations.GET',
]);
});

0 comments on commit 921cc6c

Please sign in to comment.