Add initial repository
This commit is contained in:
parent
3cd8d11ebf
commit
f1d8722889
|
@ -3,11 +3,14 @@
|
|||
"description": "Write and deploy modern PHP 8 code, today.",
|
||||
"type": "project",
|
||||
"require": {
|
||||
"nikic/php-parser": "^4.7"
|
||||
"nikic/php-parser": "^4.7",
|
||||
"composer-plugin-api": "^1|^2",
|
||||
"amphp/byte-stream": "^1.7"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^7 | ^8 | ^9",
|
||||
"amphp/php-cs-fixer-config": "dev-master"
|
||||
"amphp/php-cs-fixer-config": "dev-master",
|
||||
"composer/composer": "^1|^2"
|
||||
},
|
||||
"license": "MIT",
|
||||
"authors": [{
|
||||
|
@ -23,4 +26,4 @@
|
|||
"cs-fix": "php-cs-fixer fix -v --diff",
|
||||
"test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit --coverage-text"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
namespace Phabel\Composer;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\EventDispatcher\EventSubscriberInterface;
|
||||
use Composer\Installer\InstallerEvent;
|
||||
use Composer\Installer\InstallerEvents;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Plugin\PluginInterface;
|
||||
|
||||
/**
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
* @license MIT
|
||||
*/
|
||||
class Plugin implements PluginInterface, EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* IO interface.
|
||||
*/
|
||||
private IOInterface $io;
|
||||
/**
|
||||
* Apply plugin modifications to Composer.
|
||||
*
|
||||
* @param Composer $composer Composer instance
|
||||
* @param IOInterface $io IO instance
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function activate(Composer $composer, IOInterface $io): void
|
||||
{
|
||||
$repoManager = $composer->getRepositoryManager();
|
||||
$repos = $repoManager->getRepositories();
|
||||
$repoManager->prependRepository()
|
||||
$this->io = $io;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
InstallerEvents::PRE_DEPENDENCIES_SOLVING =>
|
||||
['onDependencySolve', 100000],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Emitted before composer solves dependencies
|
||||
*
|
||||
* @param InstallerEvent $event Event
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onDependencySolve(InstallerEvent $event): void
|
||||
{
|
||||
var_dump($event);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
<?php
|
||||
|
||||
namespace Phabel\Composer;
|
||||
|
||||
use Composer\Package\Link;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Repository\ComposerRepository;
|
||||
use Composer\Semver\Constraint\ConstraintInterface;
|
||||
|
||||
class Repository extends ComposerRepository
|
||||
{
|
||||
/**
|
||||
* Configuration prefix.
|
||||
*/
|
||||
private const CONFIG_PREFIX = 'phabel-config';
|
||||
/**
|
||||
* Previous repository .
|
||||
*/
|
||||
private ComposerRepository $repository;
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param RepositoryInterface[] $repositories Previous repositories
|
||||
*/
|
||||
public function __construct(ComposerRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get repository configuration.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRepoConfig()
|
||||
{
|
||||
return $this->repository->getRepoConfig();
|
||||
}
|
||||
/**
|
||||
* Set root aliases.
|
||||
*
|
||||
* @param array $rootAliases Root aliases
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setRootAliases(array $rootAliases): void
|
||||
{
|
||||
$this->repository->setRootAliases($rootAliases);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if specified package registered (installed).
|
||||
*
|
||||
* @param PackageInterface $package package instance
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasPackage(PackageInterface $package): bool
|
||||
{
|
||||
return $this->repository->hasPackage($package);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for phabel configuration parameters in constraint.
|
||||
*
|
||||
* @param string|\Composer\Semver\Constraint\ConstraintInterface|null &$constraint package version or version constraint to match against
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function prepareConstraint(&$constraint): array
|
||||
{
|
||||
if (!$constraint instanceof ConstraintInterface && !\is_string($constraint)) {
|
||||
return [];
|
||||
}
|
||||
$constraint = (string) $constraint;
|
||||
if (!str_starts_with($constraint, self::CONFIG_PREFIX)) {
|
||||
return [];
|
||||
}
|
||||
[$config, $constraint] = \explode("\n", $constraint, 2);
|
||||
return \json_decode(\substr($config, 0, \strlen(self::CONFIG_PREFIX)), true) ?: [];
|
||||
}
|
||||
/**
|
||||
* Prepare package.
|
||||
*
|
||||
* @param PackageInterface $package Package
|
||||
* @param array $config Configuration inherited from constraint
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function preparePackage(PackageInterface $package, array $config): void
|
||||
{
|
||||
/**
|
||||
* Phabel configuration of current package.
|
||||
* @var array
|
||||
*/
|
||||
$myConfig = $package->getExtra()['phabel'] ?? [];
|
||||
$havePhabel = false;
|
||||
$myConfig['target'] ??= '7.0';
|
||||
/** @var array */
|
||||
foreach ($package->getRequires() as $link) {
|
||||
if ($link->getTarget() === 'phabel/phabel') {
|
||||
$havePhabel = true;
|
||||
}
|
||||
if ($link->getTarget() === 'php') {
|
||||
$myConfig['target'] = $link->getConstraint();
|
||||
if ($havePhabel) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$havePhabel) {
|
||||
return;
|
||||
}
|
||||
// Config merging logic here...
|
||||
$links = [];
|
||||
foreach ($package->getRequires() as $link) {
|
||||
$version = self::CONFIG_PREFIX.\json_encode($config)."\n".($link->getConstraint() ?? '');
|
||||
$links []= new Link($link->getSource(), $link->getTarget(), $version, $link->getDescription());
|
||||
}
|
||||
$package->setRequires($links);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for the first match of a package by name and version.
|
||||
*
|
||||
* @param string $name package name
|
||||
* @param string|\Composer\Semver\Constraint\ConstraintInterface $constraint package version or version constraint to match against
|
||||
*
|
||||
* @return PackageInterface|null
|
||||
*/
|
||||
public function findPackage(string $name, $constraint): ?PackageInterface
|
||||
{
|
||||
$config = self::prepareConstraint($constraint);
|
||||
if (!$package = $this->repository->findPackage($name, $constraint)) {
|
||||
return null;
|
||||
}
|
||||
return self::preparePackage($package, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for all packages matching a name and optionally a version.
|
||||
*
|
||||
* @param string $name package name
|
||||
* @param string|\Composer\Semver\Constraint\ConstraintInterface $constraint package version or version constraint to match against
|
||||
*
|
||||
* @return PackageInterface[]
|
||||
*/
|
||||
public function findPackages($name, $constraint = null)
|
||||
{
|
||||
$config = self::prepareConstraint($constraint);
|
||||
foreach ($packages = $this->repository->findPackages($name, $constraint) as $package) {
|
||||
self::preparePackage($package, $config);
|
||||
}
|
||||
return $packages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of registered packages.
|
||||
*
|
||||
* @return PackageInterface[]
|
||||
*/
|
||||
public function getPackages()
|
||||
{
|
||||
$packages = $this->repository->getPackages();
|
||||
foreach ($packages as $package) {
|
||||
self::preparePackage($package, []);
|
||||
}
|
||||
return $packages;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function search($query, $mode = 0, $type = null)
|
||||
{
|
||||
return $this->repository->search($query, $mode, $type);
|
||||
}
|
||||
|
||||
public function getProviderNames()
|
||||
{
|
||||
return $this->repository->getProviderNames();
|
||||
}
|
||||
|
||||
public function hasProviders()
|
||||
{
|
||||
return $this->repository->hasProviders();
|
||||
}
|
||||
public function resetPackageIds()
|
||||
{
|
||||
return $this->repository->resetPackageIds();
|
||||
}
|
||||
public function addPackage(PackageInterface $package)
|
||||
{
|
||||
$this->repository->addPackage($package);
|
||||
}
|
||||
/**
|
||||
* @param Pool $pool
|
||||
* @param string $name package name
|
||||
* @param bool $bypassFilters If set to true, this bypasses the stability filtering, and forces a recompute without cache
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function whatProvides(Pool $pool, $name, $bypassFilters = false)
|
||||
{
|
||||
$whatProvides = $this->repository->whatProvides($pool, $name, $bypassFilters);
|
||||
foreach ($whatProvides as $package => &$versions) {
|
||||
foreach ($versions as &$version) {
|
||||
if (!isset($version['require']['phabel/phabel'])) {
|
||||
continue;
|
||||
}
|
||||
$config = $version['extra']['phabel'] ?? [];
|
||||
if (!isset($config['target'])) {
|
||||
if (isset($version['require']['php'])) {
|
||||
$config['target'] = $version['require']['php'];
|
||||
} else {
|
||||
$config['target'] = '7.0';
|
||||
}
|
||||
}
|
||||
foreach ($version['require'] as $package => &$version) {
|
||||
$version = self::CONFIG_PREFIX.\json_encode($config)."\n".$version;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $whatProvides;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
namespace Phabel;
|
||||
|
||||
/**
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
*/
|
||||
class Context
|
||||
{
|
||||
}
|
||||
|
|
|
@ -15,6 +15,9 @@ use PhpParser\Node\Stmt\Expression;
|
|||
use PhpParser\ParserFactory;
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
*/
|
||||
abstract class Plugin implements PluginInterface
|
||||
{
|
||||
/**
|
||||
|
@ -31,7 +34,7 @@ abstract class Plugin implements PluginInterface
|
|||
* @param array $config
|
||||
* @return void
|
||||
*/
|
||||
public function setConfigArray(array $config)
|
||||
public function setConfigArray(array $config): void
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
@ -207,6 +210,13 @@ abstract class Plugin implements PluginInterface
|
|||
{
|
||||
return $configs;
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function splitConfig(array $config): array
|
||||
{
|
||||
return [$config];
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
|
|
@ -20,6 +20,8 @@ use SplStack;
|
|||
|
||||
/**
|
||||
* Enable memoization of results based on a parameter.
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
*/
|
||||
class Memoization
|
||||
{
|
||||
|
|
|
@ -11,6 +11,8 @@ use PhpParser\Node\UnionType;
|
|||
|
||||
/**
|
||||
* Replace all usages of a certain type in typehints.
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
*/
|
||||
class TypeHintStripper extends Plugin
|
||||
{
|
||||
|
|
|
@ -4,6 +4,8 @@ namespace Phabel;
|
|||
|
||||
/**
|
||||
* Caches plugin information.
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
*/
|
||||
class PluginCache
|
||||
{
|
||||
|
|
|
@ -4,6 +4,9 @@ namespace Phabel\PluginGraph;
|
|||
|
||||
use Phabel\PluginInterface;
|
||||
|
||||
/**
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
*/
|
||||
class CircularException extends \Exception
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -4,6 +4,8 @@ namespace Phabel\PluginGraph;
|
|||
|
||||
/**
|
||||
* Graph API wrapper.
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
*/
|
||||
class Graph
|
||||
{
|
||||
|
|
|
@ -6,6 +6,9 @@ use Phabel\PluginInterface;
|
|||
use SplObjectStorage;
|
||||
use SplQueue;
|
||||
|
||||
/**
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
*/
|
||||
class GraphInternal
|
||||
{
|
||||
/**
|
||||
|
@ -59,12 +62,7 @@ class GraphInternal
|
|||
*/
|
||||
public function addPlugin(string $plugin, array $config, PackageContext $ctx): array
|
||||
{
|
||||
$configs = $plugin::splitConfig($config);
|
||||
$nodes = [];
|
||||
foreach ($configs as $config) {
|
||||
$nodes []= $this->addPluginInternal($plugin, $config, $ctx);
|
||||
}
|
||||
return $nodes;
|
||||
return \array_map(fn (array $config): Node => $this->addPluginInternal($plugin, $config, $ctx), $plugin::splitConfig($config));
|
||||
}
|
||||
/**
|
||||
* Add plugin.
|
||||
|
|
|
@ -9,6 +9,8 @@ use SplQueue;
|
|||
|
||||
/**
|
||||
* Represents a plugin with a certain configuration.
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
*/
|
||||
class Node
|
||||
{
|
||||
|
|
|
@ -4,6 +4,8 @@ namespace Phabel\PluginGraph;
|
|||
|
||||
/**
|
||||
* List of packages associated with plugin.
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
*/
|
||||
class PackageContext
|
||||
{
|
||||
|
|
|
@ -7,6 +7,8 @@ use SplQueue;
|
|||
|
||||
/**
|
||||
* Representation of multiple plugins+configs.
|
||||
*
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
*/
|
||||
class Plugins
|
||||
{
|
||||
|
|
|
@ -4,6 +4,9 @@ namespace Phabel;
|
|||
|
||||
use Phabel\PluginGraph\PackageContext;
|
||||
|
||||
/**
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
*/
|
||||
interface PluginInterface
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Phabel\Target;
|
||||
|
||||
use Phabel\Plugin;
|
||||
use Phabel\PluginInterface;
|
||||
use Phabel\Target\Php70\AnonymousClassReplacer;
|
||||
use Phabel\Target\Php70\ClosureCallReplacer;
|
||||
use Phabel\Target\Php70\CompoundAccess;
|
||||
use Phabel\Target\Php70\DefineArrayReplacer;
|
||||
use Phabel\Target\Php70\GroupUseReplacer;
|
||||
use Phabel\Target\Php70\NullCoalesceReplacer;
|
||||
use Phabel\Target\Php70\ReservedNameReplacer;
|
||||
use Phabel\Target\Php70\ScalarTypeHintsRemover;
|
||||
use Phabel\Target\Php70\SpaceshipOperatorReplacer;
|
||||
use Phabel\Target\Php70\StrictTypesDeclareStatementRemover;
|
||||
use Phabel\Target\Php70\ThrowableReplacer;
|
||||
|
||||
/**
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
*/
|
||||
class Php70 extends Plugin
|
||||
{
|
||||
public static function runWithAfter(): array
|
||||
{
|
||||
return [
|
||||
AnonymousClassReplacer::class,
|
||||
ClosureCallReplacer::class,
|
||||
CompoundAccess::class,
|
||||
DefineArrayReplacer::class,
|
||||
GroupUseReplacer::class,
|
||||
NullCoalesceReplacer::class,
|
||||
ReservedNameReplacer::class,
|
||||
ScalarTypeHintsRemover::class,
|
||||
SpaceshipOperatorReplacer::class,
|
||||
StrictTypesDeclareStatementRemover::class,
|
||||
ThrowableReplacer::class
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,16 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Spatie\Php7to5\NodeVisitors;
|
||||
namespace Phabel\Target\Php70;
|
||||
|
||||
use Phabel\Plugin;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Declare_;
|
||||
use PhpParser\Node\Stmt\Namespace_;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use PhpParser\NodeVisitorAbstract;
|
||||
use Spatie\Php7to5\Converter;
|
||||
use Spatie\Php7to5\Exceptions\InvalidPhpCode;
|
||||
|
||||
class AnonymousClassReplacer extends NodeVisitorAbstract
|
||||
class AnonymousClassReplacer extends Plugin
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
|
@ -47,82 +47,4 @@ class AnonymousClassReplacer extends NodeVisitorAbstract
|
|||
|
||||
return $newNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function afterTraverse(array $nodes)
|
||||
{
|
||||
if (\count($this->anonymousClassNodes) === 0) {
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
$anonymousClassStatements = $this->anonymousClassNodes;
|
||||
|
||||
$anonymousClassStatements = $this->convertToPhp5Statements($anonymousClassStatements);
|
||||
|
||||
$hookIndex = $this->getAnonymousClassHookIndex($nodes);
|
||||
|
||||
$nodes = $this->moveAnonymousClassesToHook($nodes, $hookIndex, $anonymousClassStatements);
|
||||
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the index of the first statement that is not a declare, use or namespace statement.
|
||||
*
|
||||
* @param array $statements
|
||||
*
|
||||
* @return int
|
||||
*
|
||||
* @throws \Spatie\Php7to5\Exceptions\InvalidPhpCode
|
||||
*/
|
||||
protected function getAnonymousClassHookIndex(array $statements)
|
||||
{
|
||||
$hookIndex = false;
|
||||
|
||||
foreach ($statements as $index => $statement) {
|
||||
if (!$statement instanceof Declare_ &&
|
||||
!$statement instanceof Use_ &&
|
||||
!$statement instanceof Namespace_) {
|
||||
$hookIndex = $index;
|
||||
}
|
||||
}
|
||||
|
||||
if ($hookIndex === false) {
|
||||
return 1;
|
||||
//throw InvalidPhpCode::noValidLocationFoundToInsertClasses();
|
||||
}
|
||||
|
||||
return $hookIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $nodes
|
||||
* @param $hookIndex
|
||||
* @param $anonymousClassStatements
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function moveAnonymousClassesToHook(array $nodes, $hookIndex, $anonymousClassStatements)
|
||||
{
|
||||
$preStatements = \array_slice($nodes, 0, $hookIndex);
|
||||
$postStatements = \array_slice($nodes, $hookIndex);
|
||||
|
||||
return \array_merge($preStatements, $anonymousClassStatements, $postStatements);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $php7statements
|
||||
*
|
||||
* @return \PhpParser\Node[]
|
||||
*/
|
||||
public function convertToPhp5Statements(array $php7statements)
|
||||
{
|
||||
$converter = Converter::getTraverser($php7statements);
|
||||
|
||||
$php5Statements = $converter->traverse($php7statements);
|
||||
|
||||
return $php5Statements;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace Phabel\Target;
|
||||
|
||||
use Phabel\Plugin;
|
||||
use Phabel\PluginInterface;
|
||||
use Phabel\Target\Php70\AnonymousClassReplacer;
|
||||
use Phabel\Target\Php70\ClosureCallReplacer;
|
||||
use Phabel\Target\Php70\CompoundAccess;
|
||||
use Phabel\Target\Php70\DefineArrayReplacer;
|
||||
use Phabel\Target\Php70\GroupUseReplacer;
|
||||
use Phabel\Target\Php70\NullCoalesceReplacer;
|
||||
use Phabel\Target\Php70\ReservedNameReplacer;
|
||||
use Phabel\Target\Php70\ScalarTypeHintsRemover;
|
||||
use Phabel\Target\Php70\SpaceshipOperatorReplacer;
|
||||
use Phabel\Target\Php70\StrictTypesDeclareStatementRemover;
|
||||
use Phabel\Target\Php70\ThrowableReplacer;
|
||||
use Phabel\Target\Php71\ArrayList;
|
||||
use Phabel\Target\Php71\ClassConstantVisibilityModifiersRemover;
|
||||
use Phabel\Target\Php71\ListKey;
|
||||
use Phabel\Target\Php71\MultipleCatchReplacer;
|
||||
use Spatie\Php7to5\NodeVisitors\NullableTypeRemover;
|
||||
|
||||
/**
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
*/
|
||||
class Php71 extends Plugin
|
||||
{
|
||||
public static function runWithAfter(): array
|
||||
{
|
||||
return [
|
||||
ArrayList::class,
|
||||
ClassConstantVisibilityModifiersRemover::class,
|
||||
ListKey::class,
|
||||
MultipleCatchReplacer::class,
|
||||
NullableTypeRemover::class
|
||||
];
|
||||
}
|
||||
}
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
namespace Phabel;
|
||||
|
||||
/**
|
||||
* @author Daniil Gentili <daniil@daniil.it>
|
||||
*/
|
||||
class Traverser
|
||||
{
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue