<commit_before><?php

namespace AmpProject\Tooling\Validator;

use AmpProject\Tooling\Validator\SpecGenerator\Section;
use AmpProject\Tooling\Validator\SpecGenerator\Template;
use Nette\PhpGenerator\ClassType;
use Nette\PhpGenerator\PhpFile;
use Nette\PhpGenerator\PsrPrinter;

final class SpecGenerator
{

    /**
     * Namespace under which to find the spec generator files.
     *
     * @var string
     */
    const GENERATOR_NAMESPACE = 'AmpProject\\Tooling\\Validator\\SpecGenerator';

    /**
     * Generate the PHP spec from a JSON definition.
     *
     * @param array  $jsonSpec      Validator spec as defined by the downloaded JSON file.
     * @param string $rootNamespace Root namespace to generate the PHP validator spec under.
     * @param string $destination   Destination folder to store the PHP validator spec under.
     */
    public function generate($jsonSpec, $rootNamespace, $destination)
    {
        $printer = new PsrPrinter();
        $this->ensureDirectoriesExist($destination);

        $specFile      = $this->createNewFile();
        $specNamespace = $specFile->addNamespace($rootNamespace);
        $specClass     = $specNamespace->addClass('Spec')
                                       ->setFinal();

        $specNamespace->addUse("{$rootNamespace}\\Spec");

        $tagFile      = new PhpFile();
        $tagNamespace = $tagFile->addNamespace("{$rootNamespace}\\Spec");
        $tagClass     = ClassType::withBodiesFrom(Template\Tag::class);
        $tagNamespace->add($tagClass);
        file_put_contents("{$destination}/Spec/Tag.php", $printer->printFile($tagFile));

        foreach ($jsonSpec as $section => $sectionSpec) {
            $sectionFile      = $this->createNewFile();
            $sectionNamespace = $sectionFile->addNamespace("{$rootNamespace}\\Spec\\Section");
            $sectionClass     = $sectionNamespace->addClass($this->getClassName($section))
                                                 ->setFinal();

            $sectionProcessorClass = self::GENERATOR_NAMESPACE . "\\Section\\{$this->getClassName($section)}";

            if (class_exists($sectionProcessorClass)) {
                /** @var Section $sectionProcessor */
                $sectionProcessor = new $sectionProcessorClass();
                $sectionProcessor->process($rootNamespace, $sectionSpec, $sectionNamespace, $sectionClass);
            }

            file_put_contents(
                "{$destination}/Spec/Section/{$this->getClassName($section)}.php",
                $printer->printFile($sectionFile)
            );

            $specClass->addProperty($section)
                      ->setPrivate()
                      ->addComment("@var Spec\\Section\\{$this->getClassName($section)}");

            $specClass->addMethod($section)
                      ->addBody('if ($this->? === null) {', [$section])
                      ->addBody("    \$this->? = new Spec\\Section\\{$this->getClassName($section)}();", [$section])
                      ->addBody('}')
                      ->addBody('return $this->?;', [$section])
                      ->addComment("@return Spec\\Section\\{$this->getClassName($section)}");
        }

        file_put_contents("{$destination}/Spec.php", $printer->printFile($specFile));
    }
<commit_msg>Reuse section class name<commit_after><?php

namespace AmpProject\Tooling\Validator;

use AmpProject\Tooling\Validator\SpecGenerator\Section;
use AmpProject\Tooling\Validator\SpecGenerator\Template;
use Nette\PhpGenerator\ClassType;
use Nette\PhpGenerator\PhpFile;
use Nette\PhpGenerator\PsrPrinter;

final class SpecGenerator
{

    /**
     * Namespace under which to find the spec generator files.
     *
     * @var string
     */
    const GENERATOR_NAMESPACE = 'AmpProject\\Tooling\\Validator\\SpecGenerator';

    /**
     * Generate the PHP spec from a JSON definition.
     *
     * @param array  $jsonSpec      Validator spec as defined by the downloaded JSON file.
     * @param string $rootNamespace Root namespace to generate the PHP validator spec under.
     * @param string $destination   Destination folder to store the PHP validator spec under.
     */
    public function generate($jsonSpec, $rootNamespace, $destination)
    {
        $printer = new PsrPrinter();
        $this->ensureDirectoriesExist($destination);

        $specFile      = $this->createNewFile();
        $specNamespace = $specFile->addNamespace($rootNamespace);
        $specClass     = $specNamespace->addClass('Spec')
                                       ->setFinal();

        $specNamespace->addUse("{$rootNamespace}\\Spec");

        $tagFile      = new PhpFile();
        $tagNamespace = $tagFile->addNamespace("{$rootNamespace}\\Spec");
        $tagClass     = ClassType::withBodiesFrom(Template\Tag::class);
        $tagNamespace->add($tagClass);
        file_put_contents("{$destination}/Spec/Tag.php", $printer->printFile($tagFile));

        foreach ($jsonSpec as $section => $sectionSpec) {
            $sectionFile      = $this->createNewFile();
            $sectionNamespace = $sectionFile->addNamespace("{$rootNamespace}\\Spec\\Section");
            $sectionClassName = $this->getClassName($section);
            $sectionClass     = $sectionNamespace->addClass($sectionClassName)
                                                 ->setFinal();

            $sectionProcessorClass = self::GENERATOR_NAMESPACE . "\\Section\\{$sectionClassName}";

            if (class_exists($sectionProcessorClass)) {
                /** @var Section $sectionProcessor */
                $sectionProcessor = new $sectionProcessorClass();
                $sectionProcessor->process($rootNamespace, $sectionSpec, $sectionNamespace, $sectionClass);
            }

            file_put_contents(
                "{$destination}/Spec/Section/{$sectionClassName}.php",
                $printer->printFile($sectionFile)
            );

            $specClass->addProperty($section)
                      ->setPrivate()
                      ->addComment("@var Spec\\Section\\{$sectionClassName}");

            $specClass->addMethod($section)
                      ->addBody('if ($this->? === null) {', [$section])
                      ->addBody("    \$this->? = new Spec\\Section\\{$sectionClassName}();", [$section])
                      ->addBody('}')
                      ->addBody('return $this->?;', [$section])
                      ->addComment("@return Spec\\Section\\{$sectionClassName}");
        }

        file_put_contents("{$destination}/Spec.php", $printer->printFile($specFile));
    }

{'fraction_non_alphanumeric': 0.13849194283976893, 'fraction_numerical': 0.0, 'mean_word_length': 2.3429878048780486, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 68, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4720723', 'n_tokens_mistral': 1696, 'n_tokens_neox': 1635, 'n_words': 311}