+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Command;
+
+use Composer\Json\JsonFile;
+use Composer\Package\AliasPackage;
+use Composer\Package\BasePackage;
+use Composer\Package\CompletePackageInterface;
+use Composer\Pcre\Preg;
+use Composer\Repository\CompositeRepository;
+use Composer\Semver\Constraint\MatchAllConstraint;
+use Symfony\Component\Console\Formatter\OutputFormatter;
+use Symfony\Component\Console\Input\InputInterface;
+use Composer\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * @author Nicolas Grekas
+ * @author Jordi Boggiano
+ */
+class FundCommand extends BaseCommand
+{
+ protected function configure(): void
+ {
+ $this->setName('fund')
+ ->setDescription('Discover how to help fund the maintenance of your dependencies')
+ ->setDefinition([
+ new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text', ['text', 'json']),
+ ])
+ ;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $composer = $this->requireComposer();
+
+ $repo = $composer->getRepositoryManager()->getLocalRepository();
+ $remoteRepos = new CompositeRepository($composer->getRepositoryManager()->getRepositories());
+ $fundings = [];
+
+ $packagesToLoad = [];
+ foreach ($repo->getPackages() as $package) {
+ if ($package instanceof AliasPackage) {
+ continue;
+ }
+ $packagesToLoad[$package->getName()] = new MatchAllConstraint();
+ }
+
+ // load all packages dev versions in parallel
+ $result = $remoteRepos->loadPackages($packagesToLoad, ['dev' => BasePackage::STABILITY_DEV], []);
+
+ // collect funding data from default branches
+ foreach ($result['packages'] as $package) {
+ if (
+ !$package instanceof AliasPackage
+ && $package instanceof CompletePackageInterface
+ && $package->isDefaultBranch()
+ && $package->getFunding()
+ && isset($packagesToLoad[$package->getName()])
+ ) {
+ $fundings = $this->insertFundingData($fundings, $package);
+ unset($packagesToLoad[$package->getName()]);
+ }
+ }
+
+ // collect funding from installed packages if none was found in the default branch above
+ foreach ($repo->getPackages() as $package) {
+ if ($package instanceof AliasPackage || !isset($packagesToLoad[$package->getName()])) {
+ continue;
+ }
+
+ if ($package instanceof CompletePackageInterface && $package->getFunding()) {
+ $fundings = $this->insertFundingData($fundings, $package);
+ }
+ }
+
+ ksort($fundings);
+
+ $io = $this->getIO();
+
+ $format = $input->getOption('format');
+ if (!in_array($format, ['text', 'json'])) {
+ $io->writeError(sprintf('Unsupported format "%s". See help for supported formats.', $format));
+
+ return 1;
+ }
+
+ if ($fundings && $format === 'text') {
+ $prev = null;
+
+ $io->write('The following packages were found in your dependencies which publish funding information:');
+
+ foreach ($fundings as $vendor => $links) {
+ $io->write('');
+ $io->write(sprintf("%s", $vendor));
+ foreach ($links as $url => $packages) {
+ $line = sprintf(' %s', implode(', ', $packages));
+
+ if ($prev !== $line) {
+ $io->write($line);
+ $prev = $line;
+ }
+
+ $io->write(sprintf(' %s>', OutputFormatter::escape($url), $url));
+ }
+ }
+
+ $io->write("");
+ $io->write("Please consider following these links and sponsoring the work of package authors!");
+ $io->write("Thank you!");
+ } elseif ($format === 'json') {
+ $io->write(JsonFile::encode($fundings));
+ } else {
+ $io->write("No funding links were found in your package dependencies. This doesn't mean they don't need your support!");
+ }
+
+ return 0;
+ }
+
+ /**
+ * @param mixed[] $fundings
+ * @return mixed[]
+ */
+ private function insertFundingData(array $fundings, CompletePackageInterface $package): array
+ {
+ foreach ($package->getFunding() as $fundingOption) {
+ [$vendor, $packageName] = explode('/', $package->getPrettyName());
+ // ignore malformed funding entries
+ if (empty($fundingOption['url'])) {
+ continue;
+ }
+ $url = $fundingOption['url'];
+ if (!empty($fundingOption['type']) && $fundingOption['type'] === 'github' && Preg::isMatch('{^https://github.com/([^/]+)$}', $url, $match)) {
+ $url = 'https://github.com/sponsors/'.$match[1];
+ }
+ $fundings[$vendor][$url][] = $packageName;
+ }
+
+ return $fundings;
+ }
+}
diff --git a/vendor/composer/composer/src/Composer/Command/GlobalCommand.php b/vendor/composer/composer/src/Composer/Command/GlobalCommand.php
new file mode 100644
index 000000000..90b601797
--- /dev/null
+++ b/vendor/composer/composer/src/Composer/Command/GlobalCommand.php
@@ -0,0 +1,170 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Command;
+
+use Composer\Factory;
+use Composer\Pcre\Preg;
+use Composer\Util\Filesystem;
+use Composer\Util\Platform;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Completion\CompletionInput;
+use Symfony\Component\Console\Completion\CompletionSuggestions;
+use Symfony\Component\Console\Input\InputInterface;
+use Composer\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\StringInput;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * @author Jordi Boggiano
+ */
+class GlobalCommand extends BaseCommand
+{
+ public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
+ {
+ $application = $this->getApplication();
+ if ($input->mustSuggestArgumentValuesFor('command-name')) {
+ $suggestions->suggestValues(array_values(array_filter(
+ array_map(static function (Command $command) {
+ return $command->isHidden() ? null : $command->getName();
+ }, $application->all()),
+ static function (?string $cmd) {
+ return $cmd !== null;
+ }
+ )));
+
+ return;
+ }
+
+ if ($application->has($commandName = $input->getArgument('command-name'))) {
+ $input = $this->prepareSubcommandInput($input, true);
+ $input = CompletionInput::fromString($input->__toString(), 2);
+ $command = $application->find($commandName);
+ $command->mergeApplicationDefinition();
+
+ $input->bind($command->getDefinition());
+ $command->complete($input, $suggestions);
+ }
+ }
+
+ protected function configure(): void
+ {
+ $this
+ ->setName('global')
+ ->setDescription('Allows running commands in the global composer dir ($COMPOSER_HOME)')
+ ->setDefinition([
+ new InputArgument('command-name', InputArgument::REQUIRED, ''),
+ new InputArgument('args', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, ''),
+ ])
+ ->setHelp(
+ <<\AppData\Roaming\Composer on Windows
+and /home//.composer on unix systems.
+
+If your system uses freedesktop.org standards, then it will first check
+XDG_CONFIG_HOME or default to /home//.config/composer
+
+Note: This path may vary depending on customizations to bin-dir in
+composer.json or the environmental variable COMPOSER_BIN_DIR.
+
+Read more at https://getcomposer.org/doc/03-cli.md#global
+EOT
+ )
+ ;
+ }
+
+ /**
+ * @throws \Symfony\Component\Console\Exception\ExceptionInterface
+ */
+ public function run(InputInterface $input, OutputInterface $output): int
+ {
+ // TODO remove for Symfony 6+ as it is then in the interface
+ if (!method_exists($input, '__toString')) { // @phpstan-ignore-line
+ throw new \LogicException('Expected an Input instance that is stringable, got '.get_class($input));
+ }
+
+ // extract real command name
+ $tokens = Preg::split('{\s+}', $input->__toString());
+ $args = [];
+ foreach ($tokens as $token) {
+ if ($token && $token[0] !== '-') {
+ $args[] = $token;
+ if (count($args) >= 2) {
+ break;
+ }
+ }
+ }
+
+ // show help for this command if no command was found
+ if (count($args) < 2) {
+ return parent::run($input, $output);
+ }
+
+ $input = $this->prepareSubcommandInput($input);
+
+ return $this->getApplication()->run($input, $output);
+ }
+
+ private function prepareSubcommandInput(InputInterface $input, bool $quiet = false): StringInput
+ {
+ // TODO remove for Symfony 6+ as it is then in the interface
+ if (!method_exists($input, '__toString')) { // @phpstan-ignore-line
+ throw new \LogicException('Expected an Input instance that is stringable, got '.get_class($input));
+ }
+
+ // The COMPOSER env var should not apply to the global execution scope
+ if (Platform::getEnv('COMPOSER')) {
+ Platform::clearEnv('COMPOSER');
+ }
+
+ // change to global dir
+ $config = Factory::createConfig();
+ $home = $config->get('home');
+
+ if (!is_dir($home)) {
+ $fs = new Filesystem();
+ $fs->ensureDirectoryExists($home);
+ if (!is_dir($home)) {
+ throw new \RuntimeException('Could not create home directory');
+ }
+ }
+
+ try {
+ chdir($home);
+ } catch (\Exception $e) {
+ throw new \RuntimeException('Could not switch to home directory "'.$home.'"', 0, $e);
+ }
+ if (!$quiet) {
+ $this->getIO()->writeError('Changed current directory to '.$home.'');
+ }
+
+ // create new input without "global" command prefix
+ $input = new StringInput(Preg::replace('{\bg(?:l(?:o(?:b(?:a(?:l)?)?)?)?)?\b}', '', $input->__toString(), 1));
+ $this->getApplication()->resetComposer();
+
+ return $input;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function isProxyCommand(): bool
+ {
+ return true;
+ }
+}
diff --git a/vendor/composer/composer/src/Composer/Command/HomeCommand.php b/vendor/composer/composer/src/Composer/Command/HomeCommand.php
new file mode 100644
index 000000000..3547faec7
--- /dev/null
+++ b/vendor/composer/composer/src/Composer/Command/HomeCommand.php
@@ -0,0 +1,165 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Command;
+
+use Composer\Package\CompletePackageInterface;
+use Composer\Repository\RepositoryInterface;
+use Composer\Repository\RootPackageRepository;
+use Composer\Repository\RepositoryFactory;
+use Composer\Util\Platform;
+use Composer\Util\ProcessExecutor;
+use Composer\Console\Input\InputArgument;
+use Composer\Console\Input\InputOption;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * @author Robert Schönthal
+ */
+class HomeCommand extends BaseCommand
+{
+ use CompletionTrait;
+
+ /**
+ * @inheritDoc
+ */
+ protected function configure(): void
+ {
+ $this
+ ->setName('browse')
+ ->setAliases(['home'])
+ ->setDescription('Opens the package\'s repository URL or homepage in your browser')
+ ->setDefinition([
+ new InputArgument('packages', InputArgument::IS_ARRAY, 'Package(s) to browse to.', null, $this->suggestInstalledPackage()),
+ new InputOption('homepage', 'H', InputOption::VALUE_NONE, 'Open the homepage instead of the repository URL.'),
+ new InputOption('show', 's', InputOption::VALUE_NONE, 'Only show the homepage or repository URL.'),
+ ])
+ ->setHelp(
+ <<initializeRepos();
+ $io = $this->getIO();
+ $return = 0;
+
+ $packages = $input->getArgument('packages');
+ if (count($packages) === 0) {
+ $io->writeError('No package specified, opening homepage for the root package');
+ $packages = [$this->requireComposer()->getPackage()->getName()];
+ }
+
+ foreach ($packages as $packageName) {
+ $handled = false;
+ $packageExists = false;
+ foreach ($repos as $repo) {
+ foreach ($repo->findPackages($packageName) as $package) {
+ $packageExists = true;
+ if ($package instanceof CompletePackageInterface && $this->handlePackage($package, $input->getOption('homepage'), $input->getOption('show'))) {
+ $handled = true;
+ break 2;
+ }
+ }
+ }
+
+ if (!$packageExists) {
+ $return = 1;
+ $io->writeError('Package '.$packageName.' not found');
+ }
+
+ if (!$handled) {
+ $return = 1;
+ $io->writeError(''.($input->getOption('homepage') ? 'Invalid or missing homepage' : 'Invalid or missing repository URL').' for '.$packageName.'');
+ }
+ }
+
+ return $return;
+ }
+
+ private function handlePackage(CompletePackageInterface $package, bool $showHomepage, bool $showOnly): bool
+ {
+ $support = $package->getSupport();
+ $url = $support['source'] ?? $package->getSourceUrl();
+ if (!$url || $showHomepage) {
+ $url = $package->getHomepage();
+ }
+
+ if (!$url || !filter_var($url, FILTER_VALIDATE_URL)) {
+ return false;
+ }
+
+ if ($showOnly) {
+ $this->getIO()->write(sprintf('%s', $url));
+ } else {
+ $this->openBrowser($url);
+ }
+
+ return true;
+ }
+
+ /**
+ * opens a url in your system default browser
+ */
+ private function openBrowser(string $url): void
+ {
+ $process = new ProcessExecutor($this->getIO());
+ if (Platform::isWindows()) {
+ $process->execute(['start', '"web"', 'explorer', $url], $output);
+
+ return;
+ }
+
+ $linux = $process->execute(['which', 'xdg-open'], $output);
+ $osx = $process->execute(['which', 'open'], $output);
+
+ if (0 === $linux) {
+ $process->execute(['xdg-open', $url], $output);
+ } elseif (0 === $osx) {
+ $process->execute(['open', $url], $output);
+ } else {
+ $this->getIO()->writeError('No suitable browser opening command found, open yourself: ' . $url);
+ }
+ }
+
+ /**
+ * Initializes repositories
+ *
+ * Returns an array of repos in order they should be checked in
+ *
+ * @return RepositoryInterface[]
+ */
+ private function initializeRepos(): array
+ {
+ $composer = $this->tryComposer();
+
+ if ($composer) {
+ return array_merge(
+ [new RootPackageRepository(clone $composer->getPackage())], // root package
+ [$composer->getRepositoryManager()->getLocalRepository()], // installed packages
+ $composer->getRepositoryManager()->getRepositories() // remotes
+ );
+ }
+
+ return RepositoryFactory::defaultReposWithDefaultManager($this->getIO());
+ }
+}
diff --git a/vendor/composer/composer/src/Composer/Command/InitCommand.php b/vendor/composer/composer/src/Composer/Command/InitCommand.php
new file mode 100644
index 000000000..2a54da313
--- /dev/null
+++ b/vendor/composer/composer/src/Composer/Command/InitCommand.php
@@ -0,0 +1,662 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Command;
+
+use Composer\Factory;
+use Composer\Json\JsonFile;
+use Composer\Json\JsonValidationException;
+use Composer\Package\BasePackage;
+use Composer\Pcre\Preg;
+use Composer\Repository\CompositeRepository;
+use Composer\Repository\PlatformRepository;
+use Composer\Repository\RepositoryFactory;
+use Composer\Spdx\SpdxLicenses;
+use Composer\Util\Filesystem;
+use Composer\Util\Silencer;
+use Symfony\Component\Console\Input\ArrayInput;
+use Symfony\Component\Console\Input\InputInterface;
+use Composer\Console\Input\InputOption;
+use Composer\Util\ProcessExecutor;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Helper\FormatterHelper;
+
+/**
+ * @author Justin Rainbow
+ * @author Jordi Boggiano
+ */
+class InitCommand extends BaseCommand
+{
+ use CompletionTrait;
+ use PackageDiscoveryTrait;
+
+ /** @var array */
+ private $gitConfig;
+
+ /**
+ * @inheritDoc
+ */
+ protected function configure(): void
+ {
+ $this
+ ->setName('init')
+ ->setDescription('Creates a basic composer.json file in current directory')
+ ->setDefinition([
+ new InputOption('name', null, InputOption::VALUE_REQUIRED, 'Name of the package'),
+ new InputOption('description', null, InputOption::VALUE_REQUIRED, 'Description of package'),
+ new InputOption('author', null, InputOption::VALUE_REQUIRED, 'Author name of package'),
+ new InputOption('type', null, InputOption::VALUE_REQUIRED, 'Type of package (e.g. library, project, metapackage, composer-plugin)'),
+ new InputOption('homepage', null, InputOption::VALUE_REQUIRED, 'Homepage of package'),
+ new InputOption('require', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Package to require with a version constraint, e.g. foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"', null, $this->suggestAvailablePackageInclPlatform()),
+ new InputOption('require-dev', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Package to require for development with a version constraint, e.g. foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"', null, $this->suggestAvailablePackageInclPlatform()),
+ new InputOption('stability', 's', InputOption::VALUE_REQUIRED, 'Minimum stability (empty or one of: '.implode(', ', array_keys(BasePackage::STABILITIES)).')'),
+ new InputOption('license', 'l', InputOption::VALUE_REQUIRED, 'License of package'),
+ new InputOption('repository', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Add custom repositories, either by URL or using JSON arrays'),
+ new InputOption('autoload', 'a', InputOption::VALUE_REQUIRED, 'Add PSR-4 autoload mapping. Maps your package\'s namespace to the provided directory. (Expects a relative path, e.g. src/)'),
+ ])
+ ->setHelp(
+ <<init