4 Commits

Author SHA1 Message Date
0f95fab755 WIP 2026-04-08 17:40:06 +08:00
a2cc18a434 Misc 2024-11-09 19:05:37 +08:00
58e6157f40 Some refactorings related to main Processor class 2024-08-09 12:21:39 +08:00
2bf9345f69 Minimum version php8.1 => 8.2 + dev-dependecies updated 2024-08-04 23:17:04 +08:00
25 changed files with 1339 additions and 723 deletions

3
.gitignore vendored
View File

@@ -1,5 +1,8 @@
/.idea /.idea
/.vscode /.vscode
/vendor /vendor
/nbproject
/tmp
.phpunit.result.cache .phpunit.result.cache
.phpunit.cache .phpunit.cache

View File

@@ -70,7 +70,7 @@ Possible ARGUMENTS:
-p, --preserve - do not delete OUTPUT_PATH (if exists) -p, --preserve - do not delete OUTPUT_PATH (if exists)
--dump - convert provided arguments into settings file in `pwd` --dump - convert provided arguments into settings file in `pwd`
-h, --help - show this help message and exit -h, --help - show this help message and exit
-v, --version - show version info and exit --version - show version info and exit
If no ARGUMENTS passed then --help implied. If no ARGUMENTS passed then --help implied.
If both -f and -d are specified then only unique set of files from both arguments will be converted. If both -f and -d are specified then only unique set of files from both arguments will be converted.

View File

@@ -12,7 +12,7 @@
], ],
"keywords": ["postman", "collection", "converter", "http", "wget", "curl", "api", "convert"], "keywords": ["postman", "collection", "converter", "http", "wget", "curl", "api", "convert"],
"require": { "require": {
"php": "^8.1", "php": "^8.4",
"ext-json": "*", "ext-json": "*",
"ext-mbstring": "*", "ext-mbstring": "*",
"ext-readline": "*" "ext-readline": "*"
@@ -32,6 +32,6 @@
"sort-packages": true "sort-packages": true
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^10.3" "phpunit/phpunit": "^12.5"
} }
} }

773
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,10 +2,12 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
use PmConverter\Handler;
const EOL = PHP_EOL; const EOL = PHP_EOL;
const DS = DIRECTORY_SEPARATOR; const DS = DIRECTORY_SEPARATOR;
use PmConverter\Processor; const PM_VERSION = '1.8';
$paths = [ $paths = [
__DIR__ . '/../../autoload.php', __DIR__ . '/../../autoload.php',
@@ -22,14 +24,13 @@ foreach ($paths as $path) {
is_null($file) && throw new RuntimeException('Unable to locate autoload.php file.'); is_null($file) && throw new RuntimeException('Unable to locate autoload.php file.');
$processor = new Processor($argv); $handler = new Handler();
$handler::printVersion();
$handler::printCopyright();
try { try {
$processor->handle(); $handler->init($argv);
} catch (InvalidArgumentException $e) { $handler->start();
fwrite(STDERR, sprintf('ERROR: %s%s', $e->getMessage(), EOL));
print(implode(EOL, Processor::usage()));
die(1);
} catch (Exception $e) { } catch (Exception $e) {
fwrite(STDERR, sprintf('ERROR: %s%s', $e->getMessage(), EOL)); fwrite(STDERR, sprintf('ERROR: %s%s', $e->getMessage(), EOL));
die(1); exit(1);
} }

10
pm-convert-settings.json Normal file
View File

@@ -0,0 +1,10 @@
{
"directories": [
"tmp"
],
"output": "tmp/output",
"preserveOutput": false,
"formats": [
"opencollection"
]
}

183
src/ArgumentParser.php Normal file
View File

@@ -0,0 +1,183 @@
<?php
declare(strict_types=1);
namespace PmConverter;
use InvalidArgumentException;
use PmConverter\Converters\ConvertFormat;
use PmConverter\Enums\ArgumentNames as AN;
class ArgumentParser
{
/**
* @var array Raw arguments passed from cli ($argv)
*/
protected readonly array $raw;
/**
* @var array Parsed and ready to use
*/
protected ?array $parsed = null;
/**
* Constructor
*
* @param array $argv Raw arguments passed from cli ($argv)
*/
public function __construct(array $argv)
{
$this->raw = array_slice($argv, 1);
}
/**
* Parses raw arguments
*
* @return array Settings according to settings file format
*/
public function parse(): array
{
foreach ($this->raw as $idx => $arg) {
switch ($arg) {
case '-c':
case '--config':
if (empty($this->raw[$idx + 1])) {
throw new InvalidArgumentException('a configuration file path is expected for -c (--config)');
}
if (isset($this->parsed[AN::Config])) {
printf(
"INFO: Config file is already set to '%s' and will be overwritten to '%s'",
$this->parsed[AN::Config],
$this->raw[$idx + 1],
);
}
$this->parsed[AN::Config] = $this->raw[$idx + 1];
break;
case '-d':
case '--dir':
if (empty($this->raw[$idx + 1])) {
throw new InvalidArgumentException('a directory path is expected for -d (--dir)');
}
$this->parsed[AN::Directories][] = $this->raw[$idx + 1];
break;
case '-f':
case '--file':
if (empty($this->raw[$idx + 1])) {
throw new InvalidArgumentException('a directory path is expected for -f (--file)');
}
$this->parsed[AN::Files][] = $this->raw[$idx + 1];
break;
case '-e':
case '--env':
if (empty($this->raw[$idx + 1])) {
throw new InvalidArgumentException('an environment file path is expected for -e (--env)');
}
$this->parsed[AN::Environment][] = $this->raw[$idx + 1];
break;
case '-o':
case '--output':
if (empty($this->raw[$idx + 1])) {
throw new InvalidArgumentException('an output path is expected for -o (--output)');
}
$this->parsed[AN::Output][] = $this->raw[$idx + 1];
break;
case '-p':
case '--preserve':
$this->parsed[AN::PreserveOutput] = true;
break;
case '--http':
$this->parsed[AN::Formats][] = ConvertFormat::Http;
break;
case '--curl':
$this->parsed[AN::Formats][] = ConvertFormat::Curl;
break;
case '--wget':
$this->parsed[AN::Formats][] = ConvertFormat::Wget;
break;
case '--openc':
case '--opencollection':
$this->parsed[AN::Formats][] = ConvertFormat::OpenCollection;
break;
case '--v2.0':
$this->parsed[AN::Formats][] = ConvertFormat::Postman20;
break;
case '--v2.1':
$this->parsed[AN::Formats][] = ConvertFormat::Postman21;
break;
case '-a':
case '--all':
foreach (ConvertFormat::cases() as $format) {
$this->parsed[AN::Formats][] = $format;
}
break;
case '--var':
$definition = trim($this->raw[$idx + 1]);
$name = strtok($definition, '='); // take first part before equal sign as var name
$value = strtok(''); // take the rest of argument as var value
if (isset($this->parsed[AN::Vars][$name])) {
printf(
"INFO: Variable '%s' is already set to '%s' and will be overwritten to '%s'",
$name,
$this->parsed[AN::Vars][$name],
$value,
);
}
$this->parsed[AN::Vars][$name] = $value;
break;
case '--dev':
$this->parsed[AN::DevMode] = true;
break;
case '-v':
case '--verbose':
$this->parsed[AN::Verbose] = true;
break;
case '--dump':
$this->parsed[AN::Dump] = true;
break;
case '--version':
$this->parsed[AN::Version] = true;
break;
case '-h':
case '--help':
$this->parsed[AN::Help] = true;
break;
}
}
foreach ([AN::Directories, AN::Files, AN::Formats] as $field) {
if (!empty($this->parsed[$field])) {
$this->parsed[$field] = array_unique($this->parsed[$field] ?? []);
}
}
return $this->parsed ?? [];
}
/**
* Returns parsed arguments (if set) or parses raw ones
*
* @return array
*/
public function parsed(): array
{
return $this->parsed ??= $this->parse();
}
}

View File

@@ -7,6 +7,7 @@ namespace PmConverter;
use Exception; use Exception;
use Generator; use Generator;
use JsonException; use JsonException;
use PmConverter\Enums\CollectionVersion;
use Stringable; use Stringable;
/** /**
@@ -111,26 +112,23 @@ class Collection implements Stringable
*/ */
public static function detectFileVersion(string $filepath): CollectionVersion public static function detectFileVersion(string $filepath): CollectionVersion
{ {
$handle = fopen($filepath, 'r'); $content = file_get_contents($filepath);
if ($handle === false) {
throw new Exception("Cannot open file for reading: $filepath"); if ($content === false) {
throw new Exception("cannot read file: $filepath");
} }
$content = '';
// Postman collection files may be HUGE and I don't need to parse $json = json_decode($content, true, flags: JSON_THROW_ON_ERROR);
// them here to find value .info.schema field because normally it $schema = $json['info']['schema'] ?? '';
// is stored at the beginning of a file, so if it's not then this
// is a user problem, not mine. if (str_ends_with($schema, 'v2.0.0/collection.json')) {
while (\mb_strlen($content) <= 2048) {
$content .= fgets($handle, 50);
if (str_contains($content, 'https://schema.getpostman.com/json/collection')) {
if (str_contains($content, '/v2.0.')) {
return CollectionVersion::Version20; return CollectionVersion::Version20;
} }
if (str_contains($content, '/v2.1.')) {
if (str_ends_with($schema, 'v2.1.0/collection.json')) {
return CollectionVersion::Version21; return CollectionVersion::Version21;
} }
}
}
return CollectionVersion::Unknown; return CollectionVersion::Unknown;
} }

View File

@@ -62,7 +62,8 @@ abstract class AbstractConverter
$this->setCollectionVars(); $this->setCollectionVars();
foreach ($collection->iterate() as $path => $item) { foreach ($collection->iterate() as $path => $item) {
// $this->requests[$path][] = $this->makeRequest($item); // $this->requests[$path][] = $this->makeRequest($item);
$this->writeRequest($this->makeRequest($item), $path); $request = $this->makeRequest($item);
$this->writeRequest($request, $path);
} }
return $this; return $this;
} }
@@ -103,6 +104,7 @@ abstract class AbstractConverter
foreach ($this->collection?->variable ?? [] as $var) { foreach ($this->collection?->variable ?? [] as $var) {
Environment::instance()->setCustomVar($var->key, $var->value); Environment::instance()->setCustomVar($var->key, $var->value);
} }
return $this; return $this;
} }

