init with kirby, vue and pagedjs interactive

This commit is contained in:
isUnknown 2025-11-24 14:01:48 +01:00
commit dc0ae26464
968 changed files with 211706 additions and 0 deletions

View file

@ -0,0 +1,122 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
class Bound
{
/**
* @var string
*/
private $version;
/**
* @var bool
*/
private $isInclusive;
/**
* @param string $version
* @param bool $isInclusive
*/
public function __construct($version, $isInclusive)
{
$this->version = $version;
$this->isInclusive = $isInclusive;
}
/**
* @return string
*/
public function getVersion()
{
return $this->version;
}
/**
* @return bool
*/
public function isInclusive()
{
return $this->isInclusive;
}
/**
* @return bool
*/
public function isZero()
{
return $this->getVersion() === '0.0.0.0-dev' && $this->isInclusive();
}
/**
* @return bool
*/
public function isPositiveInfinity()
{
return $this->getVersion() === PHP_INT_MAX.'.0.0.0' && !$this->isInclusive();
}
/**
* Compares a bound to another with a given operator.
*
* @param Bound $other
* @param string $operator
*
* @return bool
*/
public function compareTo(Bound $other, $operator)
{
if (!\in_array($operator, array('<', '>'), true)) {
throw new \InvalidArgumentException('Does not support any other operator other than > or <.');
}
// If they are the same it doesn't matter
if ($this == $other) {
return false;
}
$compareResult = version_compare($this->getVersion(), $other->getVersion());
// Not the same version means we don't need to check if the bounds are inclusive or not
if (0 !== $compareResult) {
return (('>' === $operator) ? 1 : -1) === $compareResult;
}
// Question we're answering here is "am I higher than $other?"
return '>' === $operator ? $other->isInclusive() : !$other->isInclusive();
}
public function __toString()
{
return sprintf(
'%s [%s]',
$this->getVersion(),
$this->isInclusive() ? 'inclusive' : 'exclusive'
);
}
/**
* @return self
*/
public static function zero()
{
return new Bound('0.0.0.0-dev', true);
}
/**
* @return self
*/
public static function positiveInfinity()
{
return new Bound(PHP_INT_MAX.'.0.0.0', false);
}
}

View file

