Introducing settings file, some refactorings and stabilization

This commit is contained in:
2024-07-07 23:43:15 +08:00
parent 5666702ccc
commit 47930b010f
22 changed files with 910 additions and 328 deletions

View File

@@ -5,21 +5,19 @@ declare(strict_types=1);
namespace PmConverter\Converters\Abstract;
use Exception;
use Iterator;
use PmConverter\Collection;
use PmConverter\Converters\{
ConverterContract,
RequestContract};
use PmConverter\Converters\RequestContract;
use PmConverter\Environment;
use PmConverter\Exceptions\{
CannotCreateDirectoryException,
DirectoryIsNotWriteableException,
InvalidHttpVersionException};
use PmConverter\Exceptions\CannotCreateDirectoryException;
use PmConverter\Exceptions\DirectoryIsNotWriteableException;
use PmConverter\Exceptions\InvalidHttpVersionException;
use PmConverter\FileSystem;
/**
*
*/
abstract class AbstractConverter implements ConverterContract
abstract class AbstractConverter
{
/**
* @var Collection|null
@@ -32,53 +30,66 @@ abstract class AbstractConverter implements ConverterContract
protected string $outputPath;
/**
* @var Environment|null
* @var RequestContract[] Converted requests
*/
protected ?Environment $env = null;
protected array $requests = [];
/**
* Sets an environment with vars
* Sets output path
*
* @param Environment $env
* @param string $outputPath
* @return $this
*/
public function withEnv(Environment $env): static
public function to(string $outputPath): self
{
$this->env = $env;
$this->outputPath = sprintf('%s%s%s', $outputPath, DS, static::OUTPUT_DIR);
return $this;
}
/**
* Creates a new directory to save a converted collection into
*
* @param string $outputPath
* @return void
* @throws CannotCreateDirectoryException
* @throws DirectoryIsNotWriteableException
*/
protected function prepareOutputDir(string $outputPath): void
{
$outputPath = sprintf('%s%s%s', $outputPath, DS, static::OUTPUT_DIR);
$this->outputPath = FileSystem::makeDir($outputPath);
}
/**
* Converts collection requests
* Converts requests from collection
*
* @param Collection $collection
* @param string $outputPath
* @return void
* @return static
* @throws CannotCreateDirectoryException
* @throws DirectoryIsNotWriteableException
* @throws Exception
*/
public function convert(Collection $collection, string $outputPath): void
public function convert(Collection $collection): static
{
$this->prepareOutputDir($outputPath);
$this->collection = $collection;
$this->setVariables();
foreach ($collection->item as $item) {
$this->convertItem($item);
$this->outputPath = FileSystem::makeDir($this->outputPath);
$this->setCollectionVars();
foreach ($collection->iterate() as $path => $item) {
// $this->requests[$path][] = $this->makeRequest($item);
$this->writeRequest($this->makeRequest($item), $path);
}
return $this;
}
/**
* Returns converted requests
*
* @return Iterator<string, RequestContract>
*/
public function converted(): Iterator
{
foreach ($this->requests as $path => $requests) {
foreach ($requests as $request) {
yield $path => $request;
}
}
}
/**
* Writes requests on disk
*
* @throws Exception
*/
public function flush(): void
{
foreach ($this->converted() as $path => $request) {
$this->writeRequest($request, $path);
}
}
@@ -87,13 +98,10 @@ abstract class AbstractConverter implements ConverterContract
*
* @return $this
*/
protected function setVariables(): static
protected function setCollectionVars(): static
{
empty($this->env) && $this->env = new Environment($this->collection?->variable);
if (!empty($this->collection?->variable)) {
foreach ($this->collection->variable as $var) {
$this->env[$var->key] = $var->value;
}
foreach ($this->collection?->variable ?? [] as $var) {
Environment::instance()->setCustomVar($var->key, $var->value);
}
return $this;
}
@@ -121,30 +129,6 @@ abstract class AbstractConverter implements ConverterContract
&& empty($item->request);
}
/**
* Converts an item to request object and writes it into file
*
* @throws Exception
*/
protected function convertItem(mixed $item): void
{
if ($this->isItemFolder($item)) {
static $dir_tree;
foreach ($item->item as $subitem) {
$dir_tree[] = $item->name;
$path = implode(DS, $dir_tree);
if ($this->isItemFolder($subitem)) {
$this->convertItem($subitem);
} else {
$this->writeRequest($this->initRequest($subitem), $path);
}
array_pop($dir_tree);
}
} else {
$this->writeRequest($this->initRequest($item));
}
}
/**
* Initialiazes request object to be written in file
*
@@ -152,17 +136,18 @@ abstract class AbstractConverter implements ConverterContract
* @return RequestContract
* @throws InvalidHttpVersionException
*/
protected function initRequest(object $item): RequestContract
protected function makeRequest(object $item): RequestContract
{
$request_class = static::REQUEST_CLASS;
/** @var RequestContract $request */
$request = new $request_class();
$request->setName($item->name);
$request->setVersion($this->collection->version);
$request->setHttpVersion(1.1); //TODO http version?
$request->setDescription($item->request?->description ?? null);
$request->setVerb($item->request->method);
$request->setUrl($item->request->url->raw);
$request->setUrl($item->request->url);
$request->setHeaders($item->request->header);
$request->setAuth($item->request?->auth ?? $this->collection?->auth ?? null);
if ($item->request->method !== 'GET' && !empty($item->request->body)) {
@@ -196,18 +181,9 @@ abstract class AbstractConverter implements ConverterContract
*/
protected function interpolate(string $content): string
{
if (!$this->env?->hasVars()) {
return $content;
}
$matches = [];
if (preg_match_all('/\{\{.*}}/m', $content, $matches, PREG_PATTERN_ORDER) > 0) {
foreach ($matches[0] as $key => $var) {
if (str_contains($content, $var)) {
$content = str_replace($var, $this->env[$var] ?: $var, $content);
unset($matches[0][$key]);
}
}
}
return $content;
$replace = static fn ($a) => Environment::instance()->var($var = $a[0]) ?: $var;
return Environment::instance()->hasVars()
? preg_replace_callback('/\{\{.*}}/m', $replace, $content)
: $content;
}
}

View File

@@ -4,10 +4,10 @@ declare(strict_types=1);
namespace PmConverter\Converters\Abstract;
use PmConverter\CollectionVersion;
use PmConverter\Converters\RequestContract;
use PmConverter\Exceptions\{
EmptyHttpVerbException,
InvalidHttpVersionException};
use PmConverter\Exceptions\EmptyHttpVerbException;
use PmConverter\Exceptions\InvalidHttpVersionException;
use PmConverter\HttpVersion;
use Stringable;
@@ -22,9 +22,9 @@ abstract class AbstractRequest implements Stringable, RequestContract
protected string $verb;
/**
* @var string URL where to send a request
* @var object|string URL where to send a request
*/
protected string $url;
protected object|string $url;
/**
* @var float HTTP protocol version
@@ -56,6 +56,15 @@ abstract class AbstractRequest implements Stringable, RequestContract
*/
protected string $bodymode = 'raw';
protected CollectionVersion $version;
public function setVersion(CollectionVersion $version): static
{
$this->version = $version;
return $this;
}
/**
* @inheritDoc
*/
@@ -133,7 +142,7 @@ abstract class AbstractRequest implements Stringable, RequestContract
/**
* @inheritDoc
*/
public function setUrl(string $url): static
public function setUrl(object|string $url): static
{
$this->url = $url;
return $this;
@@ -142,9 +151,9 @@ abstract class AbstractRequest implements Stringable, RequestContract
/**
* @inheritDoc
*/
public function getUrl(): string
public function getRawUrl(): string
{
return $this->url ?: '<empty url>';
return is_object($this->url) ? $this->url->raw : $this->url;
}
/**
@@ -186,7 +195,11 @@ abstract class AbstractRequest implements Stringable, RequestContract
if (!empty($auth)) {
switch ($auth->type) {
case 'bearer':
$this->setHeader('Authorization', 'Bearer ' . $auth->{$auth->type}[0]->value);
$this->setHeader('Authorization', 'Bearer ' . match ($this->version) {
CollectionVersion::Version20 => $auth->{$auth->type}->token,
CollectionVersion::Version21 => $auth->{$auth->type}[0]->value,
default => null
});
break;
default:
break;

View File

@@ -5,12 +5,11 @@ declare(strict_types=1);
namespace PmConverter\Converters;
use PmConverter\Converters\{
Curl\CurlConverter,
Http\HttpConverter,
Postman20\Postman20Converter,
Postman21\Postman21Converter,
Wget\WgetConverter};
use PmConverter\Converters\Curl\CurlConverter;
use PmConverter\Converters\Http\HttpConverter;
use PmConverter\Converters\Postman20\Postman20Converter;
use PmConverter\Converters\Postman21\Postman21Converter;
use PmConverter\Converters\Wget\WgetConverter;
enum ConvertFormat: string
{
@@ -19,4 +18,26 @@ enum ConvertFormat: string
case Wget = WgetConverter::class;
case Postman20 = Postman20Converter::class;
case Postman21 = Postman21Converter::class;
public static function fromArg(string $arg): self
{
return match ($arg) {
'http' => ConvertFormat::Http,
'curl' => ConvertFormat::Curl,
'wget' => ConvertFormat::Wget,
'v2.0' => ConvertFormat::Postman20,
'v2.1' => ConvertFormat::Postman21,
};
}
public function toArg(): string
{
return match ($this) {
ConvertFormat::Http => 'http',
ConvertFormat::Curl => 'curl',
ConvertFormat::Wget => 'wget',
ConvertFormat::Postman20 => 'v2.0',
ConvertFormat::Postman21 => 'v2.1',
};
}
}

View File

@@ -4,11 +4,9 @@ declare(strict_types=1);
namespace PmConverter\Converters\Curl;
use PmConverter\Converters\{
Abstract\AbstractConverter,
ConverterContract};
use PmConverter\Converters\Abstract\AbstractConverter;
class CurlConverter extends AbstractConverter implements ConverterContract
class CurlConverter extends AbstractConverter
{
protected const FILE_EXT = 'sh';

View File

@@ -72,7 +72,7 @@ class CurlRequest extends AbstractRequest
"curl \ ",
"\t--http1.1 \ ", //TODO proto
"\t--request $this->verb \ ",
"\t--location $this->url \ ",
"\t--location {$this->getRawUrl()} \ ",
],
$this->prepareHeaders(),
$this->prepareBody()

View File

@@ -4,11 +4,9 @@ declare(strict_types=1);
namespace PmConverter\Converters\Http;
use PmConverter\Converters\{
Abstract\AbstractConverter,
ConverterContract};
use PmConverter\Converters\Abstract\AbstractConverter;
class HttpConverter extends AbstractConverter implements ConverterContract
class HttpConverter extends AbstractConverter
{
protected const FILE_EXT = 'http';

View File

@@ -5,8 +5,7 @@ declare(strict_types=1);
namespace PmConverter\Converters\Http;
use PmConverter\Converters\Abstract\AbstractRequest;
use PmConverter\Exceptions\{
EmptyHttpVerbException};
use PmConverter\Exceptions\EmptyHttpVerbException;
/**
* Class to determine file content with http request format
@@ -29,7 +28,7 @@ class HttpRequest extends AbstractRequest
*/
protected function prepareHeaders(): array
{
$output[] = sprintf('%s %s HTTP/%s', $this->getVerb(), $this->getUrl(), $this->getHttpVersion());
$output[] = sprintf('%s %s HTTP/%s', $this->getVerb(), $this->getRawUrl(), $this->getHttpVersion());
foreach ($this->headers as $name => $data) {
$output[] = sprintf('%s%s: %s', $data['disabled'] ? '# ' : '', $name, $data['value']);
}

View File

@@ -6,9 +6,7 @@ namespace PmConverter\Converters\Postman20;
use PmConverter\Collection;
use PmConverter\CollectionVersion;
use PmConverter\Converters\{
Abstract\AbstractConverter,
ConverterContract};
use PmConverter\Converters\Abstract\AbstractConverter;
use PmConverter\Exceptions\CannotCreateDirectoryException;
use PmConverter\Exceptions\DirectoryIsNotWriteableException;
use PmConverter\FileSystem;
@@ -16,7 +14,7 @@ use PmConverter\FileSystem;
/**
* Converts Postman Collection v2.1 to v2.0
*/
class Postman20Converter extends AbstractConverter implements ConverterContract
class Postman20Converter extends AbstractConverter
{
protected const FILE_EXT = 'v20.postman_collection.json';
@@ -26,25 +24,25 @@ class Postman20Converter extends AbstractConverter implements ConverterContract
* Converts collection requests
*
* @param Collection $collection
* @param string $outputPath
* @return void
* @return static
* @throws CannotCreateDirectoryException
* @throws DirectoryIsNotWriteableException
*/
public function convert(Collection $collection, string $outputPath): void
public function convert(Collection $collection): static
{
$this->collection = $collection;
// if data was exported from API, here is already valid json to
// just flush it in file, otherwise we need to convert it deeper
if ($this->collection->version() === CollectionVersion::Version21) {
if ($this->collection->version === CollectionVersion::Version21) {
$this->collection->info->schema = str_replace('/v2.1.', '/v2.0.', $this->collection->info->schema);
$this->convertAuth($this->collection->raw());
foreach ($this->collection->item as $item) {
$this->convertItem($item);
}
}
$this->prepareOutputDir($outputPath);
$this->outputPath = FileSystem::makeDir($this->outputPath);
$this->writeCollection();
return $this;
}
/**
@@ -97,11 +95,11 @@ class Postman20Converter extends AbstractConverter implements ConverterContract
if (empty($request->auth)) {
return;
}
$type = $request->auth->type;
if ($type !== 'noauth' && is_array($request->auth->$type)) {
$auth = [];
$auth = ['type' => 'noauth'];
$type = strtolower($request->auth->type);
if ($type !== 'noauth') {
foreach ($request->auth->$type as $param) {
$auth[$param->key] = $param->value;
$auth[$param->key] = $param->value ?? '';
}
$request->auth->$type = (object)$auth;
}

View File

@@ -6,9 +6,7 @@ namespace PmConverter\Converters\Postman21;
use PmConverter\Collection;
use PmConverter\CollectionVersion;
use PmConverter\Converters\{
Abstract\AbstractConverter,
ConverterContract};
use PmConverter\Converters\Abstract\AbstractConverter;
use PmConverter\Exceptions\CannotCreateDirectoryException;
use PmConverter\Exceptions\DirectoryIsNotWriteableException;
use PmConverter\FileSystem;
@@ -16,7 +14,7 @@ use PmConverter\FileSystem;
/**
* Converts Postman Collection v2.0 to v2.1
*/
class Postman21Converter extends AbstractConverter implements ConverterContract
class Postman21Converter extends AbstractConverter
{
protected const FILE_EXT = 'v21.postman_collection.json';
@@ -26,25 +24,25 @@ class Postman21Converter extends AbstractConverter implements ConverterContract
* Converts collection requests
*
* @param Collection $collection
* @param string $outputPath
* @return void
* @return static
* @throws CannotCreateDirectoryException
* @throws DirectoryIsNotWriteableException
*/
public function convert(Collection $collection, string $outputPath): void
public function convert(Collection $collection): static
{
$this->collection = $collection;
// if data was exported from API, here is already valid json to
// just flush it in file, otherwise we need to convert it deeper
if ($this->collection->version() === CollectionVersion::Version20) {
if ($this->collection->version === CollectionVersion::Version20) {
$this->collection->info->schema = str_replace('/v2.0.', '/v2.1.', $this->collection->info->schema);
$this->convertAuth($this->collection->raw());
foreach ($this->collection->item as $item) {
$this->convertItem($item);
}
}
$this->prepareOutputDir($outputPath);
$this->outputPath = FileSystem::makeDir($this->outputPath);
$this->writeCollection();
return $this;
}
/**

View File

@@ -86,7 +86,7 @@ interface RequestContract
*
* @return string
*/
public function getUrl(): string;
public function getRawUrl(): string;
/**
* Sets headers from collection item to request object
@@ -116,7 +116,7 @@ interface RequestContract
/**
* Sets authorization headers
*
* @param object|null $auth
* @param object $auth
* @return $this
*/
public function setAuth(object $auth): static;

View File

@@ -4,11 +4,9 @@ declare(strict_types=1);
namespace PmConverter\Converters\Wget;
use PmConverter\Converters\{
Abstract\AbstractConverter,
ConverterContract};
use PmConverter\Converters\Abstract\AbstractConverter;
class WgetConverter extends AbstractConverter implements ConverterContract
class WgetConverter extends AbstractConverter
{
protected const FILE_EXT = 'sh';

View File

@@ -77,16 +77,16 @@ class WgetRequest extends AbstractRequest
if ($this->getBodymode() === 'formdata') {
if ($this->getBody()) {
if ($this->getVerb() === 'GET') {
$output[] = sprintf("\t%s?%s", $this->getUrl(), http_build_query($this->prepareBody()));
$output[] = sprintf("\t%s?%s", $this->getRawUrl(), http_build_query($this->prepareBody()));
} else {
$output[] = sprintf("\t--body-data '%s' \ ", http_build_query($this->prepareBody()));
$output[] = sprintf("\t%s", $this->getUrl());
$output[] = sprintf("\t%s", $this->getRawUrl());
}
}
} else {
if ($this->getVerb() !== 'GET') {
$output[] = sprintf("\t--body-data '%s' \ ", implode("\n", $this->prepareBody()));
$output[] = sprintf("\t%s", $this->getUrl());
$output[] = sprintf("\t%s", $this->getRawUrl());
}
}
return implode(EOL, array_merge($output, ['']));