<commit_before><?php

namespace Sunlight\Composer;

use Sunlight\Util\Filesystem;
use Sunlight\Util\Json;

/**
 * Composer repository
 *
 * Provides access to a composer.json file and its installed packages.
 */
class Repository
{
    /** @var string */
    private $composerJsonPath;
    /** @var string|null */
    private $directory;
    /** @var \stdClass|null */
    private $package;
    /** @var string|null */
    private $vendorPath;
    /** @var \stdClass[]|null name-indexed */
    private $installedPackages;
    /** @var array|null */
    private $classMap;

    function __construct(string $composerJsonPath)
    {
        $this->composerJsonPath = $composerJsonPath;
    }

    function getComposerJsonPath(): string
    {
        return $this->composerJsonPath;
    }

    /**
     * Get data from composer.json
     */
    function getDefinition(): \stdClass
    {
        if ($this->package === null) {
            $this->package = Json::decode(file_get_contents($this->composerJsonPath), false);
        }

        return $this->package;
    }

    /**
     * Get directory where composer.json is located
     */
    function getDirectory(): string
    {
        if ($this->directory === null) {
            $this->directory = dirname($this->composerJsonPath);
        }

        return $this->directory;
    }

    function getVendorPath(): string
    {
        if ($this->vendorPath === null) {
            $package = $this->getDefinition();

            if (isset($package->config->{'vendor-dir'})) {
                $vendorDir = $package->config->{'vendor-dir'};

                if (Filesystem::isAbsolutePath($vendorDir)) {
                    throw new \UnexpectedValueException('Absolute vendor dir is not supported');
                }
            } else {
                $vendorDir = 'vendor';
            }

            $this->vendorPath = Filesystem::normalizeWithBasePath($this->getDirectory(), $vendorDir);
        }

        return $this->vendorPath;
    }

    function getPackagePath(\stdClass $package): string
    {
        return $this->getVendorPath() . '/' . $package->name;
    }

    function getPackageComposerJsonPath(\stdClass $package): string
    {
        return $this->getPackagePath($package) . '/composer.json';
    }

    function getInstalledJsonPath(): string
    {
        return $this->getVendorPath() . '/composer/installed.json';
    }

    /**
     * @return \stdClass[] name-indexed
     */
    function getInstalledPackages(): array
    {
        if ($this->installedPackages === null) {
            $this->installedPackages = [];

            if (is_file($installedJson = $this->getInstalledJsonPath())) {
                $packages = Json::decode(file_get_contents($installedJson), false);
                $packages = $packages->packages ?? $packages; // composer 2.0 has wrapper
                
                foreach ($packages as $package) {
                    $this->installedPackages[$package->name] = $package;
                }
            }
        }

        return $this->installedPackages;
    }

    function getClassMap(): array
    {<commit_msg>Fix composer repository JSON decoding<commit_after><?php

namespace Sunlight\Composer;

use Sunlight\Util\Filesystem;
use Sunlight\Util\Json;

/**
 * Composer repository
 *
 * Provides access to a composer.json file and its installed packages.
 */
class Repository
{
    /** @var string */
    private $composerJsonPath;
    /** @var string|null */
    private $directory;
    /** @var \stdClass|null */
    private $package;
    /** @var string|null */
    private $vendorPath;
    /** @var \stdClass[]|null name-indexed */
    private $installedPackages;
    /** @var array|null */
    private $classMap;

    function __construct(string $composerJsonPath)
    {
        $this->composerJsonPath = $composerJsonPath;
    }

    function getComposerJsonPath(): string
    {
        return $this->composerJsonPath;
    }

    /**
     * Get data from composer.json
     */
    function getDefinition(): \stdClass
    {
        if ($this->package === null) {
            $this->package = Json::decode(file_get_contents($this->composerJsonPath), 0, false);
        }

        return $this->package;
    }

    /**
     * Get directory where composer.json is located
     */
    function getDirectory(): string
    {
        if ($this->directory === null) {
            $this->directory = dirname($this->composerJsonPath);
        }

        return $this->directory;
    }

    function getVendorPath(): string
    {
        if ($this->vendorPath === null) {
            $package = $this->getDefinition();

            if (isset($package->config->{'vendor-dir'})) {
                $vendorDir = $package->config->{'vendor-dir'};

                if (Filesystem::isAbsolutePath($vendorDir)) {
                    throw new \UnexpectedValueException('Absolute vendor dir is not supported');
                }
            } else {
                $vendorDir = 'vendor';
            }

            $this->vendorPath = Filesystem::normalizeWithBasePath($this->getDirectory(), $vendorDir);
        }

        return $this->vendorPath;
    }

    function getPackagePath(\stdClass $package): string
    {
        return $this->getVendorPath() . '/' . $package->name;
    }

    function getPackageComposerJsonPath(\stdClass $package): string
    {
        return $this->getPackagePath($package) . '/composer.json';
    }

    function getInstalledJsonPath(): string
    {
        return $this->getVendorPath() . '/composer/installed.json';
    }

    /**
     * @return \stdClass[] name-indexed
     */
    function getInstalledPackages(): array
    {
        if ($this->installedPackages === null) {
            $this->installedPackages = [];

            if (is_file($installedJson = $this->getInstalledJsonPath())) {
                $packages = Json::decode(file_get_contents($installedJson), 0, false);
                $packages = $packages->packages ?? $packages; // composer 2.0 has wrapper
                
                foreach ($packages as $package) {
                    $this->installedPackages[$package->name] = $package;
                }
            }
        }

        return $this->installedPackages;
    }

    function getClassMap(): array
    {
{'fraction_non_alphanumeric': 0.1356255969436485, 'fraction_numerical': 0.0009551098376313276, 'mean_word_length': 2.090506640432858, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 63, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2121366', 'n_tokens_mistral': 1766, 'n_tokens_neox': 1690, 'n_words': 348}