@ -0,0 +1,435 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
/**
* Defines a constraint.
*/
class Constraint implements ConstraintInterface
{
/* operator integer values */
const OP_EQ = 0;
const OP_LT = 1;
const OP_LE = 2;
const OP_GT = 3;
const OP_GE = 4;
const OP_NE = 5;
/* operator string values */
const STR_OP_EQ = '==';
const STR_OP_EQ_ALT = '=';
const STR_OP_LT = '<';
const STR_OP_LE = '<=';
const STR_OP_GT = '>';
const STR_OP_GE = '>=';
const STR_OP_NE = '!=';
const STR_OP_NE_ALT = '<>';
/**
* Operator to integer translation table.
*
* @var array
* @phpstan-var array<self::STR_OP_*, self::OP_*>
*/
private static $transOpStr = array(
'=' => self::OP_EQ,
'==' => self::OP_EQ,
'<' => self::OP_LT,
'<=' => self::OP_LE,
'>' => self::OP_GT,
'>=' => self::OP_GE,
'<>' => self::OP_NE,
'!=' => self::OP_NE,
);
/**
* Integer to operator translation table.
*
* @var array
* @phpstan-var array<self::OP_*, self::STR_OP_*>
*/
private static $transOpInt = array(
self::OP_EQ => '==',
self::OP_LT => '<',
self::OP_LE => '<=',
self::OP_GT => '>',
self::OP_GE => '>=',
self::OP_NE => '!=',
);
/**
* @var int
* @phpstan-var self::OP_*
*/
protected $operator;
/** @var string */
protected $version;
/** @var string|null */
protected $prettyString;
/** @var Bound */
protected $lowerBound;
/** @var Bound */
protected $upperBound;
/**
* Sets operator and version to compare with.
*
* @param string $operator
* @param string $version
*
* @throws \InvalidArgumentException if invalid operator is given.
*
* @phpstan-param self::STR_OP_* $operator
*/
public function __construct($operator, $version)
{
if (!isset(self::$transOpStr[$operator])) {
throw new \InvalidArgumentException(sprintf(
'Invalid operator "%s" given, expected one of: %s',
$operator,
implode(', ', self::getSupportedOperators())
));
}
$this->operator = self::$transOpStr[$operator];
$this->version = $version;
}
/**
* @return string
*/
public function getVersion()
{
return $this->version;
}
/**
* @return string
*
* @phpstan-return self::STR_OP_*
*/
public function getOperator()
{
return self::$transOpInt[$this->operator];
}
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider)
{
if ($provider instanceof self) {
return $this->matchSpecific($provider);
}
// turn matching around to find a match
return $provider->matches($this);
}
/**
* {@inheritDoc}
*/
public function setPrettyString($prettyString)
{
$this->prettyString = $prettyString;
}
/**
* {@inheritDoc}
*/
public function getPrettyString()
{
if ($this->prettyString) {
return $this->prettyString;
}
return $this->__toString();
}
/**
* Get all supported comparison operators.
*
* @return array
*
* @phpstan-return list<self::STR_OP_*>
*/
public static function getSupportedOperators()
{
return array_keys(self::$transOpStr);
}
/**
* @param string $operator
* @return int
*
* @phpstan-param self::STR_OP_* $operator
* @phpstan-return self::OP_*
*/
public static function getOperatorConstant($operator)
{
return self::$transOpStr[$operator];
}
/**
* @param string $a
* @param string $b
* @param string $operator
* @param bool $compareBranches
*
* @throws \InvalidArgumentException if invalid operator is given.
*
* @return bool
*
* @phpstan-param self::STR_OP_* $operator
*/
public function versionCompare($a, $b, $operator, $compareBranches = false)
{
if (!isset(self::$transOpStr[$operator])) {
throw new \InvalidArgumentException(sprintf(
'Invalid operator "%s" given, expected one of: %s',
$operator,
implode(', ', self::getSupportedOperators())
));
}
$aIsBranch = strpos($a, 'dev-') === 0;
$bIsBranch = strpos($b, 'dev-') === 0;
if ($operator === '!=' && ($aIsBranch || $bIsBranch)) {
return $a !== $b;
}
if ($aIsBranch && $bIsBranch) {
return $operator === '==' && $a === $b;
}
// when branches are not comparable, we make sure dev branches never match anything
if (!$compareBranches && ($aIsBranch || $bIsBranch)) {
return false;
}
return \version_compare($a, $b, $operator);
}
/**
* {@inheritDoc}
*/
public function compile($otherOperator)
{
if (strpos($this->version, 'dev-') === 0) {
if (self::OP_EQ === $this->operator) {
if (self::OP_EQ === $otherOperator) {
return sprintf('$b && $v === %s', \var_export($this->version, true));
}
if (self::OP_NE === $otherOperator) {
return sprintf('!$b || $v !== %s', \var_export($this->version, true));
}
return 'false';
}
if (self::OP_NE === $this->operator) {
if (self::OP_EQ === $otherOperator) {
return sprintf('!$b || $v !== %s', \var_export($this->version, true));
}
if (self::OP_NE === $otherOperator) {
return 'true';
}
return '!$b';
}
return 'false';
}
if (self::OP_EQ === $this->operator) {
if (self::OP_EQ === $otherOperator) {
return sprintf('\version_compare($v, %s, \'==\')', \var_export($this->version, true));
}
if (self::OP_NE === $otherOperator) {
return sprintf('$b || \version_compare($v, %s, \'!=\')', \var_export($this->version, true));
}
return sprintf('!$b && \version_compare(%s, $v, \'%s\')', \var_export($this->version, true), self::$transOpInt[$otherOperator]);
}
if (self::OP_NE === $this->operator) {
if (self::OP_EQ === $otherOperator) {
return sprintf('$b || (!$b && \version_compare($v, %s, \'!=\'))', \var_export($this->version, true));
}
if (self::OP_NE === $otherOperator) {
return 'true';
}
return '!$b';
}
if (self::OP_LT === $this->operator || self::OP_LE === $this->operator) {
if (self::OP_LT === $otherOperator || self::OP_LE === $otherOperator) {
return '!$b';
}
} else { // $this->operator must be self::OP_GT || self::OP_GE here
if (self::OP_GT === $otherOperator || self::OP_GE === $otherOperator) {
return '!$b';
}
}
if (self::OP_NE === $otherOperator) {
return 'true';
}
$codeComparison = sprintf('\version_compare($v, %s, \'%s\')', \var_export($this->version, true), self::$transOpInt[$this->operator]);
if ($this->operator === self::OP_LE) {
if ($otherOperator === self::OP_GT) {
return sprintf('!$b && \version_compare($v, %s, \'!=\') && ', \var_export($this->version, true)) . $codeComparison;
}
} elseif ($this->operator === self::OP_GE) {
if ($otherOperator === self::OP_LT) {
return sprintf('!$b && \version_compare($v, %s, \'!=\') && ', \var_export($this->version, true)) . $codeComparison;
}
}
return sprintf('!$b && %s', $codeComparison);
}
/**
* @param Constraint $provider
* @param bool $compareBranches
*
* @return bool
*/
public function matchSpecific(Constraint $provider, $compareBranches = false)
{
$noEqualOp = str_replace('=', '', self::$transOpInt[$this->operator]);
$providerNoEqualOp = str_replace('=', '', self::$transOpInt[$provider->operator]);
$isEqualOp = self::OP_EQ === $this->operator;
$isNonEqualOp = self::OP_NE === $this->operator;
$isProviderEqualOp = self::OP_EQ === $provider->operator;
$isProviderNonEqualOp = self::OP_NE === $provider->operator;
// '!=' operator is match when other operator is not '==' operator or version is not match
// these kinds of comparisons always have a solution
if ($isNonEqualOp || $isProviderNonEqualOp) {
if ($isNonEqualOp && !$isProviderNonEqualOp && !$isProviderEqualOp && strpos($provider->version, 'dev-') === 0) {
return false;
}
if ($isProviderNonEqualOp && !$isNonEqualOp && !$isEqualOp && strpos($this->version, 'dev-') === 0) {
return false;
}
if (!$isEqualOp && !$isProviderEqualOp) {
return true;
}
return $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
}
// an example for the condition is <= 2.0 & < 1.0
// these kinds of comparisons always have a solution
if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) {
return !(strpos($this->version, 'dev-') === 0 || strpos($provider->version, 'dev-') === 0);
}
$version1 = $isEqualOp ? $this->version : $provider->version;
$version2 = $isEqualOp ? $provider->version : $this->version;
$operator = $isEqualOp ? $provider->operator : $this->operator;
if ($this->versionCompare($version1, $version2, self::$transOpInt[$operator], $compareBranches)) {
// special case, e.g. require >= 1.0 and provide < 1.0
// 1.0 >= 1.0 but 1.0 is outside of the provided interval
return !(self::$transOpInt[$provider->operator] === $providerNoEqualOp
&& self::$transOpInt[$this->operator] !== $noEqualOp
&& \version_compare($provider->version, $this->version, '=='));
}
return false;
}
/**
* @return string
*/
public function __toString()
{
return self::$transOpInt[$this->operator] . ' ' . $this->version;
}
/**
* {@inheritDoc}
*/
public function getLowerBound()
{
$this->extractBounds();
return $this->lowerBound;
}
/**
* {@inheritDoc}
*/
public function getUpperBound()
{
$this->extractBounds();
return $this->upperBound;
}
/**
* @return void
*/
private function extractBounds()
{
if (null !== $this->lowerBound) {
return;
}
// Branches
if (strpos($this->version, 'dev-') === 0) {
$this->lowerBound = Bound::zero();
$this->upperBound = Bound::positiveInfinity();
return;
}
switch ($this->operator) {
case self::OP_EQ:
$this->lowerBound = new Bound($this->version, true);
$this->upperBound = new Bound($this->version, true);
break;
case self::OP_LT:
$this->lowerBound = Bound::zero();
$this->upperBound = new Bound($this->version, false);
break;
case self::OP_LE:
$this->lowerBound = Bound::zero();
$this->upperBound = new Bound($this->version, true);
break;
case self::OP_GT:
$this->lowerBound = new Bound($this->version, false);
$this->upperBound = Bound::positiveInfinity();
break;
case self::OP_GE:
$this->lowerBound = new Bound($this->version, true);
$this->upperBound = Bound::positiveInfinity();
break;
case self::OP_NE:
$this->lowerBound = Bound::zero();
$this->upperBound = Bound::positiveInfinity();
break;
}
}
}

