swaggest/json-cli

View on GitHub
src/GenGo.php

Summary

Maintainability
B
5 hrs
Test Coverage
<?php

namespace Swaggest\JsonCli;

use Swaggest\GoCodeBuilder\JsonSchema\GoBuilder;
use Swaggest\GoCodeBuilder\JsonSchema\MarshalingTestFunc;
use Swaggest\GoCodeBuilder\JsonSchema\StripPrefixPathToNameHook;
use Swaggest\GoCodeBuilder\JsonSchema\StructHookCallback;
use Swaggest\GoCodeBuilder\Templates\GoFile;
use Swaggest\GoCodeBuilder\Templates\Struct\StructDef;
use Swaggest\JsonCli\GenGo\BuilderOptions;
use Swaggest\JsonCli\JsonSchema\ResolverMux;
use Swaggest\JsonSchema\Context;
use Swaggest\JsonSchema\RemoteRef\BasicFetcher;
use Swaggest\JsonSchema\RemoteRef\Preloaded;
use Swaggest\JsonSchema\Schema;
use Yaoi\Command;

class GenGo extends Base
{
    use BuilderOptions;

    /** @var string */
    public $packageName = 'entities';

    /** @var string */
    public $rootName = 'Structure';

    /** @var bool */
    public $withTests = false;

    public $output;

    /**
     * @param Command\Definition $definition
     * @param \stdClass|static $options
     */
    public static function setUpDefinition(Command\Definition $definition, $options)
    {
        $definition->description = 'Generate Go code from JSON schema';
        Base::setupGenOptions($definition, $options);

        $options->output = Command\Option::create()
            ->setDescription('Path to output .go file, STDOUT is used by default')->setType();

        $options->packageName = Command\Option::create()->setType()
            ->setDescription('Go package name, default "entities"');

        $options->rootName = Command\Option::create()->setType()
            ->setDescription('Go root struct name, default "Structure", only used for # pointer');

        $options->withTests = Command\Option::create()
            ->setDescription('Generate (un)marshaling tests for entities (experimental feature)');

        static::setUpBuilderOptions($options);
    }


    public function performAction()
    {
        try {
            $skipRoot = false;
            $baseName = null;
            $schema = $this->loadSchema($skipRoot, $baseName);

            $builderOptions = $this->makeGoBuilderOptions();
            $builder = new GoBuilder();
            $builder->options = $builderOptions;

            $pathToNameHook = new StripPrefixPathToNameHook();

            if (!empty($this->defPtr)) {
                $pathToNameHook->prefixes = [];
                foreach ($this->defPtr as $defPtr) {
                    if (isset($baseName)) {
                        $pathToNameHook->prefixes[] = $baseName . $defPtr;
                    }
                    $pathToNameHook->prefixes[] = $defPtr;
                }
            }

            if (isset($baseName)) {
                $pathToNameHook->prefixes[] = $baseName;
            }

            $builder->pathToNameHook = $pathToNameHook;

            $builder->structCreatedHook = new StructHookCallback(function (StructDef $structDef, $path, $schema) {
                if ('#' === $path) {
                    $structDef->setName($this->rootName);
                }
            });
            if ($schema instanceof Schema) {
                $builder->getType($schema);
            }

            $goFile = new GoFile($this->packageName);
            $goFile->fileComment = 'Code generated by github.com/swaggest/json-cli ' . App::$ver . ', DO NOT EDIT.';
            $goFile->setComment('Package ' . $this->packageName . ' contains JSON mapping structures.');

            $goTestFile = new GoFile($this->packageName . '_test');
            $goTestFile->setPackage($this->packageName);
            $goTestFile->fileComment = 'Code generated by github.com/swaggest/json-cli ' . App::$ver . ', DO NOT EDIT.';

            mt_srand(1);

            foreach ($builder->getGeneratedStructs() as $generatedStruct) {
                if ($skipRoot && $generatedStruct->path === '#') {
                    continue;
                }
                $goFile->getCode()->addSnippet($generatedStruct->structDef);
                if ($this->withTests) {
                    $goTestFile->getCode()->addSnippet(MarshalingTestFunc::make($generatedStruct, $builder->options));
                }
            }
            $goFile->getCode()->addSnippet($builder->getCode());

            if ($this->output) {
                if (!file_exists(dirname($this->output))) {
                    $this->response->error('Destination directory does not exist, please create: ' . dirname($this->output));
                    throw new ExitCode('', 1);
                }
                file_put_contents($this->output, $goFile->render());

                if ($this->withTests) {
                    file_put_contents(str_replace('.go', '_test.go', $this->output), $goTestFile->render());
                }
            } else {
                echo $goFile->render();
            }
        } catch (\Exception $e) {
            $this->response->error($e->getMessage());
            throw new ExitCode('', 1);
        }
    }
}