View File

@@ -4,11 +4,11 @@ declare(strict_types=1);
namespace PmConverter\Converters\Abstract; namespace PmConverter\Converters\Abstract;
use PmConverter\CollectionVersion;
use PmConverter\Converters\RequestContract; use PmConverter\Converters\RequestContract;
use PmConverter\Enums\CollectionVersion;
use PmConverter\Enums\HttpVersion;
use PmConverter\Exceptions\EmptyHttpVerbException; use PmConverter\Exceptions\EmptyHttpVerbException;
use PmConverter\Exceptions\InvalidHttpVersionException; use PmConverter\Exceptions\InvalidHttpVersionException;
use PmConverter\HttpVersion;
use Stringable; use Stringable;
/** /**

View File

@@ -7,6 +7,7 @@ namespace PmConverter\Converters;
use PmConverter\Converters\Curl\CurlConverter; use PmConverter\Converters\Curl\CurlConverter;
use PmConverter\Converters\Http\HttpConverter; use PmConverter\Converters\Http\HttpConverter;
use PmConverter\Converters\OpenCollection\OpenCollectionConverter;
use PmConverter\Converters\Postman20\Postman20Converter; use PmConverter\Converters\Postman20\Postman20Converter;
use PmConverter\Converters\Postman21\Postman21Converter; use PmConverter\Converters\Postman21\Postman21Converter;
use PmConverter\Converters\Wget\WgetConverter; use PmConverter\Converters\Wget\WgetConverter;
@@ -16,6 +17,7 @@ enum ConvertFormat: string
case Http = HttpConverter::class; case Http = HttpConverter::class;
case Curl = CurlConverter::class; case Curl = CurlConverter::class;
case Wget = WgetConverter::class; case Wget = WgetConverter::class;
case OpenCollection = OpenCollectionConverter::class;
case Postman20 = Postman20Converter::class; case Postman20 = Postman20Converter::class;
case Postman21 = Postman21Converter::class; case Postman21 = Postman21Converter::class;
@@ -25,6 +27,7 @@ enum ConvertFormat: string
'http' => ConvertFormat::Http, 'http' => ConvertFormat::Http,
'curl' => ConvertFormat::Curl, 'curl' => ConvertFormat::Curl,
'wget' => ConvertFormat::Wget, 'wget' => ConvertFormat::Wget,
'opencollection' => ConvertFormat::OpenCollection,
'v2.0' => ConvertFormat::Postman20, 'v2.0' => ConvertFormat::Postman20,
'v2.1' => ConvertFormat::Postman21, 'v2.1' => ConvertFormat::Postman21,
}; };
@@ -36,6 +39,7 @@ enum ConvertFormat: string
ConvertFormat::Http => 'http', ConvertFormat::Http => 'http',
ConvertFormat::Curl => 'curl', ConvertFormat::Curl => 'curl',
ConvertFormat::Wget => 'wget', ConvertFormat::Wget => 'wget',
ConvertFormat::OpenCollection => 'opencollection',
ConvertFormat::Postman20 => 'v2.0', ConvertFormat::Postman20 => 'v2.0',
ConvertFormat::Postman21 => 'v2.1', ConvertFormat::Postman21 => 'v2.1',
}; };

View File

@@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
namespace PmConverter\Converters\OpenCollection;
use PmConverter\Collection;
use PmConverter\Converters\Abstract\AbstractConverter;
use PmConverter\FileSystem;
class OpenCollectionConverter extends AbstractConverter
{
protected const FILE_EXT = 'yml';
protected const OUTPUT_DIR = 'opencollection';
protected const REQUEST_CLASS = OpenCollectionRequest::class;
/**
* @inheritDoc
*/
public function convert(Collection $collection): static
{
$this->collection = $collection;
$this->outputPath = FileSystem::makeDir($this->outputPath);
$this->setCollectionVars();
// Write main collection file
$this->writeCollectionFile($collection);
foreach ($collection->iterate() as $path => $item) {
$request = $this->makeRequest($item);
$this->writeRequest($request, $path);
}
return $this;
}
/**
* Writes main OpenCollection collection file
*
* @param Collection $collection
* @return void
*/
protected function writeCollectionFile(Collection $collection): void
{
$filepath = sprintf('%s%scollection.%s', $this->outputPath, DS, static::FILE_EXT);
$content = $this->generateCollectionContent($collection);
file_put_contents($filepath, $content);
}
/**
* Generates collection YAML content
*
* @param Collection $collection
* @return string
*/
protected function generateCollectionContent(Collection $collection): string
{
$output = [
'name: ' . ($collection->name ?? 'Untitled Collection'),
'type: collection',
'',
];
if (!empty($collection->info?->description)) {
$output[] = 'description: |';
$output[] = ' ' . str_replace("\n", "\n ", $collection->info->description);
$output[] = '';
}
$output[] = 'version: 1';
$output[] = '';
$output[] = 'baseVars: []';
$output[] = '';
$output[] = 'environments: []';
$output[] = '';
$output[] = 'requests:';
foreach ($collection->iterate() as $path => $item) {
$requestRef = str_replace(DS, '/', $path . '/' . $item->name);
$output[] = ' - $ref: ./' . $requestRef . '.yml';
}
return implode("\n", $output);
}
}