View file

@ -0,0 +1,75 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
/**
* DO NOT IMPLEMENT this interface. It is only meant for usage as a type hint
* in libraries relying on composer/semver but creating your own constraint class
* that implements this interface is not a supported use case and will cause the
* composer/semver components to return unexpected results.
*/
interface ConstraintInterface
{
/**
* Checks whether the given constraint intersects in any way with this constraint
*
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider);
/**
* Provides a compiled version of the constraint for the given operator
* The compiled version must be a PHP expression.
* Executor of compile version must provide 2 variables:
* - $v = the string version to compare with
* - $b = whether or not the version is a non-comparable branch (starts with "dev-")
*
* @see Constraint::OP_* for the list of available operators.
* @example return '!$b && version_compare($v, '1.0', '>')';
*
* @param int $otherOperator one Constraint::OP_*
*
* @return string
*
* @phpstan-param Constraint::OP_* $otherOperator
*/
public function compile($otherOperator);
/**
* @return Bound
*/
public function getUpperBound();
/**
* @return Bound
*/
public function getLowerBound();
/**
* @return string
*/
public function getPrettyString();
/**
* @param string|null $prettyString
*
* @return void
*/
public function setPrettyString($prettyString);
/**
* @return string
*/
public function __toString();
}

View file

@ -0,0 +1,85 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
/**
* Defines the absence of a constraint.
*
* This constraint matches everything.
*/
class MatchAllConstraint implements ConstraintInterface
{
/** @var string|null */
protected $prettyString;
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider)
{
return true;
}
/**
* {@inheritDoc}
*/
public function compile($otherOperator)
{
return 'true';
}
/**
* {@inheritDoc}
*/
public function setPrettyString($prettyString)
{
$this->prettyString = $prettyString;
}
/**
* {@inheritDoc}
*/
public function getPrettyString()
{
if ($this->prettyString) {
return $this->prettyString;
}
return (string) $this;
}
/**
* {@inheritDoc}
*/
public function __toString()
{
return '*';
}
/**
* {@inheritDoc}
*/
public function getUpperBound()
{
return Bound::positiveInfinity();
}
/**
* {@inheritDoc}
*/
public function getLowerBound()
{
return Bound::zero();
}
}