View File

@@ -0,0 +1,112 @@
<?php
declare(strict_types=1);
namespace PmConverter\Converters\OpenCollection;
use PmConverter\Converters\Abstract\AbstractRequest;
use PmConverter\Exceptions\EmptyHttpVerbException;
/**
* Class to determine file content with OpenCollection format
*/
class OpenCollectionRequest extends AbstractRequest
{
/**
* @inheritDoc
*/
protected function prepareDescription(): array
{
return empty($this->description)
? []
: ['description: |', ' ' . str_replace("\n", "\n ", $this->description), ''];
}
/**
* @inheritDoc
* @throws EmptyHttpVerbException
*/
protected function prepareHeaders(): array
{
$output = ['headers:'];
foreach ($this->headers as $name => $data) {
$prefix = $data['disabled'] ? '# ' : '';
$output[] = sprintf('%s %s: %s', $prefix, $name, $data['value']);
}
return $output;
}
/**
* @inheritDoc
*/
protected function prepareBody(): array
{
$output = ['body:'];
switch ($this->getBodymode()) {
case 'formdata':
$output[] = ' type: formdata';
$output[] = ' files:';
foreach ($this->body as $key => $data) {
$disabled = $data['disabled'] ?? false;
$prefix = $disabled ? '# ' : ' ';
if ($data['type'] === 'file') {
$output[] = sprintf('%s- name: %s', $prefix, $key);
$output[] = sprintf('%s type: file', $prefix);
$output[] = sprintf('%s value: %s', $prefix, $data['value']);
} else {
$output[] = sprintf('%s- name: %s', $prefix, $key);
$output[] = sprintf('%s type: text', $prefix);
$output[] = sprintf('%s value: %s', $prefix, $data['value']);
}
}
break;
default:
$output[] = ' type: raw';
if (!empty($this->body)) {
$output[] = ' content: |';
$bodyContent = is_string($this->body) ? $this->body : json_encode($this->body, JSON_PRETTY_PRINT);
foreach (explode("\n", $bodyContent) as $line) {
$output[] = ' ' . $line;
}
}
break;
}
return $output;
}
/**
* @inheritDoc
* @throws EmptyHttpVerbException
*/
public function __toString(): string
{
$output = [
'name: ' . $this->getName(),
'type: request',
'',
];
$output[] = 'method: ' . strtolower($this->getVerb());
$output[] = '';
$url = $this->getRawUrl();
$output[] = 'url: ' . $url;
$output[] = '';
$output = array_merge($output, $this->prepareDescription());
if (!empty($this->headers)) {
$output = array_merge($output, $this->prepareHeaders());
$output[] = '';
}
if ($this->verb !== 'GET' && !empty($this->body)) {
$output = array_merge($output, $this->prepareBody());
$output[] = '';
}
return implode("\n", $output);
}
}

View File

@@ -5,8 +5,8 @@ declare(strict_types=1);
namespace PmConverter\Converters\Postman20; namespace PmConverter\Converters\Postman20;
use PmConverter\Collection; use PmConverter\Collection;
use PmConverter\CollectionVersion;
use PmConverter\Converters\Abstract\AbstractConverter; use PmConverter\Converters\Abstract\AbstractConverter;
use PmConverter\Enums\CollectionVersion;
use PmConverter\Exceptions\CannotCreateDirectoryException; use PmConverter\Exceptions\CannotCreateDirectoryException;
use PmConverter\Exceptions\DirectoryIsNotWriteableException; use PmConverter\Exceptions\DirectoryIsNotWriteableException;
use PmConverter\FileSystem; use PmConverter\FileSystem;

View File

@@ -5,8 +5,8 @@ declare(strict_types=1);
namespace PmConverter\Converters\Postman21; namespace PmConverter\Converters\Postman21;
use PmConverter\Collection; use PmConverter\Collection;
use PmConverter\CollectionVersion;
use PmConverter\Converters\Abstract\AbstractConverter; use PmConverter\Converters\Abstract\AbstractConverter;
use PmConverter\Enums\CollectionVersion;
use PmConverter\Exceptions\CannotCreateDirectoryException; use PmConverter\Exceptions\CannotCreateDirectoryException;
use PmConverter\Exceptions\DirectoryIsNotWriteableException; use PmConverter\Exceptions\DirectoryIsNotWriteableException;
use PmConverter\FileSystem; use PmConverter\FileSystem;

View File

@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace PmConverter\Enums;
/**
* Argument names
*/
class ArgumentNames
{
public const Config = 'config';
public const Directories = 'directories';
public const Files = 'files';
public const Environment = 'environment';
public const Output = 'output';
public const PreserveOutput = 'preserveOutput';
public const Formats = 'formats';
public const Vars = 'vars';
public const DevMode = 'devMode';
public const Verbose = 'verbose';
public const Dump = 'dump';
public const Version = 'version';
public const Help = 'help';
}

View File

@@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace PmConverter; namespace PmConverter\Enums;
enum CollectionVersion: string enum CollectionVersion: string
{ {

View File

@@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace PmConverter; namespace PmConverter\Enums;
enum HttpVersion: string enum HttpVersion: string
{ {

View File

@@ -38,11 +38,11 @@ class Environment implements ArrayAccess
} }
/** /**
* @param string $filepath * @param string|null $filepath
* @return $this * @return $this
* @throws JsonException * @throws JsonException
*/ */
public function readFromFile(string $filepath): static public function readFromFile(?string $filepath): static
{ {
if (empty($filepath)) { if (empty($filepath)) {
return $this; return $this;

View File

@@ -6,6 +6,7 @@ namespace PmConverter;
use Exception; use Exception;
use JsonException; use JsonException;
use PmConverter\Enums\CollectionVersion;
use PmConverter\Exceptions\CannotCreateDirectoryException; use PmConverter\Exceptions\CannotCreateDirectoryException;
use PmConverter\Exceptions\DirectoryIsNotReadableException; use PmConverter\Exceptions\DirectoryIsNotReadableException;
use PmConverter\Exceptions\DirectoryIsNotWriteableException; use PmConverter\Exceptions\DirectoryIsNotWriteableException;
@@ -24,7 +25,16 @@ class FileSystem
*/ */
public static function normalizePath(string $path): string public static function normalizePath(string $path): string
{ {
$path = str_replace('~/', "{$_SERVER['HOME']}/", $path); $path = trim($path);
if (str_starts_with($path, '~' . DS)) {
$path = str_replace('~' . DS, $_SERVER['HOME'] . DS, $path);
} elseif (str_starts_with($path, '.' . DS)) {
$path = str_replace('.' . DS, $_SERVER['PWD'] . DS, $path);
} elseif (!str_starts_with($path, DS)) {
$path = $_SERVER['PWD'] . DS . $path;
}
return rtrim($path, DS); return rtrim($path, DS);
} }
@@ -116,9 +126,11 @@ class FileSystem
*/ */
public static function isCollectionFile(string $path): bool public static function isCollectionFile(string $path): bool
{ {
return (!empty($path = static::normalizePath($path))) $path = static::normalizePath($path);
return !empty($path)
&& str_ends_with($path, '.postman_collection.json') && str_ends_with($path, '.postman_collection.json')
&& file_exists($path) && file_exists($path)
&& is_file($path)
&& is_readable($path) && is_readable($path)
&& Collection::detectFileVersion($path) !== CollectionVersion::Unknown; && Collection::detectFileVersion($path) !== CollectionVersion::Unknown;
} }

239
src/Handler.php Normal file
View File

@@ -0,0 +1,239 @@
<?php
declare(strict_types = 1);
namespace PmConverter;
use JsonException;
use PmConverter\Enums\ArgumentNames as AN;
class Handler
{
/**
* @var array Ready to use arguments
*/
protected array $arguments;
/**
* @var Settings Settings read from file and merged with provided in cli
*/
protected Settings $settings;
/**
* @var Environment Environment laoded from file with custom vars provided
*/
protected Environment $env;
/**
* @var Processor Object that do convertions according to settings
*/
protected Processor $processor;
/**
* Initializes main flow
*
* @param array $argv Raw arguments passed from cli
* @return void
* @throws JsonException
* @throws \Exception
*/
public function init(array $argv): void
{
$this->arguments = (new ArgumentParser($argv))->parsed();
if (!empty($this->arguments[AN::Help])) {
self::printHelp();
exit;
}
if (!empty($this->arguments[AN::Version])) {
self::printVersion();
exit;
}
$this->settings = new Settings();
$this->settings->loadFromFile($this->arguments[AN::Config] ?? null);
$this->settings->override($this->arguments);
if (empty($this->settings->collectionPaths())) {
throw new \Exception('at least 1 collection file must be defined');
}
if (!empty($arguments[AN::Dump])) {
$this->handleSettingsDump();
}
$this->env = Environment::instance()
->readFromFile($this->settings->envFilepath())
->setCustomVars($this->settings->vars());
}
/**
* Starts convertions
*
* @return void
* @throws Exceptions\CannotCreateDirectoryException
* @throws Exceptions\DirectoryIsNotReadableException
* @throws Exceptions\DirectoryIsNotWriteableException
* @throws Exceptions\DirectoryNotExistsException
* @throws Exceptions\IncorrectSettingsFileException
* @throws JsonException
*/
public function start(): void
{
$this->processor = new Processor($this->settings, $this->env);
$this->processor->start();
}
/**
* Handles settings file saving when requested by --dump
*
* @return never
*/
protected function handleSettingsDump(): never
{
$answer = 'o';
if ($this->settings->fileExists()) {
echo 'Settings file already exists: ' . $this->settings->filePath() . EOL;
echo 'Do you want to (o)verwrite it, (b)ackup it and create new one or (c)ancel (default)?' . EOL;
$answer = strtolower(trim(readline('> ')));
}
if (!in_array($answer, ['o', 'b'])) {
die('Current settings file has not been changed' . EOL);
}
if ($answer === 'b') {
$filepath = $this->settings->backup();
printf("Settings file has been backed up to file:%s\t%s%s", EOL, $filepath, EOL);
}
$this->settings->dump();
printf("Arguments has been converted into settings file:%s\t%s%s", EOL, $this->settings->filePath(), EOL);
die('Review and edit it if needed.' . EOL);
}
/**
* Returns usage help strings
*
* @return array
*/
protected static function help(): array
{
return array_merge(self::version(), [
'Usage:',
"\t./pm-convert -f|-d PATH -o OUTPUT_PATH [ARGUMENTS] [FORMATS]",
"\tphp pm-convert -f|-d PATH -o OUTPUT_PATH [ARGUMENTS] [FORMATS]",
"\tcomposer pm-convert -f|-d PATH -o OUTPUT_PATH [ARGUMENTS] [FORMATS]",
"\t./vendor/bin/pm-convert -f|-d PATH -o OUTPUT_PATH [ARGUMENTS] [FORMATS]",
'',
'Possible ARGUMENTS:',
"\t-f, --file - a PATH to a single collection file to convert from",
"\t-d, --dir - a PATH to a directory with collections to convert from",
"\t-o, --output - a directory OUTPUT_PATH to put results in",
"\t-e, --env - use environment file with variables to replace in requests",
"\t--var \"NAME=VALUE\" - force replace specified env variable called NAME with custom VALUE",
"\t-p, --preserve - do not delete OUTPUT_PATH (if exists)",
"\t --dump - convert provided arguments into settings file in `pwd",
"\t-h, --help - show this help message and exit",
"\t-v, --version - show version info and exit",
'',
'If no ARGUMENTS passed then --help implied.',
'If both -f and -d are specified then only unique set of files from both arguments will be converted.',
'-f or -d are required to be specified at least once, but each may be specified multiple times.',
'PATH must be a valid path to readable json-file or directory.',
'OUTPUT_PATH must be a valid path to writeable directory.',
'If -o or -e was specified several times then only last one will be used.',
'',
'Possible FORMATS:',
"\t--http - generate raw *.http files (default)",
"\t--curl - generate shell scripts with curl command",
"\t--wget - generate shell scripts with wget command",
"\t--opencollection - generate OpenCollection YAML files",
"\t--v2.0 - convert from Postman Collection Schema v2.1 into v2.0",
"\t--v2.1 - convert from Postman Collection Schema v2.0 into v2.1",
"\t-a, --all - convert to all of formats listed above",
'',
'If no FORMATS specified then --http implied.',
'Any of FORMATS can be specified at the same time or replaced by --all.',
'',
'Example:',
" ./pm-convert \ ",
" -f ~/dir1/first.postman_collection.json \ ",
" --directory ~/team \ ",
" --file ~/dir2/second.postman_collection.json \ ",
" --env ~/localhost.postman_environment.json \ ",
" -d ~/personal \ ",
" --var \"myvar=some value\" \ ",
" -o ~/postman_export \ ",
" --all",
"",
], self::copyright());
}
/**
* Prints usage help message in stdout
*
* @return void
*/
public static function printHelp(): void
{
self::printArray(self::help());
}
/**
* Returns version strings
*
* @return string[]
*/
protected static function version(): array
{
return ['Postman collection converter v' . PM_VERSION, ''];
}
/**
* Prints version message in stdout
*
* @return void
*/
public static function printVersion(): void
{
self::printArray(self::version());
}
/**
* Returns copyright strings
*
* @return string[]
*/
protected static function copyright(): array
{
return [
'Anthony Axenov (c) 2023 - ' . (int)date('Y') . ', MIT license',
'https://git.axenov.dev/anthony/pm-convert',
'',
];
}
/**
* Prints copyright message in stdout
*
* @return void
*/
public static function printCopyright(): void
{
self::printArray(self::copyright());
}
/**
* Prints an arrays of string to stdout
*
* @param ...$strings
* @return void
*/
protected static function printArray(...$strings): void
{
fwrite(STDOUT, implode("\n", array_merge(...$strings)));
}
}

View File

@@ -6,12 +6,9 @@ namespace PmConverter;
use Exception; use Exception;
use Generator; use Generator;
use InvalidArgumentException;
use JetBrains\PhpStorm\NoReturn;
use JsonException; use JsonException;
use PmConverter\Converters\Abstract\AbstractConverter; use PmConverter\Converters\Abstract\AbstractConverter;
use PmConverter\Converters\ConverterContract; use PmConverter\Converters\ConverterContract;
use PmConverter\Converters\ConvertFormat;
use PmConverter\Exceptions\CannotCreateDirectoryException; use PmConverter\Exceptions\CannotCreateDirectoryException;
use PmConverter\Exceptions\DirectoryIsNotReadableException; use PmConverter\Exceptions\DirectoryIsNotReadableException;
use PmConverter\Exceptions\DirectoryIsNotWriteableException; use PmConverter\Exceptions\DirectoryIsNotWriteableException;
@@ -19,15 +16,10 @@ use PmConverter\Exceptions\DirectoryNotExistsException;
use PmConverter\Exceptions\IncorrectSettingsFileException; use PmConverter\Exceptions\IncorrectSettingsFileException;
/** /**
* Main class * Processor class
*/ */
class Processor class Processor
{ {
/**
* Converter version
*/
public const VERSION = '1.6.1';
/** /**
* @var int Initial timestamp * @var int Initial timestamp
*/ */
@@ -38,150 +30,23 @@ class Processor
*/ */
protected readonly int $initRam; protected readonly int $initRam;
/**
* @var Settings Settings (lol)
*/
protected Settings $settings;
/** /**
* @var ConverterContract[] Converters will be used for conversion according to chosen formats * @var ConverterContract[] Converters will be used for conversion according to chosen formats
*/ */
protected array $converters = []; protected array $converters = [];
/**
* @var bool Do we need to save settings file and exit or not?
*/
protected bool $needDumpSettings = false;
/**
* @var Environment
*/
public Environment $env;
/** /**
* Constructor * Constructor
* *
* @param array $argv Arguments came from cli * @param Settings $settings Settings (lol)
* @throws IncorrectSettingsFileException * @param Environment $env Environment
* @throws JsonException
*/ */
public function __construct(protected readonly array $argv) public function __construct(
{ protected Settings $settings,
protected Environment $env,
) {
$this->initTime = hrtime(true); $this->initTime = hrtime(true);
$this->initRam = memory_get_usage(true); $this->initRam = memory_get_usage(true);
$this->settings = Settings::init();
$this->env = Environment::instance()
->readFromFile($this->settings->envFilepath())
->setCustomVars($this->settings->vars());
$this->parseArgs();
$this->needDumpSettings && $this->dumpSettingsFile();
}
/**
* Parses an array of arguments came from cli
*
* @return void
* @throws JsonException
*/
protected function parseArgs(): void
{
$arguments = array_slice($this->argv, 1);
$needHelp = count($arguments) === 0 && !$this->settings::fileExists();
foreach ($arguments as $idx => $arg) {
switch ($arg) {
case '-f':
case '--file':
$this->settings->addFilePath($this->argv[$idx + 1]);
break;
case '-o':
case '--output':
if (empty($this->argv[$idx + 1])) {
throw new InvalidArgumentException('-o is required');
}
$this->settings->setOutputPath($this->argv[$idx + 1]);
break;
case '-d':
case '--dir':
if (empty($this->argv[$idx + 1])) {
throw new InvalidArgumentException('a directory path is expected for -d (--dir)');
}
$this->settings->addDirPath($this->argv[$idx + 1]);
break;
case '-e':
case '--env':
$this->settings->setEnvFilepath($this->argv[$idx + 1]);
break;
case '-p':
case '--preserve':
$this->settings->setPreserveOutput(true);
break;
case '--http':
$this->settings->addFormat(ConvertFormat::Http);
break;
case '--curl':
$this->settings->addFormat(ConvertFormat::Curl);
break;
case '--wget':
$this->settings->addFormat(ConvertFormat::Wget);
break;
case '--v2.0':
$this->settings->addFormat(ConvertFormat::Postman20);
break;
case '--v2.1':
$this->settings->addFormat(ConvertFormat::Postman21);
break;
case '-a':
case '--all':
foreach (ConvertFormat::cases() as $format) {
$this->settings->addFormat($format);
}
break;
case '--var':
//TODO split by first equal sign
$this->env->setCustomVar(...explode('=', trim($this->argv[$idx + 1])));
break;
case '--dev':
$this->settings->setDevMode(true);
break;
case '--dump':
$this->needDumpSettings = true;
break;
case '-v':
case '--version':
die(implode(EOL, $this->version()) . EOL);
case '-h':
case '--help':
$needHelp = true;
break;
}
}
if ($needHelp) {
die(implode(EOL, $this->usage()) . EOL);
}
if (empty($this->settings->collectionPaths())) {
throw new InvalidArgumentException('there are no collections to convert');
}
if (empty($this->settings->outputPath())) {
throw new InvalidArgumentException('-o is required');
}
if (empty($this->settings->formats())) {
$this->settings->addFormat(ConvertFormat::Http);
}
} }
/** /**
@@ -193,41 +58,14 @@ class Processor
* @throws DirectoryIsNotWriteableException * @throws DirectoryIsNotWriteableException
* @throws DirectoryNotExistsException * @throws DirectoryNotExistsException
* @throws JsonException * @throws JsonException
* @throws IncorrectSettingsFileException
*/ */
public function handle(): void public function start(): void
{ {
$this->prepareOutputDirectory(); $this->prepareOutputDirectory();
$this->initConverters(); $this->initConverters();
$this->convert(); $this->convert();
} }
/**
* Writes all settings into file if --dump provided
*
* @return never
*/
#[NoReturn]
protected function dumpSettingsFile(): never
{
$answer = 'o';
if ($this->settings::fileExists()) {
echo 'Settings file already exists: ' . $this->settings::filepath() . EOL;
echo 'Do you want to (o)verwrite it, (b)ackup it and create new one or (c)ancel (default)?' . EOL;
$answer = strtolower(trim(readline('> ')));
}
if (!in_array($answer, ['o', 'b'])) {
die('Current settings file has not been changed' . EOL);
}
if ($answer === 'b') {
$filepath = $this->settings->backup();
printf("Settings file has been backed up to file:%s\t%s%s", EOL, $filepath, EOL);
}
$this->settings->dump($this->env->customVars());
printf("Arguments has been converted into settings file:%s\t%s%s", EOL, $this->settings::filepath(), EOL);
die('Review and edit it if needed.' . EOL);
}
/** /**
* Initializes output directory * Initializes output directory
* *
@@ -264,7 +102,7 @@ class Processor
* @return Generator<Collection> * @return Generator<Collection>
* @throws JsonException * @throws JsonException
*/ */
protected function newCollection(): Generator protected function nextCollection(): Generator
{ {
foreach ($this->settings->collectionPaths() as $collectionPath) { foreach ($this->settings->collectionPaths() as $collectionPath) {
yield Collection::fromFile($collectionPath); yield Collection::fromFile($collectionPath);
@@ -280,9 +118,7 @@ class Processor
{ {
$count = count($this->settings->collectionPaths()); $count = count($this->settings->collectionPaths());
$current = $success = 0; $current = $success = 0;
$collection = null; foreach ($this->nextCollection() as $collection) {
print(implode(EOL, array_merge($this->version(), $this->copyright())) . EOL . EOL);
foreach ($this->newCollection() as $collection) {
++$current; ++$current;
printf("Converting '%s' (%d/%d):%s", $collection->name(), $current, $count, EOL); printf("Converting '%s' (%d/%d):%s", $collection->name(), $current, $count, EOL);
foreach ($this->converters as $type => $converter) { foreach ($this->converters as $type => $converter) {
@@ -297,7 +133,7 @@ class Processor
} catch (Exception $e) { } catch (Exception $e) {
printf(' ERROR %s: %s%s', $e->getCode(), $e->getMessage(), EOL); printf(' ERROR %s: %s%s', $e->getCode(), $e->getMessage(), EOL);
if ($this->settings->isDevMode()) { if ($this->settings->isDevMode()) {
array_map(static fn ($line) => printf(' %s%s', $line, EOL), $e->getTrace()); array_map(static fn (string $line) => printf(' %s%s', $line, EOL), $e->getTrace());
} }
} }
} }
@@ -326,79 +162,4 @@ class Processor
$ram = (memory_get_peak_usage(true) - $this->initRam) / 1024 / 1024; $ram = (memory_get_peak_usage(true) - $this->initRam) / 1024 / 1024;
printf("Converted %d/%d in %.2f $timeFmt using up to %.2f MiB RAM%s", $success, $count, $time, $ram, EOL); printf("Converted %d/%d in %.2f $timeFmt using up to %.2f MiB RAM%s", $success, $count, $time, $ram, EOL);
} }
/**
* @return string[]
*/
public static function version(): array
{
return ['Postman collection converter v' . self::VERSION];
}
/**
* @return string[]
*/
public static function copyright(): array
{
$years = ($year = (int)date('Y')) > 2023 ? "2023 - $year" : $year;
return [
"Anthony Axenov (c) $years, MIT license",
'https://git.axenov.dev/anthony/pm-convert'
];
}
/**
* @return array
*/
public static function usage(): array
{
return array_merge(static::version(), [
'Usage:',
"\t./pm-convert -f|-d PATH -o OUTPUT_PATH [ARGUMENTS] [FORMATS]",
"\tphp pm-convert -f|-d PATH -o OUTPUT_PATH [ARGUMENTS] [FORMATS]",
"\tcomposer pm-convert -f|-d PATH -o OUTPUT_PATH [ARGUMENTS] [FORMATS]",
"\t./vendor/bin/pm-convert -f|-d PATH -o OUTPUT_PATH [ARGUMENTS] [FORMATS]",
'',
'Possible ARGUMENTS:',
"\t-f, --file - a PATH to a single collection file to convert from",
"\t-d, --dir - a PATH to a directory with collections to convert from",
"\t-o, --output - a directory OUTPUT_PATH to put results in",
"\t-e, --env - use environment file with variables to replace in requests",
"\t--var \"NAME=VALUE\" - force replace specified env variable called NAME with custom VALUE",
"\t-p, --preserve - do not delete OUTPUT_PATH (if exists)",
"\t --dump - convert provided arguments into settings file in `pwd",
"\t-h, --help - show this help message and exit",
"\t-v, --version - show version info and exit",
'',
'If no ARGUMENTS passed then --help implied.',
'If both -f and -d are specified then only unique set of files from both arguments will be converted.',
'-f or -d are required to be specified at least once, but each may be specified multiple times.',
'PATH must be a valid path to readable json-file or directory.',
'OUTPUT_PATH must be a valid path to writeable directory.',
'If -o or -e was specified several times then only last one will be used.',
'',
'Possible FORMATS:',
"\t--http - generate raw *.http files (default)",
"\t--curl - generate shell scripts with curl command",
"\t--wget - generate shell scripts with wget command",
"\t--v2.0 - convert from Postman Collection Schema v2.1 into v2.0",
"\t--v2.1 - convert from Postman Collection Schema v2.0 into v2.1",
"\t-a, --all - convert to all of formats listed above",
'',
'If no FORMATS specified then --http implied.',
'Any of FORMATS can be specified at the same time or replaced by --all.',
'',
'Example:',
" ./pm-convert \ ",
" -f ~/dir1/first.postman_collection.json \ ",
" --directory ~/team \ ",
" --file ~/dir2/second.postman_collection.json \ ",
" --env ~/localhost.postman_environment.json \ ",
" -d ~/personal \ ",
" --var \"myvar=some value\" \ ",
" -o ~/postman_export \ ",
" --all",
"",
], static::copyright());
}
} }

View File

@@ -4,10 +4,11 @@ declare(strict_types=1);
namespace PmConverter; namespace PmConverter;
use Exception;
use InvalidArgumentException; use InvalidArgumentException;
use JsonException; use JsonException;
use PmConverter\Converters\ConvertFormat; use PmConverter\Converters\ConvertFormat;
use PmConverter\Exceptions\IncorrectSettingsFileException; use PmConverter\Enums\ArgumentNames as AN;
/** /**
* Class responsible for settings storage and dumping * Class responsible for settings storage and dumping
@@ -15,9 +16,9 @@ use PmConverter\Exceptions\IncorrectSettingsFileException;
class Settings class Settings
{ {
/** /**
* @var string Full path to settings file * @var string|null Full path to settings file
*/ */
protected static string $filepath; protected ?string $filePath = null;
/** /**
* @var bool Flag to output some debug-specific messages * @var bool Flag to output some debug-specific messages
@@ -27,7 +28,7 @@ class Settings
/** /**
* @var string[] Paths to collection directories * @var string[] Paths to collection directories
*/ */
protected array $directories = []; protected array $dirPaths = [];
/** /**
* @var string[] Paths to collection files * @var string[] Paths to collection files
@@ -35,14 +36,14 @@ class Settings
protected array $collectionPaths = []; protected array $collectionPaths = [];
/** /**
* @var string Output path where to put results in * @var string|null Output path where to put results in
*/ */
protected string $outputPath = ''; protected ?string $outputPath;
/** /**
* @var bool Flag to remove output directories or not before conversion started * @var bool Flag to remove output directories or not before conversion started
*/ */
protected bool $preserveOutput = false; protected bool $preserveOutput;
/** /**
* @var string[] Additional variables * @var string[] Additional variables
@@ -55,36 +56,129 @@ class Settings
protected array $formats = []; protected array $formats = [];
/** /**
* @var string Path to environment file * @var string|null Path to environment file
*/ */
protected string $envFilepath = ''; protected ?string $envFilePath = null;
/** /**
* @return bool
*/
public static function fileExists(): bool
{
return file_exists(self::$filepath);
}
/**
* @return self
* @throws IncorrectSettingsFileException
* @throws JsonException * @throws JsonException
*/ */
public static function init(): self public function __construct()
{ {
$content = '{}'; $this->loadFromDefaults();
self::$filepath = sprintf('%s%spm-convert-settings.json', $_SERVER['PWD'], DS);
if (self::fileExists()) {
$content = trim(file_get_contents(self::$filepath));
} }
try {
$settings = json_decode($content ?: '{}', flags: JSON_THROW_ON_ERROR); /**
} catch (JsonException $e) { * Loads settings from file
throw new IncorrectSettingsFileException('Incorrect settings file: ' . $e->getMessage(), $e->getCode()); *
* @param string|null $filePath
* @return void
* @throws Exception
*/
public function loadFromFile(?string $filePath = null): void
{
if (is_null($filePath)) {
$filePath = sprintf('%s%spm-convert-settings.json', $_SERVER['PWD'], DS);
} }
return new self($settings);
$filePath = trim($filePath);
file_exists($filePath) || throw new Exception("file does not exist: $filePath");
is_file($filePath) || throw new Exception("not a file: $filePath");
is_readable($filePath) || throw new Exception("file is not readable: $filePath");
$content = file_get_contents($filePath);
$settings = json_decode($content ?: '{}', true, JSON_THROW_ON_ERROR);
$this->setFromArray($settings);
$this->filePath = $filePath;
}
/**
* Rewrites some defined settings with new values
*
* @param array $settings
* @return void
* @throws JsonException
*/
public function override(array $settings): void
{
$settings = array_replace_recursive($this->__serialize(), $settings);
$this->setFromArray($settings);
}
/**
* Loads settings with default values
*
* @return void
* @throws JsonException
*/
public function loadFromDefaults(): void
{
$this->setFromArray(self::defaults());
}
/**
* Returns default settings values
*
* @return array
*/
public static function defaults(?string $key = null): mixed
{
$values = [
AN::Config => null,
AN::Directories => [],
AN::Files => [],
AN::Environment => null,
AN::Output => null,
AN::PreserveOutput => false,
AN::Formats => ['http'],
AN::Vars => [],
AN::DevMode => false,
AN::Verbose => false,
];
return $key ? $values[$key] : $values;
}
/**
* Set settings from array
*
* @param array $settings
* @return void
* @throws JsonException
*/
protected function setFromArray(array $settings): void
{
foreach ($settings[AN::Directories] ?? self::defaults(AN::Directories) as $path) {
$this->addDirPath($path);
}
foreach ($settings[AN::Files] ?? self::defaults(AN::Files) ?? [] as $path) {
$this->addFilePath($path);
}
$this->setEnvFilePath($settings[AN::Environment] ?? self::defaults(AN::Environment));
$this->setOutputPath($settings[AN::Output] ?? self::defaults(AN::Output));
$this->setPreserveOutput($settings[AN::PreserveOutput] ?? self::defaults(AN::PreserveOutput));
foreach ($settings[AN::Formats] ?? self::defaults(AN::Formats) as $format) {
$this->addFormat(ConvertFormat::fromArg($format));
}
$this->vars = $settings[AN::Vars] ?? self::defaults(AN::Vars);
$this->setDevMode($settings[AN::DevMode] ?? self::defaults(AN::DevMode));
}
/**
* Checks wether settings file exists or not
*
* @return bool
*/
public function fileExists(): bool
{
return is_file($this->filePath)
&& is_readable($this->filePath)
&& is_writable($this->filePath);
} }
/** /**
@@ -92,77 +186,65 @@ class Settings
* *
* @return string * @return string
*/ */
public static function filepath(): string public function filePath(): string
{ {
return self::$filepath; return $this->filePath;
}
/**
* @param object $settings
* @throws JsonException
*/
protected function __construct(object $settings)
{
foreach ($settings->directories ?? [] as $path) {
$this->addDirPath($path);
}
foreach ($settings->files ?? [] as $path) {
$this->addFilePath($path);
}
$this->setDevMode(!empty($settings->devMode));
$this->setPreserveOutput(!empty($settings->preserveOutput));
isset($settings->environment) && $this->setEnvFilepath($settings->environment);
isset($settings->output) && $this->setOutputPath($settings->output);
foreach ($settings->formats ?? [] as $format) {
$this->addFormat(ConvertFormat::fromArg($format));
}
foreach ($settings->vars ?? [] as $name => $value) {
$this->vars[$name] = $value;
}
} }
/** /**
* Adds directory path into current settings array and fills files array with its content
*
* @param string $path * @param string $path
* @return void * @return void
* @throws JsonException * @throws JsonException
*/ */
public function addDirPath(string $path): void public function addDirPath(string $path): void
{ {
$this->directories = array_unique(array_merge( $this->dirPaths = array_unique(array_merge(
$this->directories ?? [], $this->dirPaths ?? [],
[FileSystem::normalizePath($path)] [FileSystem::normalizePath($path)]
)); ));
$files = array_filter( $files = array_filter(
FileSystem::dirContents($path), FileSystem::dirContents($path),
static fn ($filename) => FileSystem::isCollectionFile($filename) static fn ($filename) => FileSystem::isCollectionFile($filename)
); );
$this->collectionPaths = array_unique(array_merge($this->collectionPaths ?? [], $files)); $this->collectionPaths = array_unique(array_merge($this->collectionPaths ?? [], $files));
} }
/** /**
* Adds collection file into current settings array
*
* @param string $path * @param string $path
* @return void * @return void
* @throws JsonException * @throws JsonException
*/ */
public function addFilePath(string $path): void public function addFilePath(string $path): void
{ {
$normpath = FileSystem::normalizePath($path); if (!FileSystem::isCollectionFile($path)) {
if (!FileSystem::isCollectionFile($normpath)) {
throw new InvalidArgumentException("not a valid collection: $path"); throw new InvalidArgumentException("not a valid collection: $path");
} }
in_array($path, $this->collectionPaths) || $this->collectionPaths[] = $path;
if (!in_array($path, $this->collectionPaths)) {
$this->collectionPaths[] = FileSystem::normalizePath($path);
}
} }
/** /**
* @param string $outputPath * Sets output directory path
*
* @param string|null $outputPath
* @return void * @return void
*/ */
public function setOutputPath(string $outputPath): void public function setOutputPath(?string $outputPath): void
{ {
$this->outputPath = $outputPath; $this->outputPath = $outputPath;
} }
/** /**
* Sets developer mode setting
*
* @param bool $devMode * @param bool $devMode
* @return void * @return void
*/ */
@@ -172,6 +254,8 @@ class Settings
} }
/** /**
* Adds a format to convert to into current settings array
*
* @param ConvertFormat $format * @param ConvertFormat $format
* @return void * @return void
*/ */
@@ -191,6 +275,8 @@ class Settings
} }
/** /**
* Sets a setting responsible for saving old convertion results
*
* @param bool $preserveOutput * @param bool $preserveOutput
* @return void * @return void
*/ */
@@ -200,15 +286,21 @@ class Settings
} }
/** /**
* @param string $filepath * Sets environment filepath setting
*
* @param string|null $filepath
* @return void * @return void
*/ */
public function setEnvFilepath(string $filepath): void public function setEnvFilePath(?string $filepath): void
{ {
$this->envFilepath = FileSystem::normalizePath($filepath); $this->envFilePath = is_string($filepath)
? FileSystem::normalizePath($filepath)
: $filepath;
} }
/** /**
* Returns current value of developer mode setting
*
* @return bool * @return bool
*/ */
public function isDevMode(): bool public function isDevMode(): bool
@@ -217,6 +309,8 @@ class Settings
} }
/** /**
* Returns current value of collection files setting
*
* @return string[] * @return string[]
*/ */
public function collectionPaths(): array public function collectionPaths(): array
@@ -225,14 +319,18 @@ class Settings
} }
/** /**
* @return string * Returns current value of output directory path setting
*
* @return string|null
*/ */
public function outputPath(): string public function outputPath(): ?string
{ {
return $this->outputPath; return $this->outputPath;
} }
/** /**
* Returns current value of preserve output setting
*
* @return bool * @return bool
*/ */
public function isPreserveOutput(): bool public function isPreserveOutput(): bool
@@ -241,6 +339,8 @@ class Settings
} }
/** /**
* Returns current convert formats
*
* @return ConvertFormat[] * @return ConvertFormat[]
*/ */
public function formats(): array public function formats(): array
@@ -249,11 +349,13 @@ class Settings
} }
/** /**
* @return string * Returns current value of environment filepath setting
*
* @return string|null
*/ */
public function envFilepath(): string public function envFilepath(): ?string
{ {
return $this->envFilepath; return $this->envFilePath;
} }
/** /**
@@ -264,17 +366,17 @@ class Settings
public function __serialize(): array public function __serialize(): array
{ {
return [ return [
'dev' => $this->isDevMode(), AN::DevMode => $this->isDevMode(),
'directories' => $this->directories, AN::Directories => $this->dirPaths,
'files' => $this->collectionPaths(), AN::Files => $this->collectionPaths(),
'environment' => $this->envFilepath(), AN::Environment => $this->envFilepath(),
'output' => $this->outputPath(), AN::Output => $this->outputPath(),
'preserve-output' => $this->isPreserveOutput(), AN::PreserveOutput => $this->isPreserveOutput(),
'formats' => array_values(array_map( AN::Formats => array_values(array_map(
static fn (ConvertFormat $format) => $format->toArg(), static fn (ConvertFormat $format) => $format->toArg(),
$this->formats(), $this->formats(),
)), )),
'vars' => $this->vars, AN::Vars => $this->vars,
]; ];
} }
@@ -307,7 +409,8 @@ class Settings
*/ */
public function backup(): string public function backup(): string
{ {
copy(self::$filepath, $newfilepath = self::$filepath . '.bak.' . time()); $newFilePath = $this->filePath() . '.bak.' . time();
return $newfilepath; copy($this->filePath(), $newFilePath);
return $newFilePath;
} }
} }

View File

@@ -10,7 +10,7 @@ class AbstractRequestTest extends TestCase
{ {
/** /**
* @covers PmConverter\Converters\Abstract\AbstractRequest * @covers PmConverter\Converters\Abstract\AbstractRequest
* @covers PmConverter\HttpVersion * @covers \PmConverter\Enums\HttpVersion
* @return void * @return void
* @throws InvalidHttpVersionException * @throws InvalidHttpVersionException
*/ */
@@ -25,7 +25,7 @@ class AbstractRequestTest extends TestCase
/** /**
* @covers PmConverter\Converters\Abstract\AbstractRequest * @covers PmConverter\Converters\Abstract\AbstractRequest
* @covers PmConverter\Converters\Abstract\AbstractRequest::getVerb() * @covers PmConverter\Converters\Abstract\AbstractRequest::getVerb()
* @covers PmConverter\HttpVersion * @covers \PmConverter\Enums\HttpVersion
* @return void * @return void
* @throws InvalidHttpVersionException * @throws InvalidHttpVersionException
*/ */

View File

@@ -0,0 +1,10 @@
{
"files": [
"collections/20-API Lifecycle.postman_collection.json"
],
"output": "converted",
"preserveOutput": false,
"formats": [
"http"
]
}