View file

@ -0,0 +1,83 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
/**
* Blackhole of constraints, nothing escapes it
*/
class MatchNoneConstraint implements ConstraintInterface
{
/** @var string|null */
protected $prettyString;
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider)
{
return false;
}
/**
* {@inheritDoc}
*/
public function compile($otherOperator)
{
return 'false';
}
/**
* {@inheritDoc}
*/
public function setPrettyString($prettyString)
{
$this->prettyString = $prettyString;
}
/**
* {@inheritDoc}
*/
public function getPrettyString()
{
if ($this->prettyString) {
return $this->prettyString;
}
return (string) $this;
}
/**
* {@inheritDoc}
*/
public function __toString()
{
return '[]';
}
/**
* {@inheritDoc}
*/
public function getUpperBound()
{
return new Bound('0.0.0.0-dev', false);
}
/**
* {@inheritDoc}
*/
public function getLowerBound()
{
return new Bound('0.0.0.0-dev', false);
}
}

View file

@ -0,0 +1,325 @@
<?php
/*
* This file is part of composer/semver.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\Semver\Constraint;
/**
* Defines a conjunctive or disjunctive set of constraints.
*/
class MultiConstraint implements ConstraintInterface
{
/**
* @var ConstraintInterface[]
* @phpstan-var non-empty-array<ConstraintInterface>
*/
protected $constraints;
/** @var string|null */
protected $prettyString;
/** @var string|null */
protected $string;
/** @var bool */
protected $conjunctive;
/** @var Bound|null */
protected $lowerBound;
/** @var Bound|null */
protected $upperBound;
/**
* @param ConstraintInterface[] $constraints A set of constraints
* @param bool $conjunctive Whether the constraints should be treated as conjunctive or disjunctive
*
* @throws \InvalidArgumentException If less than 2 constraints are passed
*/
public function __construct(array $constraints, $conjunctive = true)
{
if (\count($constraints) < 2) {
throw new \InvalidArgumentException(
'Must provide at least two constraints for a MultiConstraint. Use '.
'the regular Constraint class for one constraint only or MatchAllConstraint for none. You may use '.
'MultiConstraint::create() which optimizes and handles those cases automatically.'
);
}
$this->constraints = $constraints;
$this->conjunctive = $conjunctive;
}
/**
* @return ConstraintInterface[]
*/
public function getConstraints()
{
return $this->constraints;
}
/**
* @return bool
*/
public function isConjunctive()
{
return $this->conjunctive;
}
/**
* @return bool
*/
public function isDisjunctive()
{
return !$this->conjunctive;
}
/**
* {@inheritDoc}
*/
public function compile($otherOperator)
{
$parts = array();
foreach ($this->constraints as $constraint) {
$code = $constraint->compile($otherOperator);
if ($code === 'true') {
if (!$this->conjunctive) {
return 'true';
}
} elseif ($code === 'false') {
if ($this->conjunctive) {
return 'false';
}
} else {
$parts[] = '('.$code.')';
}
}
if (!$parts) {
return $this->conjunctive ? 'true' : 'false';
}
return $this->conjunctive ? implode('&&', $parts) : implode('||', $parts);
}
/**
* @param ConstraintInterface $provider
*
* @return bool
*/
public function matches(ConstraintInterface $provider)
{
if (false === $this->conjunctive) {
foreach ($this->constraints as $constraint) {
if ($provider->matches($constraint)) {
return true;
}
}
return false;
}
// when matching a conjunctive and a disjunctive multi constraint we have to iterate over the disjunctive one
// otherwise we'd return true if different parts of the disjunctive constraint match the conjunctive one
// which would lead to incorrect results, e.g. [>1 and <2] would match [<1 or >2] although they do not intersect
if ($provider instanceof MultiConstraint && $provider->isDisjunctive()) {
return $provider->matches($this);
}
foreach ($this->constraints as $constraint) {
if (!$provider->matches($constraint)) {
return false;
}
}
return true;
}
/**
* {@inheritDoc}
*/
public function setPrettyString($prettyString)
{
$this->prettyString = $prettyString;
}
/**
* {@inheritDoc}
*/
public function getPrettyString()
{
if ($this->prettyString) {
return $this->prettyString;
}
return (string) $this;
}
/**
* {@inheritDoc}
*/
public function __toString()
{
if ($this->string !== null) {
return $this->string;
}
$constraints = array();
foreach ($this->constraints as $constraint) {
$constraints[] = (string) $constraint;
}
return $this->string = '[' . implode($this->conjunctive ? ' ' : ' || ', $constraints) . ']';
}
/**
* {@inheritDoc}
*/
public function getLowerBound()
{
$this->extractBounds();
if (null === $this->lowerBound) {
throw new \LogicException('extractBounds should have populated the lowerBound property');
}
return $this->lowerBound;
}
/**
* {@inheritDoc}
*/
public function getUpperBound()
{
$this->extractBounds();
if (null === $this->upperBound) {
throw new \LogicException('extractBounds should have populated the upperBound property');
}
return $this->upperBound;
}
/**
* Tries to optimize the constraints as much as possible, meaning
* reducing/collapsing congruent constraints etc.
* Does not necessarily return a MultiConstraint instance if
* things can be reduced to a simple constraint
*
* @param ConstraintInterface[] $constraints A set of constraints
* @param bool $conjunctive Whether the constraints should be treated as conjunctive or disjunctive
*
* @return ConstraintInterface
*/
public static function create(array $constraints, $conjunctive = true)
{
if (0 === \count($constraints)) {
return new MatchAllConstraint();
}
if (1 === \count($constraints)) {
return $constraints[0];
}
$optimized = self::optimizeConstraints($constraints, $conjunctive);
if ($optimized !== null) {
list($constraints, $conjunctive) = $optimized;
if (\count($constraints) === 1) {
return $constraints[0];
}
}
return new self($constraints, $conjunctive);
}
/**
* @param ConstraintInterface[] $constraints
* @param bool $conjunctive
* @return ?array
*
* @phpstan-return array{0: list<ConstraintInterface>, 1: bool}|null
*/
private static function optimizeConstraints(array $constraints, $conjunctive)
{
// parse the two OR groups and if they are contiguous we collapse
// them into one constraint
// [>= 1 < 2] || [>= 2 < 3] || [>= 3 < 4] => [>= 1 < 4]
if (!$conjunctive) {
$left = $constraints[0];
$mergedConstraints = array();
$optimized = false;
for ($i = 1, $l = \count($constraints); $i < $l; $i++) {
$right = $constraints[$i];
if (
$left instanceof self
&& $left->conjunctive
&& $right instanceof self
&& $right->conjunctive
&& \count($left->constraints) === 2
&& \count($right->constraints) === 2
&& ($left0 = (string) $left->constraints[0])
&& $left0[0] === '>' && $left0[1] === '='
&& ($left1 = (string) $left->constraints[1])
&& $left1[0] === '<'
&& ($right0 = (string) $right->constraints[0])
&& $right0[0] === '>' && $right0[1] === '='
&& ($right1 = (string) $right->constraints[1])
&& $right1[0] === '<'
&& substr($left1, 2) === substr($right0, 3)
) {
$optimized = true;
$left = new MultiConstraint(
array(
$left->constraints[0],
$right->constraints[1],
),
true);
} else {
$mergedConstraints[] = $left;
$left = $right;
}
}
if ($optimized) {
$mergedConstraints[] = $left;
return array($mergedConstraints, false);
}
}
// TODO: Here's the place to put more optimizations
return null;
}
/**
* @return void
*/
private function extractBounds()
{
if (null !== $this->lowerBound) {
return;
}
foreach ($this->constraints as $constraint) {
if (null === $this->lowerBound || null === $this->upperBound) {
$this->lowerBound = $constraint->getLowerBound();
$this->upperBound = $constraint->getUpperBound();
continue;
}
if ($constraint->getLowerBound()->compareTo($this->lowerBound, $this->isConjunctive() ? '>' : '<')) {
$this->lowerBound = $constraint->getLowerBound();
}
if ($constraint->getUpperBound()->compareTo($this->upperBound, $this->isConjunctive() ? '<' : '>')) {
$this->upperBound = $constraint->getUpperBound();
}
}
}
}