From 5dcf37c9247af2d56891a1d389b8180074e7fe47 Mon Sep 17 00:00:00 2001 From: mgiannopoulos24 <79588074+mgiannopoulos24@users.noreply.github.com> Date: Sun, 17 May 2026 12:39:18 +0300 Subject: [PATCH 01/10] Remove vendor and add on gitignore --- .gitignore | 8 +- vendor/autoload.php | 22 - vendor/composer/ClassLoader.php | 579 -------- vendor/composer/InstalledVersions.php | 396 ------ vendor/composer/LICENSE | 21 - vendor/composer/autoload_classmap.php | 25 - vendor/composer/autoload_namespaces.php | 9 - vendor/composer/autoload_psr4.php | 10 - vendor/composer/autoload_real.php | 38 - vendor/composer/autoload_static.php | 51 - vendor/composer/installed.json | 66 - vendor/composer/installed.php | 32 - vendor/composer/platform_check.php | 25 - vendor/nxp/math-executor/.gitattributes | 2 - .../math-executor/.github/workflows/tests.yml | 35 - vendor/nxp/math-executor/.gitignore | 7 - vendor/nxp/math-executor/.php-cs-fixer.php | 282 ---- vendor/nxp/math-executor/LICENSE | 19 - vendor/nxp/math-executor/README.md | 249 ---- vendor/nxp/math-executor/code-of-conduct.md | 9 - .../nxp/math-executor/code-of-conduct.ru.md | 5 - vendor/nxp/math-executor/composer.json | 47 - vendor/nxp/math-executor/phpstan.neon | 9 - vendor/nxp/math-executor/phpunit.xml.dist | 19 - .../src/NXP/Classes/Calculator.php | 93 -- .../src/NXP/Classes/CustomFunction.php | 66 - .../src/NXP/Classes/Operator.php | 56 - .../math-executor/src/NXP/Classes/Token.php | 43 - .../src/NXP/Classes/Tokenizer.php | 415 ------ .../NXP/Exception/DivisionByZeroException.php | 19 - .../Exception/IncorrectBracketsException.php | 19 - .../IncorrectExpressionException.php | 19 - .../IncorrectFunctionParameterException.php | 16 - ...ectNumberOfFunctionParametersException.php | 16 - .../NXP/Exception/MathExecutorException.php | 19 - .../Exception/UnknownFunctionException.php | 19 - .../Exception/UnknownOperatorException.php | 19 - .../Exception/UnknownVariableException.php | 19 - .../math-executor/src/NXP/MathExecutor.php | 532 -------- vendor/nxp/math-executor/tests/MathTest.php | 1163 ----------------- vendor/nxp/math-executor/tests/bootstrap.php | 11 - 41 files changed, 4 insertions(+), 4505 deletions(-) delete mode 100644 vendor/autoload.php delete mode 100644 vendor/composer/ClassLoader.php delete mode 100644 vendor/composer/InstalledVersions.php delete mode 100644 vendor/composer/LICENSE delete mode 100644 vendor/composer/autoload_classmap.php delete mode 100644 vendor/composer/autoload_namespaces.php delete mode 100644 vendor/composer/autoload_psr4.php delete mode 100644 vendor/composer/autoload_real.php delete mode 100644 vendor/composer/autoload_static.php delete mode 100644 vendor/composer/installed.json delete mode 100644 vendor/composer/installed.php delete mode 100644 vendor/composer/platform_check.php delete mode 100644 vendor/nxp/math-executor/.gitattributes delete mode 100644 vendor/nxp/math-executor/.github/workflows/tests.yml delete mode 100644 vendor/nxp/math-executor/.gitignore delete mode 100644 vendor/nxp/math-executor/.php-cs-fixer.php delete mode 100644 vendor/nxp/math-executor/LICENSE delete mode 100644 vendor/nxp/math-executor/README.md delete mode 100644 vendor/nxp/math-executor/code-of-conduct.md delete mode 100644 vendor/nxp/math-executor/code-of-conduct.ru.md delete mode 100644 vendor/nxp/math-executor/composer.json delete mode 100644 vendor/nxp/math-executor/phpstan.neon delete mode 100644 vendor/nxp/math-executor/phpunit.xml.dist delete mode 100644 vendor/nxp/math-executor/src/NXP/Classes/Calculator.php delete mode 100644 vendor/nxp/math-executor/src/NXP/Classes/CustomFunction.php delete mode 100644 vendor/nxp/math-executor/src/NXP/Classes/Operator.php delete mode 100644 vendor/nxp/math-executor/src/NXP/Classes/Token.php delete mode 100644 vendor/nxp/math-executor/src/NXP/Classes/Tokenizer.php delete mode 100644 vendor/nxp/math-executor/src/NXP/Exception/DivisionByZeroException.php delete mode 100644 vendor/nxp/math-executor/src/NXP/Exception/IncorrectBracketsException.php delete mode 100644 vendor/nxp/math-executor/src/NXP/Exception/IncorrectExpressionException.php delete mode 100644 vendor/nxp/math-executor/src/NXP/Exception/IncorrectFunctionParameterException.php delete mode 100644 vendor/nxp/math-executor/src/NXP/Exception/IncorrectNumberOfFunctionParametersException.php delete mode 100644 vendor/nxp/math-executor/src/NXP/Exception/MathExecutorException.php delete mode 100644 vendor/nxp/math-executor/src/NXP/Exception/UnknownFunctionException.php delete mode 100644 vendor/nxp/math-executor/src/NXP/Exception/UnknownOperatorException.php delete mode 100644 vendor/nxp/math-executor/src/NXP/Exception/UnknownVariableException.php delete mode 100644 vendor/nxp/math-executor/src/NXP/MathExecutor.php delete mode 100644 vendor/nxp/math-executor/tests/MathTest.php delete mode 100644 vendor/nxp/math-executor/tests/bootstrap.php diff --git a/.gitignore b/.gitignore index 314f8d8..61f6abf 100644 --- a/.gitignore +++ b/.gitignore @@ -6,10 +6,13 @@ # DDEV .ddev/ +.ddev/docker-compose.cooked.yaml -# Node.js +# Dev dependencies node_modules/ +vendor +# Tests tests/test-results/ tests/playwright-report/ tests/blob-report/ @@ -19,8 +22,5 @@ tests/.auth/ # Build build/* -# DDEV generated files -.ddev/docker-compose.cooked.yaml - # WordPress wordpress/ \ No newline at end of file diff --git a/vendor/autoload.php b/vendor/autoload.php deleted file mode 100644 index 9c07ee1..0000000 --- a/vendor/autoload.php +++ /dev/null @@ -1,22 +0,0 @@ - - * Jordi Boggiano - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Composer\Autoload; - -/** - * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. - * - * $loader = new \Composer\Autoload\ClassLoader(); - * - * // register classes with namespaces - * $loader->add('Symfony\Component', __DIR__.'/component'); - * $loader->add('Symfony', __DIR__.'/framework'); - * - * // activate the autoloader - * $loader->register(); - * - * // to enable searching the include path (eg. for PEAR packages) - * $loader->setUseIncludePath(true); - * - * In this example, if you try to use a class in the Symfony\Component - * namespace or one of its children (Symfony\Component\Console for instance), - * the autoloader will first look for the class under the component/ - * directory, and it will then fallback to the framework/ directory if not - * found before giving up. - * - * This class is loosely based on the Symfony UniversalClassLoader. - * - * @author Fabien Potencier - * @author Jordi Boggiano - * @see https://www.php-fig.org/psr/psr-0/ - * @see https://www.php-fig.org/psr/psr-4/ - */ -class ClassLoader -{ - /** @var \Closure(string):void */ - private static $includeFile; - - /** @var string|null */ - private $vendorDir; - - // PSR-4 - /** - * @var array> - */ - private $prefixLengthsPsr4 = array(); - /** - * @var array> - */ - private $prefixDirsPsr4 = array(); - /** - * @var list - */ - private $fallbackDirsPsr4 = array(); - - // PSR-0 - /** - * List of PSR-0 prefixes - * - * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) - * - * @var array>> - */ - private $prefixesPsr0 = array(); - /** - * @var list - */ - private $fallbackDirsPsr0 = array(); - - /** @var bool */ - private $useIncludePath = false; - - /** - * @var array - */ - private $classMap = array(); - - /** @var bool */ - private $classMapAuthoritative = false; - - /** - * @var array - */ - private $missingClasses = array(); - - /** @var string|null */ - private $apcuPrefix; - - /** - * @var array - */ - private static $registeredLoaders = array(); - - /** - * @param string|null $vendorDir - */ - public function __construct($vendorDir = null) - { - $this->vendorDir = $vendorDir; - self::initializeIncludeClosure(); - } - - /** - * @return array> - */ - public function getPrefixes() - { - if (!empty($this->prefixesPsr0)) { - return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); - } - - return array(); - } - - /** - * @return array> - */ - public function getPrefixesPsr4() - { - return $this->prefixDirsPsr4; - } - - /** - * @return list - */ - public function getFallbackDirs() - { - return $this->fallbackDirsPsr0; - } - - /** - * @return list - */ - public function getFallbackDirsPsr4() - { - return $this->fallbackDirsPsr4; - } - - /** - * @return array Array of classname => path - */ - public function getClassMap() - { - return $this->classMap; - } - - /** - * @param array $classMap Class to filename map - * - * @return void - */ - public function addClassMap(array $classMap) - { - if ($this->classMap) { - $this->classMap = array_merge($this->classMap, $classMap); - } else { - $this->classMap = $classMap; - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, either - * appending or prepending to the ones previously set for this prefix. - * - * @param string $prefix The prefix - * @param list|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories - * - * @return void - */ - public function add($prefix, $paths, $prepend = false) - { - $paths = (array) $paths; - if (!$prefix) { - if ($prepend) { - $this->fallbackDirsPsr0 = array_merge( - $paths, - $this->fallbackDirsPsr0 - ); - } else { - $this->fallbackDirsPsr0 = array_merge( - $this->fallbackDirsPsr0, - $paths - ); - } - - return; - } - - $first = $prefix[0]; - if (!isset($this->prefixesPsr0[$first][$prefix])) { - $this->prefixesPsr0[$first][$prefix] = $paths; - - return; - } - if ($prepend) { - $this->prefixesPsr0[$first][$prefix] = array_merge( - $paths, - $this->prefixesPsr0[$first][$prefix] - ); - } else { - $this->prefixesPsr0[$first][$prefix] = array_merge( - $this->prefixesPsr0[$first][$prefix], - $paths - ); - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, either - * appending or prepending to the ones previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param list|string $paths The PSR-4 base directories - * @param bool $prepend Whether to prepend the directories - * - * @throws \InvalidArgumentException - * - * @return void - */ - public function addPsr4($prefix, $paths, $prepend = false) - { - $paths = (array) $paths; - if (!$prefix) { - // Register directories for the root namespace. - if ($prepend) { - $this->fallbackDirsPsr4 = array_merge( - $paths, - $this->fallbackDirsPsr4 - ); - } else { - $this->fallbackDirsPsr4 = array_merge( - $this->fallbackDirsPsr4, - $paths - ); - } - } elseif (!isset($this->prefixDirsPsr4[$prefix])) { - // Register directories for a new namespace. - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = $paths; - } elseif ($prepend) { - // Prepend directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - $paths, - $this->prefixDirsPsr4[$prefix] - ); - } else { - // Append directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - $this->prefixDirsPsr4[$prefix], - $paths - ); - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, - * replacing any others previously set for this prefix. - * - * @param string $prefix The prefix - * @param list|string $paths The PSR-0 base directories - * - * @return void - */ - public function set($prefix, $paths) - { - if (!$prefix) { - $this->fallbackDirsPsr0 = (array) $paths; - } else { - $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, - * replacing any others previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param list|string $paths The PSR-4 base directories - * - * @throws \InvalidArgumentException - * - * @return void - */ - public function setPsr4($prefix, $paths) - { - if (!$prefix) { - $this->fallbackDirsPsr4 = (array) $paths; - } else { - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; - } - } - - /** - * Turns on searching the include path for class files. - * - * @param bool $useIncludePath - * - * @return void - */ - public function setUseIncludePath($useIncludePath) - { - $this->useIncludePath = $useIncludePath; - } - - /** - * Can be used to check if the autoloader uses the include path to check - * for classes. - * - * @return bool - */ - public function getUseIncludePath() - { - return $this->useIncludePath; - } - - /** - * Turns off searching the prefix and fallback directories for classes - * that have not been registered with the class map. - * - * @param bool $classMapAuthoritative - * - * @return void - */ - public function setClassMapAuthoritative($classMapAuthoritative) - { - $this->classMapAuthoritative = $classMapAuthoritative; - } - - /** - * Should class lookup fail if not found in the current class map? - * - * @return bool - */ - public function isClassMapAuthoritative() - { - return $this->classMapAuthoritative; - } - - /** - * APCu prefix to use to cache found/not-found classes, if the extension is enabled. - * - * @param string|null $apcuPrefix - * - * @return void - */ - public function setApcuPrefix($apcuPrefix) - { - $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; - } - - /** - * The APCu prefix in use, or null if APCu caching is not enabled. - * - * @return string|null - */ - public function getApcuPrefix() - { - return $this->apcuPrefix; - } - - /** - * Registers this instance as an autoloader. - * - * @param bool $prepend Whether to prepend the autoloader or not - * - * @return void - */ - public function register($prepend = false) - { - spl_autoload_register(array($this, 'loadClass'), true, $prepend); - - if (null === $this->vendorDir) { - return; - } - - if ($prepend) { - self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; - } else { - unset(self::$registeredLoaders[$this->vendorDir]); - self::$registeredLoaders[$this->vendorDir] = $this; - } - } - - /** - * Unregisters this instance as an autoloader. - * - * @return void - */ - public function unregister() - { - spl_autoload_unregister(array($this, 'loadClass')); - - if (null !== $this->vendorDir) { - unset(self::$registeredLoaders[$this->vendorDir]); - } - } - - /** - * Loads the given class or interface. - * - * @param string $class The name of the class - * @return true|null True if loaded, null otherwise - */ - public function loadClass($class) - { - if ($file = $this->findFile($class)) { - $includeFile = self::$includeFile; - $includeFile($file); - - return true; - } - - return null; - } - - /** - * Finds the path to the file where the class is defined. - * - * @param string $class The name of the class - * - * @return string|false The path if found, false otherwise - */ - public function findFile($class) - { - // class map lookup - if (isset($this->classMap[$class])) { - return $this->classMap[$class]; - } - if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { - return false; - } - if (null !== $this->apcuPrefix) { - $file = apcu_fetch($this->apcuPrefix.$class, $hit); - if ($hit) { - return $file; - } - } - - $file = $this->findFileWithExtension($class, '.php'); - - // Search for Hack files if we are running on HHVM - if (false === $file && defined('HHVM_VERSION')) { - $file = $this->findFileWithExtension($class, '.hh'); - } - - if (null !== $this->apcuPrefix) { - apcu_add($this->apcuPrefix.$class, $file); - } - - if (false === $file) { - // Remember that this class does not exist. - $this->missingClasses[$class] = true; - } - - return $file; - } - - /** - * Returns the currently registered loaders keyed by their corresponding vendor directories. - * - * @return array - */ - public static function getRegisteredLoaders() - { - return self::$registeredLoaders; - } - - /** - * @param string $class - * @param string $ext - * @return string|false - */ - private function findFileWithExtension($class, $ext) - { - // PSR-4 lookup - $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; - - $first = $class[0]; - if (isset($this->prefixLengthsPsr4[$first])) { - $subPath = $class; - while (false !== $lastPos = strrpos($subPath, '\\')) { - $subPath = substr($subPath, 0, $lastPos); - $search = $subPath . '\\'; - if (isset($this->prefixDirsPsr4[$search])) { - $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); - foreach ($this->prefixDirsPsr4[$search] as $dir) { - if (file_exists($file = $dir . $pathEnd)) { - return $file; - } - } - } - } - } - - // PSR-4 fallback dirs - foreach ($this->fallbackDirsPsr4 as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { - return $file; - } - } - - // PSR-0 lookup - if (false !== $pos = strrpos($class, '\\')) { - // namespaced class name - $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) - . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); - } else { - // PEAR-like class name - $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; - } - - if (isset($this->prefixesPsr0[$first])) { - foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { - if (0 === strpos($class, $prefix)) { - foreach ($dirs as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - } - } - } - - // PSR-0 fallback dirs - foreach ($this->fallbackDirsPsr0 as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - - // PSR-0 include paths. - if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { - return $file; - } - - return false; - } - - /** - * @return void - */ - private static function initializeIncludeClosure() - { - if (self::$includeFile !== null) { - return; - } - - /** - * Scope isolated include. - * - * Prevents access to $this/self from included files. - * - * @param string $file - * @return void - */ - self::$includeFile = \Closure::bind(static function($file) { - include $file; - }, null, null); - } -} diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php deleted file mode 100644 index 2052022..0000000 --- a/vendor/composer/InstalledVersions.php +++ /dev/null @@ -1,396 +0,0 @@ - - * Jordi Boggiano - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Composer; - -use Composer\Autoload\ClassLoader; -use Composer\Semver\VersionParser; - -/** - * This class is copied in every Composer installed project and available to all - * - * See also https://getcomposer.org/doc/07-runtime.md#installed-versions - * - * To require its presence, you can require `composer-runtime-api ^2.0` - * - * @final - */ -class InstalledVersions -{ - /** - * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to - * @internal - */ - private static $selfDir = null; - - /** - * @var mixed[]|null - * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null - */ - private static $installed; - - /** - * @var bool - */ - private static $installedIsLocalDir; - - /** - * @var bool|null - */ - private static $canGetVendors; - - /** - * @var array[] - * @psalm-var array}> - */ - private static $installedByVendor = array(); - - /** - * Returns a list of all package names which are present, either by being installed, replaced or provided - * - * @return string[] - * @psalm-return list - */ - public static function getInstalledPackages() - { - $packages = array(); - foreach (self::getInstalled() as $installed) { - $packages[] = array_keys($installed['versions']); - } - - if (1 === \count($packages)) { - return $packages[0]; - } - - return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); - } - - /** - * Returns a list of all package names with a specific type e.g. 'library' - * - * @param string $type - * @return string[] - * @psalm-return list - */ - public static function getInstalledPackagesByType($type) - { - $packagesByType = array(); - - foreach (self::getInstalled() as $installed) { - foreach ($installed['versions'] as $name => $package) { - if (isset($package['type']) && $package['type'] === $type) { - $packagesByType[] = $name; - } - } - } - - return $packagesByType; - } - - /** - * Checks whether the given package is installed - * - * This also returns true if the package name is provided or replaced by another package - * - * @param string $packageName - * @param bool $includeDevRequirements - * @return bool - */ - public static function isInstalled($packageName, $includeDevRequirements = true) - { - foreach (self::getInstalled() as $installed) { - if (isset($installed['versions'][$packageName])) { - return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; - } - } - - return false; - } - - /** - * Checks whether the given package satisfies a version constraint - * - * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: - * - * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') - * - * @param VersionParser $parser Install composer/semver to have access to this class and functionality - * @param string $packageName - * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package - * @return bool - */ - public static function satisfies(VersionParser $parser, $packageName, $constraint) - { - $constraint = $parser->parseConstraints((string) $constraint); - $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); - - return $provided->matches($constraint); - } - - /** - * Returns a version constraint representing all the range(s) which are installed for a given package - * - * It is easier to use this via isInstalled() with the $constraint argument if you need to check - * whether a given version of a package is installed, and not just whether it exists - * - * @param string $packageName - * @return string Version constraint usable with composer/semver - */ - public static function getVersionRanges($packageName) - { - foreach (self::getInstalled() as $installed) { - if (!isset($installed['versions'][$packageName])) { - continue; - } - - $ranges = array(); - if (isset($installed['versions'][$packageName]['pretty_version'])) { - $ranges[] = $installed['versions'][$packageName]['pretty_version']; - } - if (array_key_exists('aliases', $installed['versions'][$packageName])) { - $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); - } - if (array_key_exists('replaced', $installed['versions'][$packageName])) { - $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); - } - if (array_key_exists('provided', $installed['versions'][$packageName])) { - $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); - } - - return implode(' || ', $ranges); - } - - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); - } - - /** - * @param string $packageName - * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present - */ - public static function getVersion($packageName) - { - foreach (self::getInstalled() as $installed) { - if (!isset($installed['versions'][$packageName])) { - continue; - } - - if (!isset($installed['versions'][$packageName]['version'])) { - return null; - } - - return $installed['versions'][$packageName]['version']; - } - - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); - } - - /** - * @param string $packageName - * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present - */ - public static function getPrettyVersion($packageName) - { - foreach (self::getInstalled() as $installed) { - if (!isset($installed['versions'][$packageName])) { - continue; - } - - if (!isset($installed['versions'][$packageName]['pretty_version'])) { - return null; - } - - return $installed['versions'][$packageName]['pretty_version']; - } - - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); - } - - /** - * @param string $packageName - * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference - */ - public static function getReference($packageName) - { - foreach (self::getInstalled() as $installed) { - if (!isset($installed['versions'][$packageName])) { - continue; - } - - if (!isset($installed['versions'][$packageName]['reference'])) { - return null; - } - - return $installed['versions'][$packageName]['reference']; - } - - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); - } - - /** - * @param string $packageName - * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. - */ - public static function getInstallPath($packageName) - { - foreach (self::getInstalled() as $installed) { - if (!isset($installed['versions'][$packageName])) { - continue; - } - - return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; - } - - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); - } - - /** - * @return array - * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} - */ - public static function getRootPackage() - { - $installed = self::getInstalled(); - - return $installed[0]['root']; - } - - /** - * Returns the raw installed.php data for custom implementations - * - * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. - * @return array[] - * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} - */ - public static function getRawData() - { - @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); - - if (null === self::$installed) { - // only require the installed.php file if this file is loaded from its dumped location, - // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 - if (substr(__DIR__, -8, 1) !== 'C') { - self::$installed = include __DIR__ . '/installed.php'; - } else { - self::$installed = array(); - } - } - - return self::$installed; - } - - /** - * Returns the raw data of all installed.php which are currently loaded for custom implementations - * - * @return array[] - * @psalm-return list}> - */ - public static function getAllRawData() - { - return self::getInstalled(); - } - - /** - * Lets you reload the static array from another file - * - * This is only useful for complex integrations in which a project needs to use - * this class but then also needs to execute another project's autoloader in process, - * and wants to ensure both projects have access to their version of installed.php. - * - * A typical case would be PHPUnit, where it would need to make sure it reads all - * the data it needs from this class, then call reload() with - * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure - * the project in which it runs can then also use this class safely, without - * interference between PHPUnit's dependencies and the project's dependencies. - * - * @param array[] $data A vendor/composer/installed.php data set - * @return void - * - * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data - */ - public static function reload($data) - { - self::$installed = $data; - self::$installedByVendor = array(); - - // when using reload, we disable the duplicate protection to ensure that self::$installed data is - // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not, - // so we have to assume it does not, and that may result in duplicate data being returned when listing - // all installed packages for example - self::$installedIsLocalDir = false; - } - - /** - * @return string - */ - private static function getSelfDir() - { - if (self::$selfDir === null) { - self::$selfDir = strtr(__DIR__, '\\', '/'); - } - - return self::$selfDir; - } - - /** - * @return array[] - * @psalm-return list}> - */ - private static function getInstalled() - { - if (null === self::$canGetVendors) { - self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); - } - - $installed = array(); - $copiedLocalDir = false; - - if (self::$canGetVendors) { - $selfDir = self::getSelfDir(); - foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { - $vendorDir = strtr($vendorDir, '\\', '/'); - if (isset(self::$installedByVendor[$vendorDir])) { - $installed[] = self::$installedByVendor[$vendorDir]; - } elseif (is_file($vendorDir.'/composer/installed.php')) { - /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ - $required = require $vendorDir.'/composer/installed.php'; - self::$installedByVendor[$vendorDir] = $required; - $installed[] = $required; - if (self::$installed === null && $vendorDir.'/composer' === $selfDir) { - self::$installed = $required; - self::$installedIsLocalDir = true; - } - } - if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) { - $copiedLocalDir = true; - } - } - } - - if (null === self::$installed) { - // only require the installed.php file if this file is loaded from its dumped location, - // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 - if (substr(__DIR__, -8, 1) !== 'C') { - /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ - $required = require __DIR__ . '/installed.php'; - self::$installed = $required; - } else { - self::$installed = array(); - } - } - - if (self::$installed !== array() && !$copiedLocalDir) { - $installed[] = self::$installed; - } - - return $installed; - } -} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE deleted file mode 100644 index f27399a..0000000 --- a/vendor/composer/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ - -Copyright (c) Nils Adermann, Jordi Boggiano - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php deleted file mode 100644 index cead5e5..0000000 --- a/vendor/composer/autoload_classmap.php +++ /dev/null @@ -1,25 +0,0 @@ - $vendorDir . '/composer/InstalledVersions.php', - 'NXP\\Classes\\Calculator' => $vendorDir . '/nxp/math-executor/src/NXP/Classes/Calculator.php', - 'NXP\\Classes\\CustomFunction' => $vendorDir . '/nxp/math-executor/src/NXP/Classes/CustomFunction.php', - 'NXP\\Classes\\Operator' => $vendorDir . '/nxp/math-executor/src/NXP/Classes/Operator.php', - 'NXP\\Classes\\Token' => $vendorDir . '/nxp/math-executor/src/NXP/Classes/Token.php', - 'NXP\\Classes\\Tokenizer' => $vendorDir . '/nxp/math-executor/src/NXP/Classes/Tokenizer.php', - 'NXP\\Exception\\DivisionByZeroException' => $vendorDir . '/nxp/math-executor/src/NXP/Exception/DivisionByZeroException.php', - 'NXP\\Exception\\IncorrectBracketsException' => $vendorDir . '/nxp/math-executor/src/NXP/Exception/IncorrectBracketsException.php', - 'NXP\\Exception\\IncorrectExpressionException' => $vendorDir . '/nxp/math-executor/src/NXP/Exception/IncorrectExpressionException.php', - 'NXP\\Exception\\IncorrectFunctionParameterException' => $vendorDir . '/nxp/math-executor/src/NXP/Exception/IncorrectFunctionParameterException.php', - 'NXP\\Exception\\IncorrectNumberOfFunctionParametersException' => $vendorDir . '/nxp/math-executor/src/NXP/Exception/IncorrectNumberOfFunctionParametersException.php', - 'NXP\\Exception\\MathExecutorException' => $vendorDir . '/nxp/math-executor/src/NXP/Exception/MathExecutorException.php', - 'NXP\\Exception\\UnknownFunctionException' => $vendorDir . '/nxp/math-executor/src/NXP/Exception/UnknownFunctionException.php', - 'NXP\\Exception\\UnknownOperatorException' => $vendorDir . '/nxp/math-executor/src/NXP/Exception/UnknownOperatorException.php', - 'NXP\\Exception\\UnknownVariableException' => $vendorDir . '/nxp/math-executor/src/NXP/Exception/UnknownVariableException.php', - 'NXP\\MathExecutor' => $vendorDir . '/nxp/math-executor/src/NXP/MathExecutor.php', -); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php deleted file mode 100644 index 15a2ff3..0000000 --- a/vendor/composer/autoload_namespaces.php +++ /dev/null @@ -1,9 +0,0 @@ - array($vendorDir . '/nxp/math-executor/src/NXP'), -); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php deleted file mode 100644 index 3d61495..0000000 --- a/vendor/composer/autoload_real.php +++ /dev/null @@ -1,38 +0,0 @@ -register(true); - - return $loader; - } -} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php deleted file mode 100644 index eabea43..0000000 --- a/vendor/composer/autoload_static.php +++ /dev/null @@ -1,51 +0,0 @@ - - array ( - 'NXP\\' => 4, - ), - ); - - public static $prefixDirsPsr4 = array ( - 'NXP\\' => - array ( - 0 => __DIR__ . '/..' . '/nxp/math-executor/src/NXP', - ), - ); - - public static $classMap = array ( - 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', - 'NXP\\Classes\\Calculator' => __DIR__ . '/..' . '/nxp/math-executor/src/NXP/Classes/Calculator.php', - 'NXP\\Classes\\CustomFunction' => __DIR__ . '/..' . '/nxp/math-executor/src/NXP/Classes/CustomFunction.php', - 'NXP\\Classes\\Operator' => __DIR__ . '/..' . '/nxp/math-executor/src/NXP/Classes/Operator.php', - 'NXP\\Classes\\Token' => __DIR__ . '/..' . '/nxp/math-executor/src/NXP/Classes/Token.php', - 'NXP\\Classes\\Tokenizer' => __DIR__ . '/..' . '/nxp/math-executor/src/NXP/Classes/Tokenizer.php', - 'NXP\\Exception\\DivisionByZeroException' => __DIR__ . '/..' . '/nxp/math-executor/src/NXP/Exception/DivisionByZeroException.php', - 'NXP\\Exception\\IncorrectBracketsException' => __DIR__ . '/..' . '/nxp/math-executor/src/NXP/Exception/IncorrectBracketsException.php', - 'NXP\\Exception\\IncorrectExpressionException' => __DIR__ . '/..' . '/nxp/math-executor/src/NXP/Exception/IncorrectExpressionException.php', - 'NXP\\Exception\\IncorrectFunctionParameterException' => __DIR__ . '/..' . '/nxp/math-executor/src/NXP/Exception/IncorrectFunctionParameterException.php', - 'NXP\\Exception\\IncorrectNumberOfFunctionParametersException' => __DIR__ . '/..' . '/nxp/math-executor/src/NXP/Exception/IncorrectNumberOfFunctionParametersException.php', - 'NXP\\Exception\\MathExecutorException' => __DIR__ . '/..' . '/nxp/math-executor/src/NXP/Exception/MathExecutorException.php', - 'NXP\\Exception\\UnknownFunctionException' => __DIR__ . '/..' . '/nxp/math-executor/src/NXP/Exception/UnknownFunctionException.php', - 'NXP\\Exception\\UnknownOperatorException' => __DIR__ . '/..' . '/nxp/math-executor/src/NXP/Exception/UnknownOperatorException.php', - 'NXP\\Exception\\UnknownVariableException' => __DIR__ . '/..' . '/nxp/math-executor/src/NXP/Exception/UnknownVariableException.php', - 'NXP\\MathExecutor' => __DIR__ . '/..' . '/nxp/math-executor/src/NXP/MathExecutor.php', - ); - - public static function getInitializer(ClassLoader $loader) - { - return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit67a35766b07094746ef209d583ffb1f5::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit67a35766b07094746ef209d583ffb1f5::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInit67a35766b07094746ef209d583ffb1f5::$classMap; - - }, null, ClassLoader::class); - } -} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json deleted file mode 100644 index 0e8a34e..0000000 --- a/vendor/composer/installed.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "packages": [ - { - "name": "nxp/math-executor", - "version": "v2.3.2", - "version_normalized": "2.3.2.0", - "source": { - "type": "git", - "url": "https://github.com/neonxp/MathExecutor.git", - "reference": "c59f4cd15317754d2b50bd4bff2243012e815790" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/neonxp/MathExecutor/zipball/c59f4cd15317754d2b50bd4bff2243012e815790", - "reference": "c59f4cd15317754d2b50bd4bff2243012e815790", - "shasum": "" - }, - "require": { - "php": ">=7.4" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.8", - "phpunit/phpunit": ">=9.0" - }, - "time": "2022-12-08T16:15:34+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "NXP\\": "src/NXP" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Alexander 'NeonXP' Kiryukhin", - "email": "a.kiryukhin@mail.ru" - }, - { - "name": "Bruce Wells", - "email": "brucekwells@gmail.com" - } - ], - "description": "Simple math expressions calculator", - "homepage": "http://github.com/NeonXP/MathExecutor", - "keywords": [ - "calculator", - "expression", - "formula", - "math", - "mathmatics", - "parser" - ], - "support": { - "issues": "https://github.com/neonxp/MathExecutor/issues", - "source": "https://github.com/neonxp/MathExecutor/tree/v2.3.2" - }, - "install-path": "../nxp/math-executor" - } - ], - "dev": true, - "dev-package-names": [] -} diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php deleted file mode 100644 index 98ed554..0000000 --- a/vendor/composer/installed.php +++ /dev/null @@ -1,32 +0,0 @@ - array( - 'name' => 'xjsv/cooked', - 'pretty_version' => '1.14.0', - 'version' => '1.14.0.0', - 'reference' => null, - 'type' => 'wordpress-plugin', - 'install_path' => __DIR__ . '/../../', - 'aliases' => array(), - 'dev' => true, - ), - 'versions' => array( - 'nxp/math-executor' => array( - 'pretty_version' => 'v2.3.2', - 'version' => '2.3.2.0', - 'reference' => 'c59f4cd15317754d2b50bd4bff2243012e815790', - 'type' => 'library', - 'install_path' => __DIR__ . '/../nxp/math-executor', - 'aliases' => array(), - 'dev_requirement' => false, - ), - 'xjsv/cooked' => array( - 'pretty_version' => '1.14.0', - 'version' => '1.14.0.0', - 'reference' => null, - 'type' => 'wordpress-plugin', - 'install_path' => __DIR__ . '/../../', - 'aliases' => array(), - 'dev_requirement' => false, - ), - ), -); diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php deleted file mode 100644 index d2225c7..0000000 --- a/vendor/composer/platform_check.php +++ /dev/null @@ -1,25 +0,0 @@ -= 70400)) { - $issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.'; -} - -if ($issues) { - if (!headers_sent()) { - header('HTTP/1.1 500 Internal Server Error'); - } - if (!ini_get('display_errors')) { - if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { - fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); - } elseif (!headers_sent()) { - echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; - } - } - throw new \RuntimeException( - 'Composer detected issues in your platform: ' . implode(' ', $issues) - ); -} diff --git a/vendor/nxp/math-executor/.gitattributes b/vendor/nxp/math-executor/.gitattributes deleted file mode 100644 index 032c1bd..0000000 --- a/vendor/nxp/math-executor/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -* text=auto - diff --git a/vendor/nxp/math-executor/.github/workflows/tests.yml b/vendor/nxp/math-executor/.github/workflows/tests.yml deleted file mode 100644 index 4967599..0000000 --- a/vendor/nxp/math-executor/.github/workflows/tests.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Tests - -on: [push, pull_request] - -jobs: - php-tests: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - php: [8.2, 8.1, 8.0, 7.4] - dependency-version: [prefer-lowest, prefer-stable] - os: [ubuntu-latest, windows-latest] - - name: ${{ matrix.os }} - PHP${{ matrix.php }} - ${{ matrix.dependency-version }} - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - extensions: dom, curl, libxml, mbstring, zip, bcmath, intl - ini-values: precision=16 - coverage: none - - - name: Install dependencies - run: | - composer install --no-interaction - composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest - - - name: Execute tests - run: vendor/bin/phpunit diff --git a/vendor/nxp/math-executor/.gitignore b/vendor/nxp/math-executor/.gitignore deleted file mode 100644 index 9aedff4..0000000 --- a/vendor/nxp/math-executor/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -vendor/ -.idea/ -composer.lock -.phpunit.result.cache -.vscode -.php-cs-fixer.cache - diff --git a/vendor/nxp/math-executor/.php-cs-fixer.php b/vendor/nxp/math-executor/.php-cs-fixer.php deleted file mode 100644 index 2ec098c..0000000 --- a/vendor/nxp/math-executor/.php-cs-fixer.php +++ /dev/null @@ -1,282 +0,0 @@ -setRiskyAllowed(true) - ->setIndent(" ") - ->setRules([ - // Each line of multi-line DocComments must have an asterisk [PSR-5] and must be aligned with the first one. - 'align_multiline_comment' => ['comment_type'=>'all_multiline'], - // Each element of an array must be indented exactly once. - 'array_indentation' => true, - // Converts simple usages of `array_push($x, $y);` to `$x[] = $y;`. - 'array_push' => true, - // PHP arrays should be declared using the configured syntax. - 'array_syntax' => ['syntax'=>'short'], - // Converts backtick operators to `shell_exec` calls. - 'backtick_to_shell_exec' => true, - // Binary operators should be surrounded by space as configured. - 'binary_operator_spaces' => true, - // There MUST be one blank line after the namespace declaration. - 'blank_line_after_namespace' => true, - // Ensure there is no code on the same line as the PHP open tag and it is followed by a blank line. - 'blank_line_after_opening_tag' => true, - // An empty line feed must precede any configured statement. - 'blank_line_before_statement' => ['statements'=>['break','case','continue','declare','default','exit','do','exit','for','foreach','goto','if','return','switch','throw','try','while','yield']], - // A single space or none should be between cast and variable. - 'cast_spaces' => ['space'=>'none'], - // Class, trait and interface elements must be separated with one or none blank line. - 'class_attributes_separation' => true, - // Whitespace around the keywords of a class, trait or interfaces definition should be one space. - 'class_definition' => true, - // Namespace must not contain spacing, comments or PHPDoc. - 'clean_namespace' => true, - // Using `isset($var) &&` multiple times should be done in one call. - 'combine_consecutive_issets' => true, - // Calling `unset` on multiple items should be done in one call. - 'combine_consecutive_unsets' => true, - // Replace multiple nested calls of `dirname` by only one call with second `$level` parameter. Requires PHP >= 7.0. - 'combine_nested_dirname' => true, - // Comments with annotation should be docblock when used on structural elements. - 'comment_to_phpdoc' => true, - // Remove extra spaces in a nullable typehint. - 'compact_nullable_typehint' => true, - // Concatenation should be spaced according configuration. - 'concat_space' => ['spacing'=>'one'], - // The PHP constants `true`, `false`, and `null` MUST be written using the correct casing. - 'constant_case' => true, - // Equal sign in declare statement should be surrounded by spaces or not following configuration. - 'declare_equal_normalize' => ['space'=>'single'], - // Replaces `dirname(__FILE__)` expression with equivalent `__DIR__` constant. - 'dir_constant' => true, - // The keyword `elseif` should be used instead of `else if` so that all control keywords look like single words. - 'elseif' => true, - // PHP code MUST use only UTF-8 without BOM (remove BOM). - 'encoding' => true, - // Replace deprecated `ereg` regular expression functions with `preg`. - 'ereg_to_preg' => true, - // Add curly braces to indirect variables to make them clear to understand. Requires PHP >= 7.0. - 'explicit_indirect_variable' => true, - // Converts implicit variables into explicit ones in double-quoted strings or heredoc syntax. - 'explicit_string_variable' => true, - // Order the flags in `fopen` calls, `b` and `t` must be last. - 'fopen_flag_order' => true, - // PHP code must use the long ` true, - // Spaces should be properly placed in a function declaration. - 'function_declaration' => ['closure_function_spacing'=>'none'], - // Replace core functions calls returning constants with the constants. - 'function_to_constant' => true, - // Ensure single space between function's argument and its typehint. - 'function_typehint_space' => true, - // Renames PHPDoc tags. - 'general_phpdoc_tag_rename' => true, - // Function `implode` must be called with 2 arguments in the documented order. - 'implode_call' => true, - // Include/Require and file path should be divided with a single space. File path should not be placed under brackets. - 'include' => true, - // Code MUST use configured indentation type. - 'indentation_type' => true, - // Replaces `is_null($var)` expression with `null === $var`. - 'is_null' => true, - // All PHP files must use same line ending. - 'line_ending' => true, - // Ensure there is no code on the same line as the PHP open tag. - 'linebreak_after_opening_tag' => true, - // List (`array` destructuring) assignment should be declared using the configured syntax. Requires PHP >= 7.1. - 'list_syntax' => ['syntax'=>'short'], - // Use `&&` and `||` logical operators instead of `and` and `or`. - 'logical_operators' => true, - // Cast should be written in lower case. - 'lowercase_cast' => true, - // PHP keywords MUST be in lower case. - 'lowercase_keywords' => true, - // Class static references `self`, `static` and `parent` MUST be in lower case. - 'lowercase_static_reference' => true, - // Magic constants should be referred to using the correct casing. - 'magic_constant_casing' => true, - // Magic method definitions and calls must be using the correct casing. - 'magic_method_casing' => true, - // In method arguments and method call, there MUST NOT be a space before each comma and there MUST be one space after each comma. Argument lists MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one argument per line. - 'method_argument_space' => true, - // Method chaining MUST be properly indented. Method chaining with different levels of indentation is not supported. - 'method_chaining_indentation' => true, - // Replaces `intval`, `floatval`, `doubleval`, `strval` and `boolval` function calls with according type casting operator. - 'modernize_types_casting' => true, - // Forbid multi-line whitespace before the closing semicolon or move the semicolon to the new line for chained calls. - 'multiline_whitespace_before_semicolons' => true, - // Function defined by PHP should be called using the correct casing. - 'native_function_casing' => true, - // Add leading `\` before function invocation to speed up resolving. - 'native_function_invocation' => ['include'=>['@all','trans']], - // Native type hints for functions should use the correct case. - 'native_function_type_declaration_casing' => true, - // All instances created with new keyword must be followed by braces. - 'new_with_braces' => true, - // Master functions shall be used instead of aliases. - 'no_alias_functions' => true, - // Master language constructs shall be used instead of aliases. - 'no_alias_language_construct_call' => true, - // Replace control structure alternative syntax to use braces. - 'no_alternative_syntax' => true, - // There should not be blank lines between docblock and the documented element. - 'no_blank_lines_after_phpdoc' => true, - // There must be a comment when fall-through is intentional in a non-empty case body. - 'no_break_comment' => ['comment_text'=>'Intentionally fall through'], - // The closing `? >` tag MUST be omitted from files containing only PHP. - 'no_closing_tag' => true, - // There should not be any empty comments. - 'no_empty_comment' => true, - // There should not be empty PHPDoc blocks. - 'no_empty_phpdoc' => true, - // Remove useless (semicolon) statements. - 'no_empty_statement' => true, - // Replace accidental usage of homoglyphs (non ascii characters) in names. - 'no_homoglyph_names' => true, - // Remove leading slashes in `use` clauses. - 'no_leading_import_slash' => true, - // The namespace declaration line shouldn't contain leading whitespace. - 'no_leading_namespace_whitespace' => true, - // Either language construct `print` or `echo` should be used. - 'no_mixed_echo_print' => true, - // Operator `=>` should not be surrounded by multi-line whitespaces. - 'no_multiline_whitespace_around_double_arrow' => true, - // Convert PHP4-style constructors to `__construct`. - 'no_php4_constructor' => true, - // Short cast `bool` using double exclamation mark should not be used. - 'no_short_bool_cast' => true, - // When making a method or function call, there MUST NOT be a space between the method or function name and the opening parenthesis. - 'no_spaces_after_function_name' => true, - // There MUST NOT be a space after the opening parenthesis. There MUST NOT be a space before the closing parenthesis. - 'no_spaces_inside_parenthesis' => true, - // Removes `@param`, `@return` and `@var` tags that don't provide any useful information. - 'no_superfluous_phpdoc_tags' => true, - // Remove trailing whitespace at the end of non-blank lines. - 'no_trailing_whitespace' => true, - // There MUST be no trailing spaces inside comment or PHPDoc. - 'no_trailing_whitespace_in_comment' => true, - // Removes unneeded parentheses around control statements. - 'no_unneeded_control_parentheses' => true, - // Removes unneeded curly braces that are superfluous and aren't part of a control structure's body. - 'no_unneeded_curly_braces' => true, - // A `final` class must not have `final` methods and `private` methods must not be `final`. - 'no_unneeded_final_method' => true, - // In function arguments there must not be arguments with default values before non-default ones. - 'no_unreachable_default_argument_value' => true, - // Variables must be set `null` instead of using `(unset)` casting. - 'no_unset_cast' => true, - // Properties should be set to `null` instead of using `unset`. - 'no_unset_on_property' => true, - // Unused `use` statements must be removed. - 'no_unused_imports' => true, - // There should not be useless `else` cases. - 'no_useless_else' => true, - // There should not be an empty `return` statement at the end of a function. - 'no_useless_return' => true, - // There must be no `sprintf` calls with only the first argument. - 'no_useless_sprintf' => true, - // In array declaration, there MUST NOT be a whitespace before each comma. - 'no_whitespace_before_comma_in_array' => true, - // Remove trailing whitespace at the end of blank lines. - 'no_whitespace_in_blank_line' => true, - // Remove Zero-width space (ZWSP), Non-breaking space (NBSP) and other invisible unicode symbols. - 'non_printable_character' => ['use_escape_sequences_in_strings'=>true], - // Array index should always be written by using square braces. - 'normalize_index_brace' => true, - // Logical NOT operators (`!`) should have one trailing whitespace. - 'not_operator_with_successor_space' => true, - // Adds or removes `?` before type declarations for parameters with a default `null` value. - 'nullable_type_declaration_for_default_null_value' => true, - // There should not be space before or after object operators `->` and `?->`. - 'object_operator_without_whitespace' => true, - // Orders the elements of classes/interfaces/traits. - 'ordered_class_elements' => ['order'=>['use_trait','constant_public','constant_protected','constant_private','property_public','property_protected','property_private','construct','destruct','magic','phpunit','method_public','method_protected','method_private']], - // Ordering `use` statements. - 'ordered_imports' => true, - // Orders the interfaces in an `implements` or `interface extends` clause. - 'ordered_interfaces' => true, - // Trait `use` statements must be sorted alphabetically. - 'ordered_traits' => true, - // Classy that does not inherit must not have `@inheritdoc` tags. - 'phpdoc_no_useless_inheritdoc' => true, - // Annotations in PHPDoc should be ordered so that `@param` annotations come first, then `@throws` annotations, then `@return` annotations. - 'phpdoc_order' => true, - // The type of `@return` annotations of methods returning a reference to itself must the configured one. - 'phpdoc_return_self_reference' => true, - // Scalar types should always be written in the same form. `int` not `integer`, `bool` not `boolean`, `float` not `real` or `double`. - 'phpdoc_scalar' => true, - // Fixes casing of PHPDoc tags. - 'phpdoc_tag_casing' => true, - // Converts `protected` variables and methods to `private` where possible. - 'protected_to_private' => true, - // Classes must be in a path that matches their namespace, be at least one namespace deep and the class name should match the file name. - 'psr_autoloading' => true, - // There should be one or no space before colon, and one space after it in return type declarations, according to configuration. - 'return_type_declaration' => ['space_before'=>'one'], - // Instructions must be terminated with a semicolon. - 'semicolon_after_instruction' => true, - // Cast shall be used, not `settype`. - 'set_type_to_cast' => true, - // Cast `(boolean)` and `(integer)` should be written as `(bool)` and `(int)`, `(double)` and `(real)` as `(float)`, `(binary)` as `(string)`. - 'short_scalar_cast' => true, - // Converts explicit variables in double-quoted strings and heredoc syntax from simple to complex format (`${` to `{$`). - 'simple_to_complex_string_variable' => true, - // Simplify `if` control structures that return the boolean result of their condition. - 'simplified_if_return' => true, - // A return statement wishing to return `void` should not return `null`. - 'simplified_null_return' => true, - // A PHP file without end tag must always end with a single empty line feed. - 'single_blank_line_at_eof' => true, - // There should be exactly one blank line before a namespace declaration. - 'single_blank_line_before_namespace' => true, - // There MUST NOT be more than one property or constant declared per statement. - 'single_class_element_per_statement' => true, - // There MUST be one use keyword per declaration. - 'single_import_per_statement' => true, - // Each namespace use MUST go on its own line and there MUST be one blank line after the use statements block. - 'single_line_after_imports' => true, - // Single-line comments and multi-line comments with only one line of actual content should use the `//` syntax. - 'single_line_comment_style' => true, - // Convert double quotes to single quotes for simple strings. - 'single_quote' => true, - // Each trait `use` must be done as single statement. - 'single_trait_insert_per_statement' => true, - // Replace all `<>` with `!=`. - 'standardize_not_equals' => true, - // Lambdas not (indirect) referencing `$this` must be declared `static`. - 'static_lambda' => true, - // All multi-line strings must use correct line ending. - 'string_line_ending' => true, - // A case should be followed by a colon and not a semicolon. - 'switch_case_semicolon_to_colon' => true, - // Removes extra spaces between colon and case value. - 'switch_case_space' => true, - // Switch case must not be ended with `continue` but with `break`. - 'switch_continue_to_break' => true, - // Standardize spaces around ternary operator. - 'ternary_operator_spaces' => true, - // Use the Elvis operator `?:` where possible. - 'ternary_to_elvis_operator' => true, - // Use `null` coalescing operator `??` where possible. Requires PHP >= 7.0. - 'ternary_to_null_coalescing' => true, - // Arrays should be formatted like function/method arguments, without leading or trailing single line space. - 'trim_array_spaces' => true, - // Unary operators should be placed adjacent to their operands. - 'unary_operator_spaces' => true, - // Visibility MUST be declared on all properties and methods; `abstract` and `final` MUST be declared before the visibility; `static` MUST be declared after the visibility. - 'visibility_required' => true, - // Add `void` return type to functions with missing or empty return statements, but priority is given to `@return` annotations. Requires PHP >= 7.1. - 'void_return' => true, - // In array declaration, there MUST be a whitespace after each comma. - 'whitespace_after_comma_in_array' => true, - // Write conditions in Yoda style (`true`), non-Yoda style (`['equal' => false, 'identical' => false, 'less_and_greater' => false]`) or ignore those conditions (`null`) based on configuration. - 'yoda_style' => true, - ]); - -return $config->setFinder(PhpCsFixer\Finder::create() - ->exclude('vendor') - ->in(__DIR__.'/src') - ->in(__DIR__.'/tests') - ); - diff --git a/vendor/nxp/math-executor/LICENSE b/vendor/nxp/math-executor/LICENSE deleted file mode 100644 index e45f709..0000000 --- a/vendor/nxp/math-executor/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) Alexander Kiryukhin - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/vendor/nxp/math-executor/README.md b/vendor/nxp/math-executor/README.md deleted file mode 100644 index 0e88f34..0000000 --- a/vendor/nxp/math-executor/README.md +++ /dev/null @@ -1,249 +0,0 @@ -# MathExecutor [![Tests](https://github.com/neonxp/MathExecutor/workflows/Tests/badge.svg)](https://github.com/neonxp/MathExecutor/actions?query=workflow%3ATests) - -# A simple and extensible math expressions calculator - -## Features: -* Built in support for +, -, *, /, % and power (^) operators -* Paratheses () and arrays [] are fully supported -* Logical operators (==, !=, <, <, >=, <=, &&, ||) -* Built in support for most PHP math functions -* Support for BCMath Arbitrary Precision Math -* Support for variable number of function parameters and optional function parameters -* Conditional If logic -* Support for user defined operators -* Support for user defined functions -* Support for math on user defined objects -* Dynamic variable resolution (delayed computation) -* Unlimited variable name lengths -* String support, as function parameters or as evaluated as a number by PHP -* Exceptions on divide by zero, or treat as zero -* Unary Plus and Minus (e.g. +3 or -sin(12)) -* Pi ($pi) and Euler's number ($e) support to 11 decimal places -* Easily extensible - -## Install via Composer: -``` -composer require nxp/math-executor -``` - -## Sample usage: -```php -use NXP\MathExecutor; - -$executor = new MathExecutor(); - -echo $executor->execute('1 + 2 * (2 - (4+10))^2 + sin(10)'); -``` - -## Functions: -Default functions: -* abs -* acos (arccos) -* acosh -* arcctg (arccot, arccotan) -* arcsec -* arccsc (arccosec) -* array -* asin (arcsin) -* atan (atn, arctan, arctg) -* atan2 -* atanh -* avg -* bindec -* ceil -* cos -* cosec (csc) -* cosh -* ctg (cot, cotan, cotg, ctn) -* decbin -* dechex -* decoct -* deg2rad -* exp -* expm1 -* floor -* fmod -* hexdec -* hypot -* if -* intdiv -* log (ln) -* log10 (lg) -* log1p -* max -* min -* octdec -* pi -* pow -* rad2deg -* round -* sec -* sin -* sinh -* sqrt -* tan (tn, tg) -* tanh - -Add custom function to executor: -```php -$executor->addFunction('concat', function($arg1, $arg2) {return $arg1 . $arg2;}); -``` -Optional parameters: -```php -$executor->addFunction('round', function($num, int $precision = 0) {return round($num, $precision);}); -$executor->calculate('round(17.119)'); // 17 -$executor->calculate('round(17.119, 2)'); // 17.12 -``` -Variable number of parameters: -```php -$executor->addFunction('avarage', function(...$args) {return array_sum($args) / count($args);}); -$executor->calculate('avarage(1,3)'); // 2 -$executor->calculate('avarage(1, 3, 4, 8)'); // 4 -``` - -## Operators: -Default operators: `+ - * / % ^` - -Add custom operator to executor: - -```php -use NXP\Classes\Operator; - -$executor->addOperator(new Operator( - '%', // Operator sign - false, // Is right associated operator - 180, // Operator priority - function (&$stack) - { - $op2 = array_pop($stack); - $op1 = array_pop($stack); - $result = $op1->getValue() % $op2->getValue(); - - return $result; - } -)); -``` - -## Logical operators: -Logical operators (==, !=, <, <, >=, <=, &&, ||) are supported, but logically they can only return true (1) or false (0). In order to leverage them, use the built in **if** function: - -``` -if($a > $b, $a - $b, $b - $a) -``` - -You can think of the **if** function as prototyped like: - -``` -function if($condition, $returnIfTrue, $returnIfFalse) -``` -## Variables: -Variables can be prefixed with the dollar sign ($) for PHP compatibility, but is not required. - -Default variables: - -``` -$pi = 3.14159265359 -$e = 2.71828182846 -``` - -You can add your own variables to executor: - -```php -$executor->setVar('var1', 0.15)->setVar('var2', 0.22); - -echo $executor->execute("$var1 + var2"); -``` - -Arrays are also supported (as variables, as func params or can be returned in user defined funcs): -```php -$executor->setVar('monthly_salaries', [1800, 1900, 1200, 1600]); - -echo $executor->execute("avg(monthly_salaries) * min([1.1, 1.3])"); -``` - -By default, variables must be scalar values (int, float, bool or string) or array. If you would like to support another type, use **setVarValidationHandler** - -```php -$executor->setVarValidationHandler(function (string $name, $variable) { - // allow all scalars, array and null - if (is_scalar($variable) || is_array($variable) || $variable === null) { - return; - } - // Allow variables of type DateTime, but not others - if (! $variable instanceof \DateTime) { - throw new MathExecutorException("Invalid variable type"); - } -}); -``` - -You can dynamically define variables at run time. If a variable has a high computation cost, but might not be used, then you can define an undefined variable handler. It will only get called when the variable is used, rather than having to always set it initially. - -```php -$calculator = new MathExecutor(); -$calculator->setVarNotFoundHandler( - function ($varName) { - if ($varName == 'trans') { - return transmogrify(); - } - return null; - } -); -``` - -## Floating Point BCMath Support -By default, `MathExecutor` uses PHP floating point math, but if you need a fixed precision, call **useBCMath()**. Precision defaults to 2 decimal points, or pass the required number. -`WARNING`: Functions may return a PHP floating point number. By doing the basic math functions on the results, you will get back a fixed number of decimal points. Use a plus sign in front of any stand alone function to return the proper number of decimal places. - -## Division By Zero Support: -Division by zero throws a `\NXP\Exception\DivisionByZeroException` by default -```php -try { - echo $executor->execute('1/0'); -} catch (DivisionByZeroException $e) { - echo $e->getMessage(); -} -``` -Or call setDivisionByZeroIsZero -```php -echo $executor->setDivisionByZeroIsZero()->execute('1/0'); -``` -If you want another behavior, you can override division operator: -```php -$executor->addOperator("/", false, 180, function($a, $b) { - if ($b == 0) { - return null; - } - return $a / $b; -}); -echo $executor->execute('1/0'); -``` - -## String Support: -Expressions can contain double or single quoted strings that are evaluated the same way as PHP evaluates strings as numbers. You can also pass strings to functions. - -```php -echo $executor->execute("1 + '2.5' * '.5' + myFunction('category')"); -``` -To use reverse solidus character (\) in strings, or to use single quote character (') in a single quoted string, or to use double quote character (") in a double quoted string, you must prepend reverse solidus character (\). - -```php -echo $executor->execute("countArticleSentences('My Best Article\'s Title')"); -``` - -## Extending MathExecutor -You can add operators, functions and variables with the public methods in MathExecutor, but if you need to do more serious modifications to base behaviors, the easiest way to extend MathExecutor is to redefine the following methods in your derived class: -* defaultOperators -* defaultFunctions -* defaultVars - -This will allow you to remove functions and operators if needed, or implement different types more simply. - -Also note that you can replace an existing default operator by adding a new operator with the same regular expression string. For example if you just need to redefine TokenPlus, you can just add a new operator with the same regex string, in this case '\\+'. - -## Documentation - -Full class documentation via [PHPFUI/InstaDoc](http://phpfui.com/?n=NXP&c=MathExecutor) - -## Future Enhancements - -This package will continue to track currently supported versions of PHP. diff --git a/vendor/nxp/math-executor/code-of-conduct.md b/vendor/nxp/math-executor/code-of-conduct.md deleted file mode 100644 index 83e0f4e..0000000 --- a/vendor/nxp/math-executor/code-of-conduct.md +++ /dev/null @@ -1,9 +0,0 @@ -# Code of conduct - -We don't care who you are IRL. Be professional and responsible. - -If you are a good person, we are happy for you. - -If you are an asshole to us, we will be assholes in relation to you. - -> Do to no one what you yourself dislike \ No newline at end of file diff --git a/vendor/nxp/math-executor/code-of-conduct.ru.md b/vendor/nxp/math-executor/code-of-conduct.ru.md deleted file mode 100644 index 04a566f..0000000 --- a/vendor/nxp/math-executor/code-of-conduct.ru.md +++ /dev/null @@ -1,5 +0,0 @@ -# Кодекс поведения - -Нам всё равно, кто ты в реальной жизни, просто будь профессионалом и всё будет хорошо. - -Если ты будешь вести себя как сволочь - не удивляйся, что и к тебе будут относиться так же. diff --git a/vendor/nxp/math-executor/composer.json b/vendor/nxp/math-executor/composer.json deleted file mode 100644 index 6d3759d..0000000 --- a/vendor/nxp/math-executor/composer.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "nxp/math-executor", - "description": "Simple math expressions calculator", - "minimum-stability": "stable", - "keywords": [ - "math", - "parser", - "expression", - "calculator", - "formula", - "mathmatics" - ], - "homepage": "http://github.com/NeonXP/MathExecutor", - "license": "MIT", - "authors": [ - { - "name": "Alexander 'NeonXP' Kiryukhin", - "email": "a.kiryukhin@mail.ru" - }, - { - "name": "Bruce Wells", - "email": "brucekwells@gmail.com" - } - ], - "scripts": { - "test": "vendor/bin/phpunit --colors=always", - "test-coverage": "vendor/bin/phpunit --coverage-html coverage" - - }, - "require": { - "php": ">=7.4" - }, - "require-dev": { - "phpunit/phpunit": ">=9.0", - "friendsofphp/php-cs-fixer": "^3.8" - }, - "autoload": { - "psr-4": { - "NXP\\": "src/NXP" - } - }, - "autoload-dev": { - "psr-4": { - "NXP\\Tests\\": "tests/" - } - } -} diff --git a/vendor/nxp/math-executor/phpstan.neon b/vendor/nxp/math-executor/phpstan.neon deleted file mode 100644 index bed17ae..0000000 --- a/vendor/nxp/math-executor/phpstan.neon +++ /dev/null @@ -1,9 +0,0 @@ -parameters: - level: 6 - paths: - - ./ - excludes_analyse: - - vendor/* - - tests/* - bootstrapFiles: - - vendor/autoload.php \ No newline at end of file diff --git a/vendor/nxp/math-executor/phpunit.xml.dist b/vendor/nxp/math-executor/phpunit.xml.dist deleted file mode 100644 index d515f51..0000000 --- a/vendor/nxp/math-executor/phpunit.xml.dist +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - ./tests/ - - - \ No newline at end of file diff --git a/vendor/nxp/math-executor/src/NXP/Classes/Calculator.php b/vendor/nxp/math-executor/src/NXP/Classes/Calculator.php deleted file mode 100644 index 6b63503..0000000 --- a/vendor/nxp/math-executor/src/NXP/Classes/Calculator.php +++ /dev/null @@ -1,93 +0,0 @@ - - */ -class Calculator -{ - /** @var array */ - private array $functions = []; - - /** @var array */ - private array $operators = []; - - /** - * @todo PHP8: Use constructor property promotion -> public function __construct(private array $functions, private array $operators) - * - * @param array $functions - * @param array $operators - */ - public function __construct(array $functions, array $operators) - { - $this->functions = $functions; - $this->operators = $operators; - } - - /** - * Calculate array of tokens in reverse polish notation - * - * @param Token[] $tokens - * @param array $variables - * - * @throws UnknownVariableException - * @throws IncorrectExpressionException - * @return int|float|string|null - */ - public function calculate(array $tokens, array $variables, ?callable $onVarNotFound = null) - { - /** @var Token[] $stack */ - $stack = []; - - foreach ($tokens as $token) { - if (Token::Literal === $token->type || Token::String === $token->type) { - $stack[] = $token; - } elseif (Token::Variable === $token->type) { - $variable = $token->value; - - $value = null; - - if (\array_key_exists($variable, $variables)) { - $value = $variables[$variable]; - } elseif ($onVarNotFound) { - $value = \call_user_func($onVarNotFound, $variable); - } else { - throw new UnknownVariableException($variable); - } - - $stack[] = new Token(Token::Literal, $value, $variable); - } elseif (Token::Function === $token->type) { - if (! \array_key_exists($token->value, $this->functions)) { - throw new UnknownFunctionException($token->value); - } - $stack[] = $this->functions[$token->value]->execute($stack, $token->paramCount); - } elseif (Token::Operator === $token->type) { - if (! \array_key_exists($token->value, $this->operators)) { - throw new UnknownOperatorException($token->value); - } - $stack[] = $this->operators[$token->value]->execute($stack); - } - } - $result = \array_pop($stack); - - if (null === $result || ! empty($stack)) { - throw new IncorrectExpressionException('Stack must be empty'); - } - - return $result->value; - } -} diff --git a/vendor/nxp/math-executor/src/NXP/Classes/CustomFunction.php b/vendor/nxp/math-executor/src/NXP/Classes/CustomFunction.php deleted file mode 100644 index 85db379..0000000 --- a/vendor/nxp/math-executor/src/NXP/Classes/CustomFunction.php +++ /dev/null @@ -1,66 +0,0 @@ -name = $name; - $this->function = $function; - $reflection = (new ReflectionFunction($function)); - $this->isVariadic = $reflection->isVariadic(); - $this->totalParamCount = $reflection->getNumberOfParameters(); - $this->requiredParamCount = $reflection->getNumberOfRequiredParameters(); - - } - - /** - * @param array $stack - * - * @throws IncorrectNumberOfFunctionParametersException - */ - public function execute(array &$stack, int $paramCountInStack) : Token - { - if ($paramCountInStack < $this->requiredParamCount) { - throw new IncorrectNumberOfFunctionParametersException($this->name); - } - - if ($paramCountInStack > $this->totalParamCount && ! $this->isVariadic) { - throw new IncorrectNumberOfFunctionParametersException($this->name); - } - $args = []; - - if ($paramCountInStack > 0) { - for ($i = 0; $i < $paramCountInStack; $i++) { - \array_unshift($args, \array_pop($stack)->value); - } - } - - $result = \call_user_func_array($this->function, $args); - - return new Token(Token::Literal, $result); - } -} diff --git a/vendor/nxp/math-executor/src/NXP/Classes/Operator.php b/vendor/nxp/math-executor/src/NXP/Classes/Operator.php deleted file mode 100644 index 7dee06d..0000000 --- a/vendor/nxp/math-executor/src/NXP/Classes/Operator.php +++ /dev/null @@ -1,56 +0,0 @@ -operator = $operator; - $this->isRightAssoc = $isRightAssoc; - $this->priority = $priority; - $this->function = $function; - $reflection = new ReflectionFunction($function); - $this->places = $reflection->getNumberOfParameters(); - } - - /** - * @param array $stack - * - * @throws IncorrectExpressionException - */ - public function execute(array &$stack) : Token - { - if (\count($stack) < $this->places) { - throw new IncorrectExpressionException(); - } - $args = []; - - for ($i = 0; $i < $this->places; $i++) { - \array_unshift($args, \array_pop($stack)->value); - } - - $result = \call_user_func_array($this->function, $args); - - return new Token(Token::Literal, $result); - } -} diff --git a/vendor/nxp/math-executor/src/NXP/Classes/Token.php b/vendor/nxp/math-executor/src/NXP/Classes/Token.php deleted file mode 100644 index 7532e77..0000000 --- a/vendor/nxp/math-executor/src/NXP/Classes/Token.php +++ /dev/null @@ -1,43 +0,0 @@ -type = $type; - $this->value = $value; - $this->name = $name; - } -} diff --git a/vendor/nxp/math-executor/src/NXP/Classes/Tokenizer.php b/vendor/nxp/math-executor/src/NXP/Classes/Tokenizer.php deleted file mode 100644 index a74bff6..0000000 --- a/vendor/nxp/math-executor/src/NXP/Classes/Tokenizer.php +++ /dev/null @@ -1,415 +0,0 @@ - - */ -class Tokenizer -{ - /** @var array */ - public array $tokens = []; - - private string $input = ''; - - private string $numberBuffer = ''; - - private string $stringBuffer = ''; - - private bool $allowNegative = true; - - /** @var array */ - private array $operators = []; - - private bool $inSingleQuotedString = false; - - private bool $inDoubleQuotedString = false; - - /** - * Tokenizer constructor. - * @param Operator[] $operators - */ - public function __construct(string $input, array $operators) - { - $this->input = $input; - $this->operators = $operators; - } - - public function tokenize() : self - { - $isLastCharEscape = false; - - foreach (\str_split($this->input) as $ch) { - switch (true) { - case $this->inSingleQuotedString: - if ('\\' === $ch) { - if ($isLastCharEscape) { - $this->stringBuffer .= '\\'; - $isLastCharEscape = false; - } else { - $isLastCharEscape = true; - } - - continue 2; - } elseif ("'" === $ch) { - if ($isLastCharEscape) { - $this->stringBuffer .= "'"; - $isLastCharEscape = false; - } else { - $this->tokens[] = new Token(Token::String, $this->stringBuffer); - $this->inSingleQuotedString = false; - $this->stringBuffer = ''; - } - - continue 2; - } - - if ($isLastCharEscape) { - $this->stringBuffer .= '\\'; - $isLastCharEscape = false; - } - $this->stringBuffer .= $ch; - - continue 2; - - case $this->inDoubleQuotedString: - if ('\\' === $ch) { - if ($isLastCharEscape) { - $this->stringBuffer .= '\\'; - $isLastCharEscape = false; - } else { - $isLastCharEscape = true; - } - - continue 2; - } elseif ('"' === $ch) { - if ($isLastCharEscape) { - $this->stringBuffer .= '"'; - $isLastCharEscape = false; - } else { - $this->tokens[] = new Token(Token::String, $this->stringBuffer); - $this->inDoubleQuotedString = false; - $this->stringBuffer = ''; - } - - continue 2; - } - - if ($isLastCharEscape) { - $this->stringBuffer .= '\\'; - $isLastCharEscape = false; - } - $this->stringBuffer .= $ch; - - continue 2; - - case '[' === $ch: - $this->tokens[] = new Token(Token::Function, 'array'); - $this->allowNegative = true; - $this->tokens[] = new Token(Token::LeftParenthesis, ''); - - continue 2; - - case ' ' == $ch || "\n" == $ch || "\r" == $ch || "\t" == $ch: - $this->emptyNumberBufferAsLiteral(); - $this->emptyStrBufferAsVariable(); - $this->tokens[] = new Token(Token::Space, ''); - - continue 2; - - case $this->isNumber($ch): - if ('' != $this->stringBuffer) { - $this->stringBuffer .= $ch; - - continue 2; - } - $this->numberBuffer .= $ch; - $this->allowNegative = false; - - break; - /** @noinspection PhpMissingBreakStatementInspection */ - case 'e' === \strtolower($ch): - if (\strlen($this->numberBuffer) && false !== \strpos($this->numberBuffer, '.')) { - $this->numberBuffer .= 'e'; - $this->allowNegative = false; - - break; - } - // no break - // Intentionally fall through - case $this->isAlpha($ch): - if (\strlen($this->numberBuffer)) { - $this->emptyNumberBufferAsLiteral(); - $this->tokens[] = new Token(Token::Operator, '*'); - } - $this->allowNegative = false; - $this->stringBuffer .= $ch; - - break; - - case '"' == $ch: - $this->inDoubleQuotedString = true; - - continue 2; - - case "'" == $ch: - $this->inSingleQuotedString = true; - - continue 2; - - case $this->isDot($ch): - $this->numberBuffer .= $ch; - $this->allowNegative = false; - - break; - - case $this->isLP($ch): - if ('' != $this->stringBuffer) { - $this->tokens[] = new Token(Token::Function, $this->stringBuffer); - $this->stringBuffer = ''; - } elseif (\strlen($this->numberBuffer)) { - $this->emptyNumberBufferAsLiteral(); - $this->tokens[] = new Token(Token::Operator, '*'); - } - $this->allowNegative = true; - $this->tokens[] = new Token(Token::LeftParenthesis, ''); - - break; - - case $this->isRP($ch) || ']' === $ch : - $this->emptyNumberBufferAsLiteral(); - $this->emptyStrBufferAsVariable(); - $this->allowNegative = false; - $this->tokens[] = new Token(Token::RightParenthesis, ''); - - break; - - case $this->isComma($ch): - $this->emptyNumberBufferAsLiteral(); - $this->emptyStrBufferAsVariable(); - $this->allowNegative = true; - $this->tokens[] = new Token(Token::ParamSeparator, ''); - - break; - - default: - // special case for unary operations - if ('-' == $ch || '+' == $ch) { - if ($this->allowNegative) { - $this->allowNegative = false; - $this->tokens[] = new Token(Token::Operator, '-' == $ch ? 'uNeg' : 'uPos'); - - continue 2; - } - // could be in exponent, in which case negative should be added to the numberBuffer - if ($this->numberBuffer && 'e' == $this->numberBuffer[\strlen($this->numberBuffer) - 1]) { - $this->numberBuffer .= $ch; - - continue 2; - } - } - $this->emptyNumberBufferAsLiteral(); - $this->emptyStrBufferAsVariable(); - - if ('$' != $ch) { - if (\count($this->tokens) > 0) { - if (Token::Operator === $this->tokens[\count($this->tokens) - 1]->type) { - $this->tokens[\count($this->tokens) - 1]->value .= $ch; - } else { - $this->tokens[] = new Token(Token::Operator, $ch); - } - } else { - $this->tokens[] = new Token(Token::Operator, $ch); - } - } - $this->allowNegative = true; - } - } - $this->emptyNumberBufferAsLiteral(); - $this->emptyStrBufferAsVariable(); - - return $this; - } - - /** - * @throws IncorrectBracketsException - * @throws UnknownOperatorException - * @return Token[] Array of tokens in revers polish notation - */ - public function buildReversePolishNotation() : array - { - $tokens = []; - /** @var SplStack $stack */ - $stack = new SplStack(); - /** - * @var SplStack $paramCounter - */ - $paramCounter = new SplStack(); - - foreach ($this->tokens as $token) { - switch ($token->type) { - case Token::Literal: - case Token::Variable: - case Token::String: - $tokens[] = $token; - - if ($paramCounter->count() > 0 && 0 === $paramCounter->top()) { - $paramCounter->push($paramCounter->pop() + 1); - } - - break; - - case Token::Function: - if ($paramCounter->count() > 0 && 0 === $paramCounter->top()) { - $paramCounter->push($paramCounter->pop() + 1); - } - $stack->push($token); - $paramCounter->push(0); - - break; - - case Token::LeftParenthesis: - $stack->push($token); - - break; - - case Token::ParamSeparator: - while (Token::LeftParenthesis !== $stack->top()->type) { - if (0 === $stack->count()) { - throw new IncorrectBracketsException(); - } - $tokens[] = $stack->pop(); - } - $paramCounter->push($paramCounter->pop() + 1); - - break; - - case Token::Operator: - if (! \array_key_exists($token->value, $this->operators)) { - throw new UnknownOperatorException($token->value); - } - $op1 = $this->operators[$token->value]; - - while ($stack->count() > 0 && Token::Operator === $stack->top()->type) { - if (! \array_key_exists($stack->top()->value, $this->operators)) { - throw new UnknownOperatorException($stack->top()->value); - } - $op2 = $this->operators[$stack->top()->value]; - - if ($op2->priority >= $op1->priority) { - $tokens[] = $stack->pop(); - - continue; - } - - break; - } - $stack->push($token); - - break; - - case Token::RightParenthesis: - while (true) { - try { - $ctoken = $stack->pop(); - - if (Token::LeftParenthesis === $ctoken->type) { - break; - } - $tokens[] = $ctoken; - } catch (RuntimeException $e) { - throw new IncorrectBracketsException(); - } - } - - if ($stack->count() > 0 && Token::Function == $stack->top()->type) { - /** - * @var Token $f - */ - $f = $stack->pop(); - $f->paramCount = $paramCounter->pop(); - $tokens[] = $f; - } - - break; - - case Token::Space: - //do nothing - } - } - - while (0 !== $stack->count()) { - if (Token::LeftParenthesis === $stack->top()->type || Token::RightParenthesis === $stack->top()->type) { - throw new IncorrectBracketsException(); - } - - if (Token::Space === $stack->top()->type) { - $stack->pop(); - - continue; - } - $tokens[] = $stack->pop(); - } - - return $tokens; - } - - private function isNumber(string $ch) : bool - { - return $ch >= '0' && $ch <= '9'; - } - - private function isAlpha(string $ch) : bool - { - return $ch >= 'a' && $ch <= 'z' || $ch >= 'A' && $ch <= 'Z' || '_' == $ch; - } - - private function emptyNumberBufferAsLiteral() : void - { - if (\strlen($this->numberBuffer)) { - $this->tokens[] = new Token(Token::Literal, $this->numberBuffer); - $this->numberBuffer = ''; - } - } - - private function isDot(string $ch) : bool - { - return '.' == $ch; - } - - private function isLP(string $ch) : bool - { - return '(' == $ch; - } - - private function isRP(string $ch) : bool - { - return ')' == $ch; - } - - private function emptyStrBufferAsVariable() : void - { - if ('' != $this->stringBuffer) { - $this->tokens[] = new Token(Token::Variable, $this->stringBuffer); - $this->stringBuffer = ''; - } - } - - private function isComma(string $ch) : bool - { - return ',' == $ch; - } -} diff --git a/vendor/nxp/math-executor/src/NXP/Exception/DivisionByZeroException.php b/vendor/nxp/math-executor/src/NXP/Exception/DivisionByZeroException.php deleted file mode 100644 index 3a9a978..0000000 --- a/vendor/nxp/math-executor/src/NXP/Exception/DivisionByZeroException.php +++ /dev/null @@ -1,19 +0,0 @@ - - */ -class DivisionByZeroException extends MathExecutorException -{ -} diff --git a/vendor/nxp/math-executor/src/NXP/Exception/IncorrectBracketsException.php b/vendor/nxp/math-executor/src/NXP/Exception/IncorrectBracketsException.php deleted file mode 100644 index 3b2d2b7..0000000 --- a/vendor/nxp/math-executor/src/NXP/Exception/IncorrectBracketsException.php +++ /dev/null @@ -1,19 +0,0 @@ - - */ -class IncorrectBracketsException extends MathExecutorException -{ -} diff --git a/vendor/nxp/math-executor/src/NXP/Exception/IncorrectExpressionException.php b/vendor/nxp/math-executor/src/NXP/Exception/IncorrectExpressionException.php deleted file mode 100644 index 6f579c1..0000000 --- a/vendor/nxp/math-executor/src/NXP/Exception/IncorrectExpressionException.php +++ /dev/null @@ -1,19 +0,0 @@ - - */ -class IncorrectExpressionException extends MathExecutorException -{ -} diff --git a/vendor/nxp/math-executor/src/NXP/Exception/IncorrectFunctionParameterException.php b/vendor/nxp/math-executor/src/NXP/Exception/IncorrectFunctionParameterException.php deleted file mode 100644 index b378718..0000000 --- a/vendor/nxp/math-executor/src/NXP/Exception/IncorrectFunctionParameterException.php +++ /dev/null @@ -1,16 +0,0 @@ - - */ -class MathExecutorException extends \Exception -{ -} diff --git a/vendor/nxp/math-executor/src/NXP/Exception/UnknownFunctionException.php b/vendor/nxp/math-executor/src/NXP/Exception/UnknownFunctionException.php deleted file mode 100644 index e8ff0c0..0000000 --- a/vendor/nxp/math-executor/src/NXP/Exception/UnknownFunctionException.php +++ /dev/null @@ -1,19 +0,0 @@ - - */ -class UnknownFunctionException extends MathExecutorException -{ -} diff --git a/vendor/nxp/math-executor/src/NXP/Exception/UnknownOperatorException.php b/vendor/nxp/math-executor/src/NXP/Exception/UnknownOperatorException.php deleted file mode 100644 index acb4b98..0000000 --- a/vendor/nxp/math-executor/src/NXP/Exception/UnknownOperatorException.php +++ /dev/null @@ -1,19 +0,0 @@ - - */ -class UnknownOperatorException extends MathExecutorException -{ -} diff --git a/vendor/nxp/math-executor/src/NXP/Exception/UnknownVariableException.php b/vendor/nxp/math-executor/src/NXP/Exception/UnknownVariableException.php deleted file mode 100644 index 031a603..0000000 --- a/vendor/nxp/math-executor/src/NXP/Exception/UnknownVariableException.php +++ /dev/null @@ -1,19 +0,0 @@ - - */ -class UnknownVariableException extends MathExecutorException -{ -} diff --git a/vendor/nxp/math-executor/src/NXP/MathExecutor.php b/vendor/nxp/math-executor/src/NXP/MathExecutor.php deleted file mode 100644 index e991586..0000000 --- a/vendor/nxp/math-executor/src/NXP/MathExecutor.php +++ /dev/null @@ -1,532 +0,0 @@ - - */ - protected array $variables = []; - - /** - * @var callable|null - */ - protected $onVarNotFound = null; - - /** - * @var callable|null - */ - protected $onVarValidation = null; - - /** - * @var Operator[] - */ - protected array $operators = []; - - /** - * @var array - */ - protected array $functions = []; - - /** - * @var array - */ - protected array $cache = []; - - /** - * Base math operators - */ - public function __construct() - { - $this->addDefaults(); - } - - public function __clone() - { - $this->addDefaults(); - } - - /** - * Add operator to executor - * - */ - public function addOperator(Operator $operator) : self - { - $this->operators[$operator->operator] = $operator; - - return $this; - } - - /** - * Execute expression - * - * @throws Exception\IncorrectBracketsException - * @throws Exception\IncorrectExpressionException - * @throws Exception\UnknownOperatorException - * @throws UnknownVariableException - * @return int|float|string|null - */ - public function execute(string $expression, bool $cache = true) - { - $cacheKey = $expression; - - if (! \array_key_exists($cacheKey, $this->cache)) { - $tokens = (new Tokenizer($expression, $this->operators))->tokenize()->buildReversePolishNotation(); - - if ($cache) { - $this->cache[$cacheKey] = $tokens; - } - } else { - $tokens = $this->cache[$cacheKey]; - } - - $calculator = new Calculator($this->functions, $this->operators); - - return $calculator->calculate($tokens, $this->variables, $this->onVarNotFound); - } - - /** - * Add function to executor - * - * @param string $name Name of function - * @param callable|null $function Function - * - * @throws ReflectionException - * @throws Exception\IncorrectNumberOfFunctionParametersException - */ - public function addFunction(string $name, ?callable $function = null) : self - { - $this->functions[$name] = new CustomFunction($name, $function); - - return $this; - } - - /** - * Get all vars - * - * @return array - */ - public function getVars() : array - { - return $this->variables; - } - - /** - * Get a specific var - * - * @throws UnknownVariableException if VarNotFoundHandler is not set - * @return int|float - */ - public function getVar(string $variable) - { - if (! \array_key_exists($variable, $this->variables)) { - if ($this->onVarNotFound) { - return \call_user_func($this->onVarNotFound, $variable); - } - - throw new UnknownVariableException("Variable ({$variable}) not set"); - } - - return $this->variables[$variable]; - } - - /** - * Add variable to executor. To set a custom validator use setVarValidationHandler. - * - * @throws MathExecutorException if the value is invalid based on the default or custom validator - */ - public function setVar(string $variable, $value) : self - { - if ($this->onVarValidation) { - \call_user_func($this->onVarValidation, $variable, $value); - } - - $this->variables[$variable] = $value; - - return $this; - } - - /** - * Test to see if a variable exists - * - */ - public function varExists(string $variable) : bool - { - return \array_key_exists($variable, $this->variables); - } - - /** - * Add variables to executor - * - * @param array $variables - * @param bool $clear Clear previous variables - * @throws \Exception - */ - public function setVars(array $variables, bool $clear = true) : self - { - if ($clear) { - $this->removeVars(); - } - - foreach ($variables as $name => $value) { - $this->setVar($name, $value); - } - - return $this; - } - - /** - * Define a method that will be invoked when a variable is not found. - * The first parameter will be the variable name, and the returned value will be used as the variable value. - * - * - */ - public function setVarNotFoundHandler(callable $handler) : self - { - $this->onVarNotFound = $handler; - - return $this; - } - - /** - * Define a validation method that will be invoked when a variable is set using setVar. - * The first parameter will be the variable name, and the second will be the variable value. - * Set to null to disable validation. - * - * @param ?callable $handler throws a MathExecutorException in case of an invalid variable - * - */ - public function setVarValidationHandler(?callable $handler) : self - { - $this->onVarValidation = $handler; - - return $this; - } - - /** - * Remove variable from executor - * - */ - public function removeVar(string $variable) : self - { - unset($this->variables[$variable]); - - return $this; - } - - /** - * Remove all variables and the variable not found handler - */ - public function removeVars() : self - { - $this->variables = []; - $this->onVarNotFound = null; - - return $this; - } - - /** - * Get all registered operators to executor - * - * @return array of operator class names - */ - public function getOperators() : array - { - return $this->operators; - } - - /** - * Get all registered functions - * - * @return array containing callback and places indexed by - * function name - */ - public function getFunctions() : array - { - return $this->functions; - } - - /** - * Remove a specific operator - * - * @return array of operator class names - */ - public function removeOperator(string $operator) : self - { - unset($this->operators[$operator]); - - return $this; - } - - /** - * Set division by zero returns zero instead of throwing DivisionByZeroException - */ - public function setDivisionByZeroIsZero() : self - { - $this->addOperator(new Operator('/', false, 180, static fn ($a, $b) => 0 == $b ? 0 : $a / $b)); - - return $this; - } - - /** - * Get cache array with tokens - * @return array - */ - public function getCache() : array - { - return $this->cache; - } - - /** - * Clear token's cache - */ - public function clearCache() : self - { - $this->cache = []; - - return $this; - } - - public function useBCMath(int $scale = 2) : self - { - \bcscale($scale); - $this->addOperator(new Operator('+', false, 170, static fn ($a, $b) => \bcadd("{$a}", "{$b}"))); - $this->addOperator(new Operator('-', false, 170, static fn ($a, $b) => \bcsub("{$a}", "{$b}"))); - $this->addOperator(new Operator('uNeg', false, 200, static fn ($a) => \bcsub('0.0', "{$a}"))); - $this->addOperator(new Operator('*', false, 180, static fn ($a, $b) => \bcmul("{$a}", "{$b}"))); - $this->addOperator(new Operator('/', false, 180, static function($a, $b) { - /** @todo PHP8: Use throw as expression -> static fn($a, $b) => 0 == $b ? throw new DivisionByZeroException() : $a / $b */ - if (0 == $b) { - throw new DivisionByZeroException(); - } - - return \bcdiv("{$a}", "{$b}"); - })); - $this->addOperator(new Operator('^', true, 220, static fn ($a, $b) => \bcpow("{$a}", "{$b}"))); - $this->addOperator(new Operator('%', false, 180, static fn ($a, $b) => \bcmod("{$a}", "{$b}"))); - - return $this; - } - - /** - * Set default operands and functions - * @throws ReflectionException - */ - protected function addDefaults() : self - { - foreach ($this->defaultOperators() as $name => $operator) { - [$callable, $priority, $isRightAssoc] = $operator; - $this->addOperator(new Operator($name, $isRightAssoc, $priority, $callable)); - } - - foreach ($this->defaultFunctions() as $name => $callable) { - $this->addFunction($name, $callable); - } - - $this->onVarValidation = [$this, 'defaultVarValidation']; - $this->variables = $this->defaultVars(); - - return $this; - } - - /** - * Get the default operators - * - * @return array - */ - protected function defaultOperators() : array - { - return [ - '+' => [static fn ($a, $b) => $a + $b, 170, false], - '-' => [static fn ($a, $b) => $a - $b, 170, false], - // unary positive token - 'uPos' => [static fn ($a) => $a, 200, false], - // unary minus token - 'uNeg' => [static fn ($a) => 0 - $a, 200, false], - '*' => [static fn ($a, $b) => $a * $b, 180, false], - '/' => [ - static function($a, $b) { /** @todo PHP8: Use throw as expression -> static fn($a, $b) => 0 == $b ? throw new DivisionByZeroException() : $a / $b */ - if (0 == $b) { - throw new DivisionByZeroException(); - } - - return $a / $b; - }, - 180, - false - ], - '^' => [static fn ($a, $b) => \pow($a, $b), 220, true], - '%' => [static fn ($a, $b) => $a % $b, 180, false], - '&&' => [static fn ($a, $b) => $a && $b, 100, false], - '||' => [static fn ($a, $b) => $a || $b, 90, false], - '==' => [static fn ($a, $b) => \is_string($a) || \is_string($b) ? 0 == \strcmp($a, $b) : $a == $b, 140, false], - '!=' => [static fn ($a, $b) => \is_string($a) || \is_string($b) ? 0 != \strcmp($a, $b) : $a != $b, 140, false], - '>=' => [static fn ($a, $b) => $a >= $b, 150, false], - '>' => [static fn ($a, $b) => $a > $b, 150, false], - '<=' => [static fn ($a, $b) => $a <= $b, 150, false], - '<' => [static fn ($a, $b) => $a < $b, 150, false], - ]; - } - - /** - * Gets the default functions as an array. Key is function name - * and value is the function as a closure. - * - * @return array - */ - protected function defaultFunctions() : array - { - return [ - 'abs' => static fn ($arg) => \abs($arg), - 'acos' => static fn ($arg) => \acos($arg), - 'acosh' => static fn ($arg) => \acosh($arg), - 'arcsin' => static fn ($arg) => \asin($arg), - 'arcctg' => static fn ($arg) => M_PI / 2 - \atan($arg), - 'arccot' => static fn ($arg) => M_PI / 2 - \atan($arg), - 'arccotan' => static fn ($arg) => M_PI / 2 - \atan($arg), - 'arcsec' => static fn ($arg) => \acos(1 / $arg), - 'arccosec' => static fn ($arg) => \asin(1 / $arg), - 'arccsc' => static fn ($arg) => \asin(1 / $arg), - 'arccos' => static fn ($arg) => \acos($arg), - 'arctan' => static fn ($arg) => \atan($arg), - 'arctg' => static fn ($arg) => \atan($arg), - 'array' => static fn (...$args) => $args, - 'asin' => static fn ($arg) => \asin($arg), - 'atan' => static fn ($arg) => \atan($arg), - 'atan2' => static fn ($arg1, $arg2) => \atan2($arg1, $arg2), - 'atanh' => static fn ($arg) => \atanh($arg), - 'atn' => static fn ($arg) => \atan($arg), - 'avg' => static function($arg1, ...$args) { - if (\is_array($arg1)){ - if (0 === \count($arg1)){ - throw new \InvalidArgumentException('avg() must have at least one argument!'); - } - - return \array_sum($arg1) / \count($arg1); - } - - $args = [$arg1, ...$args]; - - return \array_sum($args) / \count($args); - }, - 'bindec' => static fn ($arg) => \bindec($arg), - 'ceil' => static fn ($arg) => \ceil($arg), - 'cos' => static fn ($arg) => \cos($arg), - 'cosec' => static fn ($arg) => 1 / \sin($arg), - 'csc' => static fn ($arg) => 1 / \sin($arg), - 'cosh' => static fn ($arg) => \cosh($arg), - 'ctg' => static fn ($arg) => \cos($arg) / \sin($arg), - 'cot' => static fn ($arg) => \cos($arg) / \sin($arg), - 'cotan' => static fn ($arg) => \cos($arg) / \sin($arg), - 'cotg' => static fn ($arg) => \cos($arg) / \sin($arg), - 'ctn' => static fn ($arg) => \cos($arg) / \sin($arg), - 'decbin' => static fn ($arg) => \decbin($arg), - 'dechex' => static fn ($arg) => \dechex($arg), - 'decoct' => static fn ($arg) => \decoct($arg), - 'deg2rad' => static fn ($arg) => \deg2rad($arg), - 'exp' => static fn ($arg) => \exp($arg), - 'expm1' => static fn ($arg) => \expm1($arg), - 'floor' => static fn ($arg) => \floor($arg), - 'fmod' => static fn ($arg1, $arg2) => \fmod($arg1, $arg2), - 'hexdec' => static fn ($arg) => \hexdec($arg), - 'hypot' => static fn ($arg1, $arg2) => \hypot($arg1, $arg2), - 'if' => function($expr, $trueval, $falseval) { - if (true === $expr || false === $expr) { - $exres = $expr; - } else { - $exres = $this->execute($expr); - } - - if ($exres) { - return $this->execute($trueval); - } - - return $this->execute($falseval); - }, - 'intdiv' => static fn ($arg1, $arg2) => \intdiv($arg1, $arg2), - 'ln' => static fn ($arg) => \log($arg), - 'lg' => static fn ($arg) => \log10($arg), - 'log' => static fn ($arg) => \log($arg), - 'log10' => static fn ($arg) => \log10($arg), - 'log1p' => static fn ($arg) => \log1p($arg), - 'max' => static function($arg1, ...$args) { - if (\is_array($arg1) && 0 === \count($arg1)){ - throw new \InvalidArgumentException('max() must have at least one argument!'); - } - - return \max(\is_array($arg1) ? $arg1 : [$arg1, ...$args]); - }, - 'min' => static function($arg1, ...$args) { - if (\is_array($arg1) && 0 === \count($arg1)){ - throw new \InvalidArgumentException('min() must have at least one argument!'); - } - - return \min(\is_array($arg1) ? $arg1 : [$arg1, ...$args]); - }, - 'octdec' => static fn ($arg) => \octdec($arg), - 'pi' => static fn () => M_PI, - 'pow' => static fn ($arg1, $arg2) => $arg1 ** $arg2, - 'rad2deg' => static fn ($arg) => \rad2deg($arg), - 'round' => static fn ($num, int $precision = 0) => \round($num, $precision), - 'sin' => static fn ($arg) => \sin($arg), - 'sinh' => static fn ($arg) => \sinh($arg), - 'sec' => static fn ($arg) => 1 / \cos($arg), - 'sqrt' => static fn ($arg) => \sqrt($arg), - 'tan' => static fn ($arg) => \tan($arg), - 'tanh' => static fn ($arg) => \tanh($arg), - 'tn' => static fn ($arg) => \tan($arg), - 'tg' => static fn ($arg) => \tan($arg) - ]; - } - - /** - * Returns the default variables names as key/value pairs - * - * @return array - */ - protected function defaultVars() : array - { - return [ - 'pi' => 3.14159265359, - 'e' => 2.71828182846 - ]; - } - - /** - * Default variable validation, ensures that the value is a scalar or array. - * @throws MathExecutorException if the value is not a scalar - */ - protected function defaultVarValidation(string $variable, $value) : void - { - if (! \is_scalar($value) && ! \is_array($value) && null !== $value) { - $type = \gettype($value); - - throw new MathExecutorException("Variable ({$variable}) type ({$type}) is not scalar or array!"); - } - } -} diff --git a/vendor/nxp/math-executor/tests/MathTest.php b/vendor/nxp/math-executor/tests/MathTest.php deleted file mode 100644 index 0c87c45..0000000 --- a/vendor/nxp/math-executor/tests/MathTest.php +++ /dev/null @@ -1,1163 +0,0 @@ -execute($expression); - } catch (Exception $e) { - $this->fail(\sprintf('Exception: %s (%s:%d), expression was: %s', \get_class($e), $e->getFile(), $e->getLine(), $expression)); - } - $this->assertEquals($phpResult, $result, "Expression was: {$expression}"); - } - - /** - * Expressions data provider - * - * Most tests can go in here. The idea is that each expression will be evaluated by MathExecutor and by PHP with eval. - * The results should be the same. If they are not, then the test fails. No need to add extra test unless you are doing - * something more complex and not a simple mathmatical expression. - */ - public function providerExpressions() - { - return [ - ['-5'], - ['-5+10'], - ['4-5'], - ['4 -5'], - ['(4*2)-5'], - ['(4*2) - 5'], - ['4*-5'], - ['4 * -5'], - ['+5'], - ['+(3+2)'], - ['+(+3+2)'], - ['+(-3+2)'], - ['-5'], - ['-(-5)'], - ['-(+5)'], - ['+(-5)'], - ['+(+5)'], - ['-(3+2)'], - ['-(-3+-2)'], - - ['abs(1.5)'], - ['acos(0.15)'], - ['acosh(1.5)'], - ['asin(0.15)'], - ['atan(0.15)'], - ['atan2(1.5, 3.5)'], - ['atanh(0.15)'], - ['bindec("10101")'], - ['ceil(1.5)'], - ['cos(1.5)'], - ['cosh(1.5)'], - ['decbin("15")'], - ['dechex("15")'], - ['decoct("15")'], - ['deg2rad(1.5)'], - ['exp(1.5)'], - ['expm1(1.5)'], - ['floor(1.5)'], - ['fmod(1.5, 3.5)'], - ['hexdec("abcdef")'], - ['hypot(1.5, 3.5)'], - ['intdiv(10, 2)'], - ['log(1.5)'], - ['log10(1.5)'], - ['log1p(1.5)'], - ['max(1.5, 3.5)'], - ['min(1.5, 3.5)'], - ['octdec("15")'], - ['pi()'], - ['pow(1.5, 3.5)'], - ['rad2deg(1.5)'], - ['round(1.5)'], - ['sin(1.5)'], - ['sin(12)'], - ['+sin(12)'], - ['-sin(12)'], - ['sinh(1.5)'], - ['sqrt(1.5)'], - ['tan(1.5)'], - ['tanh(1.5)'], - - ['0.1 + 0.2'], - ['0.1 + 0.2 - 0.3'], - ['1 + 2'], - - ['0.1 - 0.2'], - ['1 - 2'], - - ['0.1 * 2'], - ['1 * 2'], - - ['0.1 / 0.2'], - ['1 / 2'], - - ['2 * 2 + 3 * 3'], - ['2 * 2 / 3 * 3'], - ['2 / 2 / 3 / 3'], - ['2 / 2 * 3 / 3'], - ['2 / 2 * 3 * 3'], - - ['1 + 0.6 - 3 * 2 / 50'], - - ['(5 + 3) * -1'], - - ['-2- 2*2'], - ['2- 2*2'], - ['2-(2*2)'], - ['(2- 2)*2'], - ['2 + 2*2'], - ['2+ 2*2'], - ['2+2*2'], - ['(2+2)*2'], - ['(2 + 2)*-2'], - ['(2+-2)*2'], - - ['1 + 2 * 3 / (min(1, 5) + 2 + 1)'], - ['1 + 2 * 3 / (min(1, 5) - 2 + 5)'], - ['1 + 2 * 3 / (min(1, 5) * 2 + 1)'], - ['1 + 2 * 3 / (min(1, 5) / 2 + 1)'], - ['1 + 2 * 3 / (min(1, 5) / 2 * 1)'], - ['1 + 2 * 3 / (min(1, 5) / 2 / 1)'], - ['1 + 2 * 3 / (3 + min(1, 5) + 2 + 1)'], - ['1 + 2 * 3 / (3 - min(1, 5) - 2 + 1)'], - ['1 + 2 * 3 / (3 * min(1, 5) * 2 + 1)'], - ['1 + 2 * 3 / (3 / min(1, 5) / 2 + 1)'], - - ['(1 + 2) * 3 / (3 / min(1, 5) / 2 + 1)'], - - ['sin(10) * cos(50) / min(10, 20/2)'], - ['sin(10) * cos(50) / min(10, (20/2))'], - ['sin(10) * cos(50) / min(10, (max(10,20)/2))'], - - ['100500 * 3.5e5'], - ['100500 * 3.5e-5'], - ['100500 * 3.5E5'], - ['100500 * 3.5E-5'], - - ['1 + "2" / 3'], - ["1.5 + '2.5' / 4"], - ['1.5 + "2.5" * ".5"'], - - ['-1 + -2'], - ['-1+-2'], - ['-1- -2'], - ['-1/-2'], - ['-1*-2'], - - ['(1+2+3+4-5)*7/100'], - ['(-1+2+3+4- 5)*7/100'], - ['(1+2+3+4- 5)*7/100'], - ['( 1 + 2 + 3 + 4 - 5 ) * 7 / 100'], - - ['1 && 0'], - ['1 && 0 && 1'], - ['1 || 0'], - ['1 && 0 || 1'], - - ['5 == 3'], - ['5 == 5'], - ['5 != 3'], - ['5 != 5'], - ['5 > 3'], - ['3 > 5'], - ['3 >= 5'], - ['3 >= 3'], - ['3 < 5'], - ['5 < 3'], - ['3 <= 5'], - ['5 <= 5'], - ['10 < 9 || 4 > (2+1)'], - ['10 < 9 || 4 > (-2+1)'], - ['10 < 9 || 4 > (2+1) && 5 == 5 || 4 != 6 || 3 >= 4 || 3 <= 7'], - - ['1 + 5 == 3 + 1'], - ['1 + 5 == 5 + 1'], - ['1 + 5 != 3 + 1'], - ['1 + 5 != 5 + 1'], - ['1 + 5 > 3 + 1'], - ['1 + 3 > 5 + 1'], - ['1 + 3 >= 5 + 1'], - ['1 + 3 >= 3 + 1'], - ['1 + 3 < 5 + 1'], - ['1 + 5 < 3 + 1'], - ['1 + 3 <= 5 + 1'], - ['1 + 5 <= 5 + 1'], - - ['(-4)'], - ['(-4 + 5)'], - ['(3 * 1)'], - ['(-3 * -1)'], - ['1 + (-3 * -1)'], - ['1 + ( -3 * 1)'], - ['1 + (3 *-1)'], - ['1 - 0'], - ['1-0'], - - ['-(1.5)'], - ['-log(4)'], - ['0-acosh(1.5)'], - ['-acosh(1.5)'], - ['-(-4)'], - ['-(-4 + 5)'], - ['-(3 * 1)'], - ['-(-3 * -1)'], - ['-1 + (-3 * -1)'], - ['-1 + ( -3 * 1)'], - ['-1 + (3 *-1)'], - ['-1 - 0'], - ['-1-0'], - ['-(4*2)-5'], - ['-(4*-2)-5'], - ['-(-4*2) - 5'], - ['-4*-5'], - ['max(1,2,4.9,3)'], - ['min(1,2,4.9,3)'], - ['max([1,2,4.9,3])'], - ['min([1,2,4.9,3])'], - - ['4 % 4'], - ['7 % 4'], - ['99 % 4'], - ['123 % 7'], - ]; - } - - /** - * @dataProvider bcMathExpressions - */ - public function testBCMathCalculating(string $expression, string $expected = '') : void - { - $calculator = new MathExecutor(); - $calculator->useBCMath(); - - if ('' === $expected) - { - $expected = $expression; - } - - /** @var float $phpResult */ - eval('$phpResult = ' . $expected . ';'); - - try { - $result = $calculator->execute($expression); - } catch (Exception $e) { - $this->fail(\sprintf('Exception: %s (%s:%d), expression was: %s', \get_class($e), $e->getFile(), $e->getLine(), $expression)); - } - $this->assertEquals($phpResult, $result, "Expression was: {$expression}"); - } - - /** - * Expressions data provider - * - * Most tests can go in here. The idea is that each expression will be evaluated by MathExecutor and by PHP with eval. - * The results should be the same. If they are not, then the test fails. No need to add extra test unless you are doing - * something more complex and not a simple mathmatical expression. - */ - public function bcMathExpressions() - { - return [ - ['-5'], - ['-5+10'], - ['4-5'], - ['4 -5'], - ['(4*2)-5'], - ['(4*2) - 5'], - ['4*-5'], - ['4 * -5'], - ['+5'], - ['+(3+2)'], - ['+(+3+2)'], - ['+(-3+2)'], - ['-5'], - ['-(-5)'], - ['-(+5)'], - ['+(-5)'], - ['+(+5)'], - ['-(3+2)'], - ['-(-3+-2)'], - - ['abs(1.5)'], - ['acos(0.15)'], - ['acosh(1.5)'], - ['asin(0.15)'], - ['atan(0.15)'], - ['atan2(1.5, 3.5)'], - ['atanh(0.15)'], - ['bindec("10101")'], - ['ceil(1.5)'], - ['cos(1.5)'], - ['cosh(1.5)'], - ['decbin("15")'], - ['dechex("15")'], - ['decoct("15")'], - ['deg2rad(1.5)'], - ['exp(1.5)'], - ['expm1(1.5)'], - ['floor(1.5)'], - ['fmod(1.5, 3.5)'], - ['hexdec("abcdef")'], - ['hypot(1.5, 3.5)'], - ['intdiv(10, 2)'], - ['log(1.5)'], - ['log10(1.5)'], - ['log1p(1.5)'], - ['max(1.5, 3.5)'], - ['min(1.5, 3.5)'], - ['octdec("15")'], - ['pi()'], - ['pow(1.5, 3.5)'], - ['rad2deg(1.5)'], - ['round(1.5)'], - ['sin(1.5)'], - ['sin(12)'], - ['+sin(12)'], - ['-sin(12)', '0.53'], - ['sinh(1.5)'], - ['sqrt(1.5)'], - ['tan(1.5)'], - ['tanh(1.5)'], - - ['0.1 + 0.2', '0.30'], - ['0.1 + 0.2 - 0.3', '0.00'], - ['1 + 2'], - - ['0.1 - 0.2'], - ['1 - 2'], - - ['0.1 * 2'], - ['1 * 2'], - - ['0.1 / 0.2'], - ['1 / 2'], - - ['2 * 2 + 3 * 3'], - ['2 * 2 / 3 * 3', '3.99'], - ['2 / 2 / 3 / 3', '0.11'], - ['2 / 2 * 3 / 3'], - ['2 / 2 * 3 * 3'], - - ['1 + 0.6 - 3 * 2 / 50'], - - ['(5 + 3) * -1'], - - ['-2- 2*2'], - ['2- 2*2'], - ['2-(2*2)'], - ['(2- 2)*2'], - ['2 + 2*2'], - ['2+ 2*2'], - ['2+2*2'], - ['(2+2)*2'], - ['(2 + 2)*-2'], - ['(2+-2)*2'], - - ['1 + 2 * 3 / (min(1, 5) + 2 + 1)'], - ['1 + 2 * 3 / (min(1, 5) - 2 + 5)'], - ['1 + 2 * 3 / (min(1, 5) * 2 + 1)'], - ['1 + 2 * 3 / (min(1, 5) / 2 + 1)'], - ['1 + 2 * 3 / (min(1, 5) / 2 * 1)'], - ['1 + 2 * 3 / (min(1, 5) / 2 / 1)'], - ['1 + 2 * 3 / (3 + min(1, 5) + 2 + 1)', '1.85'], - ['1 + 2 * 3 / (3 - min(1, 5) - 2 + 1)'], - ['1 + 2 * 3 / (3 * min(1, 5) * 2 + 1)', '1.85'], - ['1 + 2 * 3 / (3 / min(1, 5) / 2 + 1)'], - - ['(1 + 2) * 3 / (3 / min(1, 5) / 2 + 1)'], - - ['sin(10) * cos(50) / min(10, 20/2)', '-0.05'], - ['sin(10) * cos(50) / min(10, (20/2))', '-0.05'], - ['sin(10) * cos(50) / min(10, (max(10,20)/2))', '-0.05'], - - ['1 + "2" / 3', '1.66'], - ["1.5 + '2.5' / 4", '2.12'], - ['1.5 + "2.5" * ".5"'], - - ['-1 + -2'], - ['-1+-2'], - ['-1- -2'], - ['-1/-2'], - ['-1*-2'], - - ['(1+2+3+4-5)*7/100'], - ['(-1+2+3+4- 5)*7/100'], - ['(1+2+3+4- 5)*7/100'], - ['( 1 + 2 + 3 + 4 - 5 ) * 7 / 100'], - - ['1 && 0'], - ['1 && 0 && 1'], - ['1 || 0'], - ['1 && 0 || 1'], - - ['5 == 3'], - ['5 == 5'], - ['5 != 3'], - ['5 != 5'], - ['5 > 3'], - ['3 > 5'], - ['3 >= 5'], - ['3 >= 3'], - ['3 < 5'], - ['5 < 3'], - ['3 <= 5'], - ['5 <= 5'], - ['10 < 9 || 4 > (2+1)'], - ['10 < 9 || 4 > (-2+1)'], - ['10 < 9 || 4 > (2+1) && 5 == 5 || 4 != 6 || 3 >= 4 || 3 <= 7'], - - ['1 + 5 == 3 + 1'], - ['1 + 5 == 5 + 1'], - ['1 + 5 != 3 + 1'], - ['1 + 5 != 5 + 1'], - ['1 + 5 > 3 + 1'], - ['1 + 3 > 5 + 1'], - ['1 + 3 >= 5 + 1'], - ['1 + 3 >= 3 + 1'], - ['1 + 3 < 5 + 1'], - ['1 + 5 < 3 + 1'], - ['1 + 3 <= 5 + 1'], - ['1 + 5 <= 5 + 1'], - - ['(-4)'], - ['(-4 + 5)'], - ['(3 * 1)'], - ['(-3 * -1)'], - ['1 + (-3 * -1)'], - ['1 + ( -3 * 1)'], - ['1 + (3 *-1)'], - ['1 - 0'], - ['1-0'], - - ['-(1.5)'], - ['-log(4)', '-1.38'], - ['0-acosh(1.5)', '-0.96'], - ['-acosh(1.5)', '-0.96'], - ['-(-4)'], - ['-(-4 + 5)'], - ['-(3 * 1)'], - ['-(-3 * -1)'], - ['-1 + (-3 * -1)'], - ['-1 + ( -3 * 1)'], - ['-1 + (3 *-1)'], - ['-1 - 0'], - ['-1-0'], - ['-(4*2)-5'], - ['-(4*-2)-5'], - ['-(-4*2) - 5'], - ['-4*-5'], - ['max(1,2,4.9,3)'], - ['min(1,2,4.9,3)'], - ['max([1,2,4.9,3])'], - ['min([1,2,4.9,3])'], - - ['4 % 4'], - ['7 % 4'], - ['99 % 4'], - ['123 % 7'], - ]; - } - - /** - * @dataProvider incorrectExpressions - */ - public function testIncorrectExpressionException(string $expression) : void - { - $calculator = new MathExecutor(); - $calculator->setVars(['a' => 12, 'b' => 24]); - $this->expectException(IncorrectExpressionException::class); - $calculator->execute($expression); - } - - /** - * Incorrect Expressions data provider - * - * These expressions should not pass validation - */ - public function incorrectExpressions() - { - return [ - ['1 * + '], - [' 2 3'], - ['2 3 '], - [' 2 4 3 '], - ['$a $b'], - ['$a [3, 4, 5]'], - ['$a (3 + 4)'], - ['$a "string"'], - ['5 "string"'], - ['"string" $a'], - ['$a round(12.345)'], - ['round(12.345) $a'], - ['4 round(12.345)'], - ['round(12.345) 4'], - ]; - } - - public function testUnknownFunctionException() : void - { - $calculator = new MathExecutor(); - $this->expectException(UnknownFunctionException::class); - $calculator->execute('1 * fred("wilma") + 3'); - } - - public function testZeroDivision() : void - { - $calculator = new MathExecutor(); - $calculator->setDivisionByZeroIsZero(); - $this->assertEquals(0, $calculator->execute('10 / 0')); - } - - public function testUnaryOperators() : void - { - $calculator = new MathExecutor(); - $this->assertEquals(5, $calculator->execute('+5')); - $this->assertEquals(5, $calculator->execute('+(3+2)')); - $this->assertEquals(-5, $calculator->execute('-5')); - $this->assertEquals(5, $calculator->execute('-(-5)')); - $this->assertEquals(-5, $calculator->execute('+(-5)')); - $this->assertEquals(-5, $calculator->execute('-(3+2)')); - } - - public function testZeroDivisionException() : void - { - $calculator = new MathExecutor(); - $this->expectException(DivisionByZeroException::class); - $calculator->execute('10 / 0'); - $calculator->setVar('one', 1)->setVar('zero', 0); - $this->assertEquals(0.0, $calculator->execute('$one / $zero')); - } - - public function testVariableIncorrectExpressionException() : void - { - $calculator = new MathExecutor(); - $calculator->setVar('four', 4); - $this->assertEquals(4, $calculator->execute('$four')); - $this->expectException(IncorrectExpressionException::class); - $this->assertEquals(0.0, $calculator->execute('$')); - $this->assertEquals(0.0, $calculator->execute('$ + $four')); - } - - public function testExponentiation() : void - { - $calculator = new MathExecutor(); - $this->assertEquals(100, $calculator->execute('10 ^ 2')); - } - - public function testStringEscape() : void - { - $calculator = new MathExecutor(); - $this->assertEquals("test\string", $calculator->execute('"test\string"')); - $this->assertEquals("\\test\string\\", $calculator->execute('"\test\string\\\\"')); - $this->assertEquals('\test\string\\', $calculator->execute('"\test\string\\\\"')); - $this->assertEquals('test\\\\string', $calculator->execute('"test\\\\\\\\string"')); - $this->assertEquals('test"string', $calculator->execute('"test\"string"')); - $this->assertEquals('test""string', $calculator->execute('"test\"\"string"')); - $this->assertEquals('"teststring', $calculator->execute('"\"teststring"')); - $this->assertEquals('teststring"', $calculator->execute('"teststring\""')); - $this->assertEquals("test'string", $calculator->execute("'test\'string'")); - $this->assertEquals("test''string", $calculator->execute("'test\'\'string'")); - $this->assertEquals("'teststring", $calculator->execute("'\'teststring'")); - $this->assertEquals("teststring'", $calculator->execute("'teststring\''")); - - $calculator->addFunction('concat', static function($arg1, $arg2) { - return $arg1 . $arg2; - }); - $this->assertEquals('test"ing', $calculator->execute('concat("test\"","ing")')); - $this->assertEquals("test'ing", $calculator->execute("concat('test\'','ing')")); - } - - public function testArrays() : void - { - $calculator = new MathExecutor(); - $this->assertEquals([1, 5, 2], $calculator->execute('array(1, 5, 2)')); - $this->assertEquals([1, 5, 2], $calculator->execute('[1, 5, 2]')); - $this->assertEquals(\max([1, 5, 2]), $calculator->execute('max([1, 5, 2])')); - $this->assertEquals(\max([1, 5, 2]), $calculator->execute('max(array(1, 5, 2))')); - $calculator->addFunction('arr_with_max_elements', static function($arg1, ...$args) { - $args = \is_array($arg1) ? $arg1 : [$arg1, ...$args]; - \usort($args, static fn ($arr1, $arr2) => \count($arr2) <=> \count($arr1)); - - return $args[0]; - }); - $this->assertEquals([3, 3, 3], $calculator->execute('arr_with_max_elements([[1],array(2,2),[3,3,3]])')); - } - - public function testFunctionParameterOrder() : void - { - $calculator = new MathExecutor(); - - $calculator->addFunction('concat', static function($arg1, $arg2) { - return $arg1 . $arg2; - }); - $this->assertEquals('testing', $calculator->execute('concat("test","ing")')); - $this->assertEquals('testing', $calculator->execute("concat('test','ing')")); - } - - public function testFunction() : void - { - $calculator = new MathExecutor(); - $calculator->addFunction('round', static function($arg) { - return \round($arg); - }); - $this->assertEquals(\round(100 / 30), $calculator->execute('round(100/30)')); - } - - public function testFunctionUnlimitedParameters() : void - { - $calculator = new MathExecutor(); - $calculator->addFunction('give_me_an_array', static function() { - return [5, 3, 7, 9, 8]; - }); - $this->assertEquals(6.4, $calculator->execute('avg(give_me_an_array())')); - $this->assertEquals(10, $calculator->execute('avg(12,8,15,5)')); - $this->assertEquals(3, $calculator->execute('min(give_me_an_array())')); - $this->assertEquals(1, $calculator->execute('min(1,2,3)')); - $this->assertEquals(9, $calculator->execute('max(give_me_an_array())')); - $this->assertEquals(3, $calculator->execute('max(1,2,3)')); - $calculator->setVar('monthly_salaries', [100, 200, 300]); - $this->assertEquals([100, 200, 300], $calculator->execute('$monthly_salaries')); - $this->assertEquals(200, $calculator->execute('avg($monthly_salaries)')); - $this->assertEquals(\min([100, 200, 300]), $calculator->execute('min($monthly_salaries)')); - $this->assertEquals(\max([100, 200, 300]), $calculator->execute('max($monthly_salaries)')); - } - - public function testFunctionOptionalParameters() : void - { - $calculator = new MathExecutor(); - $calculator->addFunction('round', static function($num, $precision = 0) { - return \round($num, $precision); - }); - $this->assertEquals(\round(11.176), $calculator->execute('round(11.176)')); - $this->assertEquals(\round(11.176, 2), $calculator->execute('round(11.176,2)')); - } - - public function testFunctionIncorrectNumberOfParameters() : void - { - $calculator = new MathExecutor(); - $this->expectException(IncorrectNumberOfFunctionParametersException::class); - $calculator->addFunction('myfunc', static function($arg1, $arg2) { - return $arg1 + $arg2; - }); - $calculator->execute('myfunc(1)'); - } - - public function testFunctionIncorrectNumberOfParametersTooMany() : void - { - $calculator = new MathExecutor(); - $this->expectException(IncorrectNumberOfFunctionParametersException::class); - $calculator->addFunction('myfunc', static function($arg1, $arg2) { - return $arg1 + $arg2; - }); - $calculator->execute('myfunc(1,2,3)'); - } - - public function testFunctionIf() : void - { - $calculator = new MathExecutor(); - $this->assertEquals( - 30, - $calculator->execute( - 'if(100 > 99, 30, 0)' - ), - 'Expression failed: if(100 > 99, 30, 0)' - ); - $this->assertEquals( - 0, - $calculator->execute( - 'if(100 < 99, 30, 0)' - ), - 'Expression failed: if(100 < 99, 30, 0)' - ); - $this->assertEquals( - 30, - $calculator->execute( - 'if(98 < 99 && sin(1) < 1, 30, 0)' - ), - 'Expression failed: if(98 < 99 && sin(1) < 1, 30, 0)' - ); - $this->assertEquals( - 40, - $calculator->execute( - 'if(98 < 99 && sin(1) < 1, max(30, 40), 0)' - ), - 'Expression failed: if(98 < 99 && sin(1) < 1, max(30, 40), 0)' - ); - $this->assertEquals( - 40, - $calculator->execute( - 'if(98 < 99 && sin(1) < 1, if(10 > 5, max(30, 40), 1), 0)' - ), - 'Expression failed: if(98 < 99 && sin(1) < 1, if(10 > 5, max(30, 40), 1), 0)' - ); - $this->assertEquals( - 20, - $calculator->execute( - 'if(98 < 99 && sin(1) > 1, if(10 > 5, max(30, 40), 1), if(4 <= 4, 20, 21))' - ), - 'Expression failed: if(98 < 99 && sin(1) > 1, if(10 > 5, max(30, 40), 1), if(4 <= 4, 20, 21))' - ); - $this->assertEquals( - \cos(2), - $calculator->execute( - 'if(98 < 99 && sin(1) >= 1, max(30, 40), cos(2))' - ), - 'Expression failed: if(98 < 99 && sin(1) >= 1, max(30, 40), cos(2))' - ); - $this->assertEquals( - \cos(2), - $calculator->execute( - 'if(cos(2), cos(2), 0)' - ), - 'Expression failed: if(cos(2), cos(2), 0)' - ); - $trx_amount = 100000; - $calculator->setVar('trx_amount', $trx_amount); - $this->assertEquals($trx_amount, $calculator->execute('$trx_amount')); - $this->assertEquals( - $trx_amount * 0.03, - $calculator->execute( - 'if($trx_amount < 40000, $trx_amount * 0.06, $trx_amount * 0.03)' - ), - 'Expression failed: if($trx_amount < 40000, $trx_amount * 0.06, $trx_amount * 0.03)' - ); - $this->assertEquals( - $trx_amount * 0.03, - $calculator->execute( - 'if($trx_amount < 40000, $trx_amount * 0.06, if($trx_amount < 60000, $trx_amount * 0.05, $trx_amount * 0.03))' - ), - 'Expression failed: if($trx_amount < 40000, $trx_amount * 0.06, if($trx_amount < 60000, $trx_amount * 0.05, $trx_amount * 0.03))' - ); - $trx_amount = 39000; - $calculator->setVar('trx_amount', $trx_amount); - $this->assertEquals( - $trx_amount * 0.06, - $calculator->execute( - 'if($trx_amount < 40000, $trx_amount * 0.06, if($trx_amount < 60000, $trx_amount * 0.05, $trx_amount * 0.03))' - ), - 'Expression failed: if($trx_amount < 40000, $trx_amount * 0.06, if($trx_amount < 60000, $trx_amount * 0.05, $trx_amount * 0.03))' - ); - $trx_amount = 59000; - $calculator->setVar('trx_amount', $trx_amount); - $this->assertEquals( - $trx_amount * 0.05, - $calculator->execute( - 'if($trx_amount < 40000, $trx_amount * 0.06, if($trx_amount < 60000, $trx_amount * 0.05, $trx_amount * 0.03))' - ), - 'Expression failed: if($trx_amount < 40000, $trx_amount * 0.06, if($trx_amount < 60000, $trx_amount * 0.05, $trx_amount * 0.03))' - ); - $this->expectException(IncorrectNumberOfFunctionParametersException::class); - $this->assertEquals( - 0.0, - $calculator->execute( - 'if($trx_amount < 40000, $trx_amount * 0.06)' - ), - 'Expression failed: if($trx_amount < 40000, $trx_amount * 0.06)' - ); - } - - public function testVariables() : void - { - $calculator = new MathExecutor(); - $this->assertEquals(3.14159265359, $calculator->execute('$pi')); - $this->assertEquals(3.14159265359, $calculator->execute('pi')); - $this->assertEquals(2.71828182846, $calculator->execute('$e')); - $this->assertEquals(2.71828182846, $calculator->execute('e')); - $calculator->setVars([ - 'trx_amount' => 100000.01, - 'ten' => 10, - 'nine' => 9, - 'eight' => 8, - 'seven' => 7, - 'six' => 6, - 'five' => 5, - 'four' => 4, - 'three' => 3, - 'two' => 2, - 'one' => 1, - 'zero' => 0, - ]); - $this->assertEquals(100000.01, $calculator->execute('$trx_amount')); - $this->assertEquals(10 - 9, $calculator->execute('$ten - $nine')); - $this->assertEquals(9 - 10, $calculator->execute('$nine - $ten')); - $this->assertEquals(10 + 9, $calculator->execute('$ten + $nine')); - $this->assertEquals(10 * 9, $calculator->execute('$ten * $nine')); - $this->assertEquals(10 / 9, $calculator->execute('$ten / $nine')); - $this->assertEquals(10 / (9 / 5), $calculator->execute('$ten / ($nine / $five)')); - - // test variables without leading $ - $this->assertEquals(100000.01, $calculator->execute('trx_amount')); - $this->assertEquals(10 - 9, $calculator->execute('ten - nine')); - $this->assertEquals(9 - 10, $calculator->execute('nine - ten')); - $this->assertEquals(10 + 9, $calculator->execute('ten + nine')); - $this->assertEquals(10 * 9, $calculator->execute('ten * nine')); - $this->assertEquals(10 / 9, $calculator->execute('ten / nine')); - $this->assertEquals(10 / (9 / 5), $calculator->execute('ten / (nine / five)')); - } - - public function testEvaluateFunctionParameters() : void - { - $calculator = new MathExecutor(); - $calculator->addFunction( - 'round', - static function($value, $decimals) { - return \round($value, $decimals); - } - ); - $expression = 'round(100 * 1.111111, 2)'; - $phpResult = 0; - eval('$phpResult = ' . $expression . ';'); - $this->assertEquals($phpResult, $calculator->execute($expression)); - $expression = 'round((100*0.04)+(((100*1.02)+0.5)*1.28),2)'; - eval('$phpResult = ' . $expression . ';'); - $this->assertEquals($phpResult, $calculator->execute($expression)); - } - - public function testFunctionsWithQuotes() : void - { - $calculator = new MathExecutor(); - $calculator->addFunction('concat', static function($first, $second) { - return $first . $second; - }); - $this->assertEquals('testing', $calculator->execute('concat("test", "ing")')); - $this->assertEquals('testing', $calculator->execute("concat('test', 'ing')")); - } - - public function testQuotes() : void - { - $calculator = new MathExecutor(); - $testString = 'some, long. arg; with: different-separators!'; - $calculator->addFunction( - 'test', - function($arg) use ($testString) { - $this->assertEquals($testString, $arg); - - return 0; - } - ); - $calculator->execute('test("' . $testString . '")'); // single quotes - $calculator->execute("test('" . $testString . "')"); // double quotes - } - - public function testBeginWithBracketAndMinus() : void - { - $calculator = new MathExecutor(); - $this->assertEquals(-4, $calculator->execute('(-4)')); - $this->assertEquals(1, $calculator->execute('(-4 + 5)')); - } - - public function testStringComparison() : void - { - $calculator = new MathExecutor(); - $this->assertEquals(true, $calculator->execute('"a" == \'a\'')); - $this->assertEquals(true, $calculator->execute('"hello world" == "hello world"')); - $this->assertEquals(false, $calculator->execute('"hello world" == "hola mundo"')); - $this->assertEquals(true, $calculator->execute('"hello world" != "hola mundo"')); - $this->assertEquals(true, $calculator->execute('"a" < "b"')); - $this->assertEquals(false, $calculator->execute('"a" > "b"')); - $this->assertEquals(true, $calculator->execute('"a" <= "b"')); - $this->assertEquals(false, $calculator->execute('"a" >= "b"')); - $this->assertEquals(true, $calculator->execute('"A" != "a"')); - } - - public function testVarStringComparison() : void - { - $calculator = new MathExecutor(); - $calculator->setVar('var', 97); - $this->assertEquals(false, $calculator->execute('97 == "a"')); - $this->assertEquals(false, $calculator->execute('$var == "a"')); - $calculator->setVar('var', 'a'); - $this->assertEquals(true, $calculator->execute('$var == "a"')); - } - - public function testOnVarNotFound() : void - { - $calculator = new MathExecutor(); - $calculator->setVarNotFoundHandler( - static function($varName) { - if ('undefined' == $varName) { - return 3; - } - } - ); - $this->assertEquals(15, $calculator->execute('5 * undefined')); - $this->assertEquals(3, $calculator->getVar('undefined')); - $this->assertNull($calculator->getVar('Lucy')); - } - - public function testGetVarException() : void - { - $calculator = new MathExecutor(); - $this->expectException(UnknownVariableException::class); - $this->assertNull($calculator->getVar('Lucy')); - } - - public function testMinusZero() : void - { - $calculator = new MathExecutor(); - $this->assertEquals(1, $calculator->execute('1 - 0')); - $this->assertEquals(1, $calculator->execute('1-0')); - } - - public function testScientificNotation() : void - { - $calculator = new MathExecutor(); - $this->assertEquals(1.5e9, $calculator->execute('1.5e9')); - $this->assertEquals(1.5e-9, $calculator->execute('1.5e-9')); - $this->assertEquals(1.5e+9, $calculator->execute('1.5e+9')); - } - - public function testNullReturnType() : void - { - $calculator = new MathExecutor(); - $calculator->setVar('nullValue', null); - $this->assertEquals(null, $calculator->execute('nullValue')); - } - - public function testGetFunctionsReturnsArray() : void - { - $calculator = new MathExecutor(); - $this->assertIsArray($calculator->getFunctions()); - } - - public function testGetFunctionsReturnsFunctions() : void - { - $calculator = new MathExecutor(); - $this->assertGreaterThan(40, \count($calculator->getFunctions())); - } - - public function testGetVarsReturnsArray() : void - { - $calculator = new MathExecutor(); - $this->assertIsArray($calculator->getVars()); - } - - public function testGetVarsReturnsCount() : void - { - $calculator = new MathExecutor(); - $this->assertGreaterThan(1, \count($calculator->getVars())); - } - - public function testUndefinedVarThrowsExecption() : void - { - $calculator = new MathExecutor(); - $this->assertGreaterThan(1, \count($calculator->getVars())); - $this->expectException(UnknownVariableException::class); - $calculator->execute('5 * undefined'); - } - - public function testSetVarsAcceptsAllScalars() : void - { - $calculator = new MathExecutor(); - $calculator->setVar('boolTrue', true); - $calculator->setVar('boolFalse', false); - $calculator->setVar('int', 1); - $calculator->setVar('null', null); - $calculator->setVar('float', 1.1); - $calculator->setVar('string', 'string'); - $this->assertCount(8, $calculator->getVars()); - $this->assertEquals(true, $calculator->getVar('boolTrue')); - $this->assertEquals(false, $calculator->getVar('boolFalse')); - $this->assertEquals(1, $calculator->getVar('int')); - $this->assertEquals(null, $calculator->getVar('null')); - $this->assertEquals(1.1, $calculator->getVar('float')); - $this->assertEquals('string', $calculator->getVar('string')); - - $this->expectException(MathExecutorException::class); - $calculator->setVar('validVar', new \DateTime()); - } - - public function testSetVarsDoesNotAcceptObject() : void - { - $calculator = new MathExecutor(); - $this->expectException(MathExecutorException::class); - $calculator->setVar('object', $this); - } - - public function testSetVarsDoesNotAcceptResource() : void - { - $calculator = new MathExecutor(); - $this->expectException(MathExecutorException::class); - $calculator->setVar('resource', \tmpfile()); - } - - public function testSetCustomVarValidator() : void - { - $calculator = new MathExecutor(); - $calculator->setVarValidationHandler(static function(string $name, $variable) : void { - // allow all scalars and null - if (\is_scalar($variable) || null === $variable) { - return; - } - // Allow variables of type DateTime, but not others - if (! $variable instanceof \DateTime) { - throw new MathExecutorException('Invalid variable type'); - } - }); - - $calculator->setVar('validFloat', 0.0); - $calculator->setVar('validInt', 0); - $calculator->setVar('validTrue', true); - $calculator->setVar('validFalse', false); - $calculator->setVar('validString', 'string'); - $calculator->setVar('validNull', null); - $calculator->setVar('validDateTime', new \DateTime()); - - $this->expectException(MathExecutorException::class); - $calculator->setVar('validVar', $this); - } - - public function testSetCustomVarNameValidator() : void - { - $calculator = new MathExecutor(); - $calculator->setVarValidationHandler(static function(string $name, $variable) : void { - // don't allow variable names with the word invalid in them - if (\str_contains($name, 'invalid')) { - throw new MathExecutorException('Invalid variable name'); - } - }); - - $calculator->setVar('validFloat', 0.0); - $calculator->setVar('validInt', 0); - $calculator->setVar('validTrue', true); - $calculator->setVar('validFalse', false); - $calculator->setVar('validString', 'string'); - $calculator->setVar('validNull', null); - $calculator->setVar('validDateTime', new \DateTime()); - - $this->expectException(MathExecutorException::class); - $calculator->setVar('invalidVar', 12); - } - - public function testVarExists() : void - { - $calculator = new MathExecutor(); - $varName = 'Eythel'; - $calculator->setVar($varName, 1); - $this->assertTrue($calculator->varExists($varName)); - $this->assertFalse($calculator->varExists('Lucy')); - } - - /** - * @dataProvider providerExpressionValues - */ - public function testCalculatingValues($expression, $value) : void - { - $calculator = new MathExecutor(); - - try { - $result = $calculator->execute($expression); - } catch (Exception $e) { - $this->fail(\sprintf('Exception: %s (%s:%d), expression was: %s', \get_class($e), $e->getFile(), $e->getLine(), $expression)); - } - $this->assertEquals($value, $result, "{$expression} did not evaluate to {$value}"); - } - - /** - * Expressions data provider - * - * Most tests can go in here. The idea is that each expression will be evaluated by MathExecutor and by PHP directly. - * The results should be the same. If they are not, then the test fails. No need to add extra test unless you are doing - * something more complex and not a simple mathmatical expression. - */ - public function providerExpressionValues() - { - return [ - ['arccos(0.5)', \acos(0.5)], - ['arccosec(4)', \asin(1 / 4)], - ['arccot(3)', M_PI / 2 - \atan(3)], - ['arccotan(4)', M_PI / 2 - \atan(4)], - ['arccsc(4)', \asin(1 / 4)], - ['arcctg(3)', M_PI / 2 - \atan(3)], - ['arcsec(4)', \acos(1 / 4)], - ['arcsin(0.5)', \asin(0.5)], - ['arctan(0.5)', \atan(0.5)], - ['arctan(4)', \atan(4)], - ['arctg(0.5)', \atan(0.5)], - ['cosec(12)', 1 / \sin(12)], - ['cosec(4)', 1 / \sin(4)], - ['cosh(12)', \cosh(12)], - ['cot(12)', \cos(12) / \sin(12)], - ['cotan(12)', \cos(12) / \sin(12)], - ['cotan(4)', \cos(4) / \sin(4)], - ['cotg(3)', \cos(3) / \sin(3)], - ['csc(4)', 1 / \sin(4)], - ['ctg(4)', \cos(4) / \sin(4)], - ['ctn(4)', \cos(4) / \sin(4)], - ['decbin(10)', \decbin(10)], - ['lg(2)', \log10(2)], - ['ln(2)', \log(2)], - ['sec(4)', 1 / \cos(4)], - ['tg(4)', \tan(4)], - ]; - } - - public function testCache() : void - { - $calculator = new MathExecutor(); - $this->assertEquals(256, $calculator->execute('2 ^ 8')); // second arg $cache is true by default - - $this->assertIsArray($calculator->getCache()); - $this->assertCount(1, $calculator->getCache()); - - $this->assertEquals(512, $calculator->execute('2 ^ 9', true)); - $this->assertCount(2, $calculator->getCache()); - - $this->assertEquals(1024, $calculator->execute('2 ^ 10', false)); - $this->assertCount(2, $calculator->getCache()); - - $calculator->clearCache(); - $this->assertIsArray($calculator->getCache()); - $this->assertCount(0, $calculator->getCache()); - - $this->assertEquals(2048, $calculator->execute('2 ^ 11', false)); - $this->assertCount(0, $calculator->getCache()); - } - - public function testUnsupportedOperands() : void - { - if (\version_compare(PHP_VERSION, '8') >= 0) { - $calculator = new MathExecutor(); - - $calculator->setVar('stringVar', 'string'); - $calculator->setVar('intVar', 1); - - $this->expectException(\TypeError::class); - $calculator->execute('stringVar + intVar'); - } else { - $this->expectNotToPerformAssertions(); - } - } -} diff --git a/vendor/nxp/math-executor/tests/bootstrap.php b/vendor/nxp/math-executor/tests/bootstrap.php deleted file mode 100644 index 85cee64..0000000 --- a/vendor/nxp/math-executor/tests/bootstrap.php +++ /dev/null @@ -1,11 +0,0 @@ - Date: Sun, 17 May 2026 22:26:31 +0300 Subject: [PATCH 02/10] Installed PHPunit and added a lot of unit tests. Made a lot of workflows for development and releases. Fixed versions on a lot of files (@since tag). Made a ton of lint fixes on `csv-import` file. --- .editorconfig | 14 + .github/workflows/gh-release.yml | 55 + .github/workflows/lint.yml | 31 + .github/workflows/phpcs.yml | 34 + .github/workflows/phpunit.yml | 34 + .github/workflows/wp-release.yml | 54 + .gitignore | 1 + .wp-env.json | 2 +- CITATION.cff | 2 +- build/.gitkeep | 0 composer.json | 26 +- composer.lock | 2358 ++++++++++++++++++- cooked.php | 59 +- includes/class.cooked-csv-import.php | 1150 +++++---- includes/class.cooked-elementor.php | 4 +- includes/class.cooked-gutenberg.php | 4 +- includes/class.cooked-import.php | 4 +- includes/class.cooked-migration.php | 4 +- includes/class.cooked-multilingual.php | 4 +- includes/class.cooked-plugin-extra.php | 4 +- includes/class.cooked-rankmathseo.php | 4 +- includes/class.cooked-yoastseo.php | 4 +- includes/widgets/init.php | 7 + includes/widgets/nutrition.php | 15 + includes/widgets/recipe-card.php | 15 + includes/widgets/recipe-categories.php | 15 + includes/widgets/recipe-list.php | 15 + includes/widgets/search.php | 15 + package.json | 5 +- phpcs.xml | 43 + phpunit.xml | 15 + tests/phpunit/CSVImportTest.php | 73 + tests/phpunit/EnqueuesTest.php | 48 + tests/phpunit/FunctionsExtraTest.php | 43 + tests/phpunit/FunctionsTest.php | 113 + tests/phpunit/MeasurementsRemainingTest.php | 70 + tests/phpunit/MeasurementsTest.php | 340 +++ tests/phpunit/MultilingualTest.php | 32 + tests/phpunit/RecipeMetaTest.php | 48 + tests/phpunit/RecipesTest.php | 64 + tests/phpunit/RelatedRecipesTest.php | 35 + tests/phpunit/SEOTest.php | 88 + tests/phpunit/SettingsTest.php | 58 + tests/phpunit/UpdatesTest.php | 34 + tests/phpunit/UsersTest.php | 40 + tests/phpunit/bootstrap.php | 296 +++ 46 files changed, 4785 insertions(+), 594 deletions(-) create mode 100644 .editorconfig create mode 100644 .github/workflows/gh-release.yml create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/phpcs.yml create mode 100644 .github/workflows/phpunit.yml create mode 100644 .github/workflows/wp-release.yml delete mode 100644 build/.gitkeep create mode 100644 phpcs.xml create mode 100644 phpunit.xml create mode 100644 tests/phpunit/CSVImportTest.php create mode 100644 tests/phpunit/EnqueuesTest.php create mode 100644 tests/phpunit/FunctionsExtraTest.php create mode 100644 tests/phpunit/FunctionsTest.php create mode 100644 tests/phpunit/MeasurementsRemainingTest.php create mode 100644 tests/phpunit/MeasurementsTest.php create mode 100644 tests/phpunit/MultilingualTest.php create mode 100644 tests/phpunit/RecipeMetaTest.php create mode 100644 tests/phpunit/RecipesTest.php create mode 100644 tests/phpunit/RelatedRecipesTest.php create mode 100644 tests/phpunit/SEOTest.php create mode 100644 tests/phpunit/SettingsTest.php create mode 100644 tests/phpunit/UpdatesTest.php create mode 100644 tests/phpunit/UsersTest.php create mode 100644 tests/phpunit/bootstrap.php diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5d2c960 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# .editorconfig +root = true + +[*.php] +indent_style = tab +indent_size = 4 +tab_width = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false \ No newline at end of file diff --git a/.github/workflows/gh-release.yml b/.github/workflows/gh-release.yml new file mode 100644 index 0000000..8ea7b21 --- /dev/null +++ b/.github/workflows/gh-release.yml @@ -0,0 +1,55 @@ +name: "GitHub Release" +on: + # push: + # tags: + # - "*" + workflow_dispatch: +jobs: + release: + name: "Release" + runs-on: ubuntu-latest + steps: + + - name: Checkout code + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Verify tag is on main branch + run: | + # Fetch the latest main branch from origin + git fetch origin main + + # Check if the current commit (${{ github.sha }}) is part of the origin/main history + if git merge-base --is-ancestor ${{ github.sha }} origin/main; then + echo "Success: Tag is on the main branch." + else + echo "Error: Tag was not pushed to the main branch. Skipping release." + exit 1 + fi + + - name: Set up Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Build the project + run: bun install && bun run build + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + tools: composer + coverage: none + + - name: Install production Composer dependencies + run: composer install --no-dev --optimize-autoloader --no-interaction --prefer-dist --no-progress + + - name: Create plugin zip + run: bunx bestzip build/cooked.zip cooked.php LICENSE readme.txt wpml-config.xml assets/ includes/ languages/ templates/ vendor/ + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + files: build/cooked.zip \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..c106d08 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,31 @@ +name: PHP Lint + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main, develop ] + workflow_dispatch: + +jobs: + lint: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: [8.5, 8.4, 8.3, 8.2] + + name: PHP ${{ matrix.php }} + + steps: + - name: Check out code + uses: actions/checkout@v6 + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + tools: composer + + - name: Lint PHP + run: php -l includes/ templates/ tests/ diff --git a/.github/workflows/phpcs.yml b/.github/workflows/phpcs.yml new file mode 100644 index 0000000..d770f4a --- /dev/null +++ b/.github/workflows/phpcs.yml @@ -0,0 +1,34 @@ +name: PHPCS + +on: + # push: + # branches: [ main, develop ] + # pull_request: + # branches: [ main, develop ] + workflow_dispatch: + +jobs: + phpcs: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: [8.5, 8.4, 8.3, 8.2] + + name: PHP ${{ matrix.php }} + + steps: + - name: Check out code + uses: actions/checkout@v6 + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + tools: composer + + - name: Install dependencies + run: composer install --no-interaction --no-progress + + - name: Run PHPCS + run: vendor/bin/phpcs --standard=phpcs.xml . diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml new file mode 100644 index 0000000..346ff7e --- /dev/null +++ b/.github/workflows/phpunit.yml @@ -0,0 +1,34 @@ +name: PHPUnit Tests + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main, develop ] + workflow_dispatch: + +jobs: + phpunit: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: [8.5, 8.4, 8.3, 8.2] + + name: PHP ${{ matrix.php }} + + steps: + - name: Check out code + uses: actions/checkout@v6 + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + tools: composer + + - name: Install dependencies + run: composer install --no-interaction --no-progress + + - name: Run PHPUnit + run: ./vendor/bin/phpunit diff --git a/.github/workflows/wp-release.yml b/.github/workflows/wp-release.yml new file mode 100644 index 0000000..ae3594d --- /dev/null +++ b/.github/workflows/wp-release.yml @@ -0,0 +1,54 @@ +name: "Wordpress.org Release" +on: + # push: + # tags: + # - "*" + workflow_dispatch: +jobs: + tag: + name: "build" + runs-on: ubuntu-latest + steps: + + - name: Checkout code + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Verify tag is on main branch + run: | + git fetch origin main + if git merge-base --is-ancestor ${{ github.sha }} origin/main; then + echo "Success: Tag is on the main branch." + else + echo "Error: Tag was not pushed to the main branch. Skipping release." + exit 1 + fi + + - name: Set up Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Build the project + run: bun install && bun run build + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + tools: composer + coverage: none + + - name: Install production Composer dependencies + run: composer install --no-dev --optimize-autoloader --no-interaction --prefer-dist --no-progress + + - name: Install SVN + run: sudo apt-get update && sudo apt-get install -y subversion + + - name: WordPress Plugin Deploy + uses: 10up/action-wordpress-plugin-deploy@stable + env: + SVN_USERNAME: ${{ secrets.SVN_USERNAME }} + SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} + SLUG: "cooked" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 61f6abf..a73988e 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ tests/playwright-report/ tests/blob-report/ tests/playwright/.cache/ tests/.auth/ +tests/phpunit/.cache # Build build/* diff --git a/.wp-env.json b/.wp-env.json index 6722618..e646bc1 100644 --- a/.wp-env.json +++ b/.wp-env.json @@ -1,6 +1,6 @@ { "core": null, - "phpVersion": "7.4", + "phpVersion": "8.2", "themes": ["WordPress/twentytwentyfive"], "plugins": ["."], "port": 8888, diff --git a/CITATION.cff b/CITATION.cff index 2310618..e32ba4d 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,5 +1,5 @@ cff-version: 1.2.0 -message: "If you use cooked, please cite it using the following metadata" +message: "If you use Cooked, please cite it using the following metadata" title: cooked authors: - family-names: Scheetz diff --git a/build/.gitkeep b/build/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/composer.json b/composer.json index eee68ff..656fa15 100644 --- a/composer.json +++ b/composer.json @@ -13,13 +13,8 @@ "homepage": "https://wordpress.org/plugins/cooked/", "version": "1.14.0", "type": "wordpress-plugin", - "license": "GPL-3.0-or-later", - "prefer-stable": true, - "minimum-stability": "dev", - "config": { - "optimize-autoloader": true - }, - "authors": [ + "license": "GPL-2.0-or-later", + "authors": [ { "name": "Gora Tech", "email": "contact@goratech.dev", @@ -33,12 +28,25 @@ "source": "https://github.com/XjSv/Cooked", "security": "https://github.com/XjSv/Cooked?tab=security-ov-file" }, - "optimize-autoloader": true, + "minimum-stability": "dev", + "prefer-stable": true, "require": { "php": ">=7.4.0", "nxp/math-executor": "^2.3" }, "require-dev": { - "php": "^7 || ^8" + "phpunit/phpunit": "^12.5", + "squizlabs/php_codesniffer": "^3.13", + "wp-coding-standards/wpcs": "^3.3", + "phpcompatibility/php-compatibility": "^10.0@alpha", + "phpcompatibility/phpcompatibility-wp": "^3.0@alpha" + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + }, + "platform": { + "php": "7.4" + } } } diff --git a/composer.lock b/composer.lock index dd13b69..2a3dfd4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,28 +4,29 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "93dff3879d013694a97a2b65c557b9d8", + "content-hash": "74f1b41ec5e7831d7cc92e8eecec51fb", "packages": [ { "name": "nxp/math-executor", - "version": "v2.3.2", + "version": "v2.3.8", "source": { "type": "git", "url": "https://github.com/neonxp/MathExecutor.git", - "reference": "c59f4cd15317754d2b50bd4bff2243012e815790" + "reference": "235deeb110839ff643d0e0804c4d362462b13550" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/neonxp/MathExecutor/zipball/c59f4cd15317754d2b50bd4bff2243012e815790", - "reference": "c59f4cd15317754d2b50bd4bff2243012e815790", + "url": "https://api.github.com/repos/neonxp/MathExecutor/zipball/235deeb110839ff643d0e0804c4d362462b13550", + "reference": "235deeb110839ff643d0e0804c4d362462b13550", "shasum": "" }, "require": { - "php": ">=7.4" + "php": ">=8.0 <8.6" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.8", - "phpunit/phpunit": ">=9.0" + "friendsofphp/php-cs-fixer": "*", + "phpstan/phpstan": "*", + "phpunit/phpunit": ">=10.0" }, "type": "library", "autoload": { @@ -59,22 +60,2335 @@ ], "support": { "issues": "https://github.com/neonxp/MathExecutor/issues", - "source": "https://github.com/neonxp/MathExecutor/tree/v2.3.2" + "source": "https://github.com/neonxp/MathExecutor/tree/v2.3.8" }, - "time": "2022-12-08T16:15:34+00:00" + "time": "2025-11-07T15:11:54+00:00" } ], - "packages-dev": [], - "aliases": [], - "minimum-stability": "dev", - "stability-flags": {}, - "prefer-stable": true, - "prefer-lowest": false, - "platform": { - "php": ">=7.4.0" - }, - "platform-dev": { - "php": "^7 || ^8" + "packages-dev": [ + { + "name": "dealerdirect/phpcodesniffer-composer-installer", + "version": "v1.2.1", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "963f0c67bffde0eac41b56be71ac0e8ba132f0bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/963f0c67bffde0eac41b56be71ac0e8ba132f0bd", + "reference": "963f0c67bffde0eac41b56be71ac0e8ba132f0bd", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.2", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^3.1.0 || ^4.0" + }, + "require-dev": { + "composer/composer": "^2.2", + "ext-json": "*", + "ext-zip": "*", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpcompatibility/php-compatibility": "^9.0 || ^10.0.0@dev", + "yoast/phpunit-polyfills": "^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Franck Nijhof", + "email": "opensource@frenck.dev", + "homepage": "https://frenck.dev", + "role": "Open source developer" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer Standards Composer Installer Plugin", + "keywords": [ + "PHPCodeSniffer", + "PHP_CodeSniffer", + "code quality", + "codesniffer", + "composer", + "installer", + "phpcbf", + "phpcs", + "plugin", + "qa", + "quality", + "standard", + "standards", + "style guide", + "stylecheck", + "tests" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "security": "https://github.com/PHPCSStandards/composer-installer/security/policy", + "source": "https://github.com/PHPCSStandards/composer-installer" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2026-05-06T08:26:05+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.4", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-08-01T08:46:24+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.7.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" + }, + "time": "2025-12-06T11:56:16+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpcompatibility/php-compatibility", + "version": "10.0.0-alpha2", + "source": { + "type": "git", + "url": "https://github.com/PHPCompatibility/PHPCompatibility.git", + "reference": "e0f0e5a3dc819a4a0f8d679a0f2453d941976e18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/e0f0e5a3dc819a4a0f8d679a0f2453d941976e18", + "reference": "e0f0e5a3dc819a4a0f8d679a0f2453d941976e18", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "phpcsstandards/phpcsutils": "^1.1.2", + "squizlabs/php_codesniffer": "^3.13.3 || ^4.0" + }, + "replace": { + "wimg/php-compatibility": "*" + }, + "require-dev": { + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpcsstandards/phpcsdevcs": "^1.2.0", + "phpcsstandards/phpcsdevtools": "^1.2.3", + "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4 || ^10.5.32 || ^11.3.3", + "yoast/phpunit-polyfills": "^1.1.5 || ^2.0.5 || ^3.1.0" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-master": "9.x-dev", + "dev-develop": "10.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Wim Godden", + "homepage": "https://github.com/wimg", + "role": "lead" + }, + { + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl", + "role": "lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" + } + ], + "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", + "homepage": "https://techblog.wimgodden.be/tag/codesniffer/", + "keywords": [ + "compatibility", + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCompatibility/PHPCompatibility/issues", + "security": "https://github.com/PHPCompatibility/PHPCompatibility/security/policy", + "source": "https://github.com/PHPCompatibility/PHPCompatibility" + }, + "funding": [ + { + "url": "https://github.com/PHPCompatibility", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcompatibility", + "type": "thanks_dev" + } + ], + "time": "2025-11-28T11:36:33+00:00" + }, + { + "name": "phpcompatibility/phpcompatibility-paragonie", + "version": "2.0.0-alpha2", + "source": { + "type": "git", + "url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git", + "reference": "7a979711c87d8202b52f56c56bd719d09d8ed7f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/7a979711c87d8202b52f56c56bd719d09d8ed7f5", + "reference": "7a979711c87d8202b52f56c56bd719d09d8ed7f5", + "shasum": "" + }, + "require": { + "phpcompatibility/php-compatibility": "^10.0@dev" + }, + "require-dev": { + "paragonie/random_compat": "dev-master", + "paragonie/sodium_compat": "dev-master" + }, + "type": "phpcodesniffer-standard", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Wim Godden", + "role": "lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "lead" + } + ], + "description": "A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by the Paragonie polyfill libraries.", + "homepage": "http://phpcompatibility.com/", + "keywords": [ + "compatibility", + "paragonie", + "phpcs", + "polyfill", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie/issues", + "security": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie/security/policy", + "source": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie" + }, + "funding": [ + { + "url": "https://github.com/PHPCompatibility", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcompatibility", + "type": "thanks_dev" + } + ], + "time": "2025-11-29T13:09:49+00:00" + }, + { + "name": "phpcompatibility/phpcompatibility-wp", + "version": "3.0.0-alpha2", + "source": { + "type": "git", + "url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git", + "reference": "bd53f24e7528422ac51d64dc8d53e8d4c4a877b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/bd53f24e7528422ac51d64dc8d53e8d4c4a877b3", + "reference": "bd53f24e7528422ac51d64dc8d53e8d4c4a877b3", + "shasum": "" + }, + "require": { + "phpcompatibility/php-compatibility": "^10.0@dev", + "phpcompatibility/phpcompatibility-paragonie": "^2.0@dev" + }, + "type": "phpcodesniffer-standard", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Wim Godden", + "role": "lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "lead" + } + ], + "description": "A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.", + "homepage": "http://phpcompatibility.com/", + "keywords": [ + "compatibility", + "phpcs", + "standards", + "static analysis", + "wordpress" + ], + "support": { + "issues": "https://github.com/PHPCompatibility/PHPCompatibilityWP/issues", + "security": "https://github.com/PHPCompatibility/PHPCompatibilityWP/security/policy", + "source": "https://github.com/PHPCompatibility/PHPCompatibilityWP" + }, + "funding": [ + { + "url": "https://github.com/PHPCompatibility", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcompatibility", + "type": "thanks_dev" + } + ], + "time": "2025-12-16T13:35:20+00:00" + }, + { + "name": "phpcsstandards/phpcsextra", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHPCSExtra.git", + "reference": "b598aa890815b8df16363271b659d73280129101" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/b598aa890815b8df16363271b659d73280129101", + "reference": "b598aa890815b8df16363271b659d73280129101", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "phpcsstandards/phpcsutils": "^1.2.0", + "squizlabs/php_codesniffer": "^3.13.5 || ^4.0.1" + }, + "require-dev": { + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpcsstandards/phpcsdevcs": "^1.2.0", + "phpcsstandards/phpcsdevtools": "^1.2.1", + "phpunit/phpunit": "^4.5 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-stable": "1.x-dev", + "dev-develop": "1.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl", + "role": "lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHPCSExtra/graphs/contributors" + } + ], + "description": "A collection of sniffs and standards for use with PHP_CodeSniffer.", + "keywords": [ + "PHP_CodeSniffer", + "phpcbf", + "phpcodesniffer-standard", + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHPCSExtra/issues", + "security": "https://github.com/PHPCSStandards/PHPCSExtra/security/policy", + "source": "https://github.com/PHPCSStandards/PHPCSExtra" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-11-12T23:06:57+00:00" + }, + { + "name": "phpcsstandards/phpcsutils", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHPCSUtils.git", + "reference": "c216317e96c8b3f5932808f9b0f1f7a14e3bbf55" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/c216317e96c8b3f5932808f9b0f1f7a14e3bbf55", + "reference": "c216317e96c8b3f5932808f9b0f1f7a14e3bbf55", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7 || ^1.0", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^3.13.5 || ^4.0.1" + }, + "require-dev": { + "ext-filter": "*", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpcsstandards/phpcsdevcs": "^1.2.0", + "yoast/phpunit-polyfills": "^1.1.0 || ^2.0.0 || ^3.0.0" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-stable": "1.x-dev", + "dev-develop": "1.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHPCSUtils/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl", + "role": "lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHPCSUtils/graphs/contributors" + } + ], + "description": "A suite of utility functions for use with PHP_CodeSniffer", + "homepage": "https://phpcsutils.com/", + "keywords": [ + "PHP_CodeSniffer", + "phpcbf", + "phpcodesniffer-standard", + "phpcs", + "phpcs3", + "phpcs4", + "standards", + "static analysis", + "tokens", + "utility" + ], + "support": { + "docs": "https://phpcsutils.com/", + "issues": "https://github.com/PHPCSStandards/PHPCSUtils/issues", + "security": "https://github.com/PHPCSStandards/PHPCSUtils/security/policy", + "source": "https://github.com/PHPCSStandards/PHPCSUtils" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-12-08T14:27:58+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "12.5.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "876099a072646c7745f673d7aeab5382c4439691" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/876099a072646c7745f673d7aeab5382c4439691", + "reference": "876099a072646c7745f673d7aeab5382c4439691", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.7.0", + "php": ">=8.3", + "phpunit/php-text-template": "^5.0", + "sebastian/complexity": "^5.0", + "sebastian/environment": "^8.0.3", + "sebastian/lines-of-code": "^4.0", + "sebastian/version": "^6.0", + "theseer/tokenizer": "^2.0.1" + }, + "require-dev": { + "phpunit/phpunit": "^12.5.1" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "12.5.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.5.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "type": "tidelift" + } + ], + "time": "2026-04-15T08:23:17+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "6.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5", + "reference": "3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator", + "type": "tidelift" + } + ], + "time": "2026-02-02T14:04:18+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406", + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^12.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:58:58+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53", + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:59:16+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "8.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/8.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:59:38+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "12.5.25", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "792c2980442dfce319226b88fa845b8b6de3b333" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/792c2980442dfce319226b88fa845b8b6de3b333", + "reference": "792c2980442dfce319226b88fa845b8b6de3b333", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.4", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.3", + "phpunit/php-code-coverage": "^12.5.6", + "phpunit/php-file-iterator": "^6.0.1", + "phpunit/php-invoker": "^6.0.0", + "phpunit/php-text-template": "^5.0.0", + "phpunit/php-timer": "^8.0.0", + "sebastian/cli-parser": "^4.2.0", + "sebastian/comparator": "^7.1.6", + "sebastian/diff": "^7.0.0", + "sebastian/environment": "^8.1.0", + "sebastian/exporter": "^7.0.2", + "sebastian/global-state": "^8.0.2", + "sebastian/object-enumerator": "^7.0.0", + "sebastian/recursion-context": "^7.0.1", + "sebastian/type": "^6.0.3", + "sebastian/version": "^6.0.0", + "staabm/side-effects-detector": "^1.0.5" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "12.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.25" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsoring.html", + "type": "other" + } + ], + "time": "2026-05-13T03:56:57+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "4.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "7d05781b13f7dec9043a629a21d086ed74582a15" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/7d05781b13f7dec9043a629a21d086ed74582a15", + "reference": "7d05781b13f7dec9043a629a21d086ed74582a15", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.5.25" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/4.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/cli-parser", + "type": "tidelift" + } + ], + "time": "2026-05-17T05:29:34+00:00" + }, + { + "name": "sebastian/comparator", + "version": "7.1.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "c769009dee98f494e0edc3fd4f4087501688f11e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/c769009dee98f494e0edc3fd4f4087501688f11e", + "reference": "c769009dee98f494e0edc3fd4f4087501688f11e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.3", + "sebastian/diff": "^7.0", + "sebastian/exporter": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^12.2" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/7.1.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" + } + ], + "time": "2026-04-14T08:23:15+00:00" + }, + { + "name": "sebastian/complexity", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb", + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:55:25+00:00" + }, + { + "name": "sebastian/diff", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "7ab1ea946c012266ca32390913653d844ecd085f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f", + "reference": "7ab1ea946c012266ca32390913653d844ecd085f", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0", + "symfony/process": "^7.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:55:46+00:00" + }, + { + "name": "sebastian/environment", + "version": "8.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "b121608b28a13f721e76ffbbd386d08eff58f3f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/b121608b28a13f721e76ffbbd386d08eff58f3f6", + "reference": "b121608b28a13f721e76ffbbd386d08eff58f3f6", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/8.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" + } + ], + "time": "2026-04-15T12:13:01+00:00" + }, + { + "name": "sebastian/exporter", + "version": "7.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "016951ae10980765e4e7aee491eb288c64e505b7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/016951ae10980765e4e7aee491eb288c64e505b7", + "reference": "016951ae10980765e4e7aee491eb288c64e505b7", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.3", + "sebastian/recursion-context": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/7.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" + } + ], + "time": "2025-09-24T06:16:11+00:00" + }, + { + "name": "sebastian/global-state", + "version": "8.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "ef1377171613d09edd25b7816f05be8313f9115d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/ef1377171613d09edd25b7816f05be8313f9115d", + "reference": "ef1377171613d09edd25b7816f05be8313f9115d", + "shasum": "" + }, + "require": { + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/8.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", + "type": "tidelift" + } + ], + "time": "2025-08-29T11:29:25+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/97ffee3bcfb5805568d6af7f0f893678fc076d2f", + "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:57:28+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894", + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894", + "shasum": "" + }, + "require": { + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:57:48+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "4bfa827c969c98be1e527abd576533293c634f6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a", + "reference": "4bfa827c969c98be1e527abd576533293c634f6a", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:58:17+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/0b01998a7d5b1f122911a66bebcb8d46f0c82d8c", + "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/7.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" + } + ], + "time": "2025-08-13T04:44:59+00:00" + }, + { + "name": "sebastian/type", + "version": "6.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "e549163b9760b8f71f191651d22acf32d56d6d4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/e549163b9760b8f71f191651d22acf32d56d6d4d", + "reference": "e549163b9760b8f71f191651d22acf32d56d6d4d", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/6.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/type", + "type": "tidelift" + } + ], + "time": "2025-08-09T06:57:12+00:00" + }, + { + "name": "sebastian/version", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c", + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T05:00:38+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.13.5", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0ca86845ce43291e8f5692c7356fccf3bcf02bf4", + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + }, + "bin": [ + "bin/phpcbf", + "bin/phpcs" + ], + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-11-04T16:30:35+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/7989e43bf381af0eac72e4f0ca5bcbfa81658be4", + "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^8.1" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/2.0.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2025-12-08T11:19:18+00:00" + }, + { + "name": "wp-coding-standards/wpcs", + "version": "3.3.0", + "source": { + "type": "git", + "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", + "reference": "7795ec6fa05663d716a549d0b44e47ffc8b0d4a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7795ec6fa05663d716a549d0b44e47ffc8b0d4a6", + "reference": "7795ec6fa05663d716a549d0b44e47ffc8b0d4a6", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "ext-libxml": "*", + "ext-tokenizer": "*", + "ext-xmlreader": "*", + "php": ">=7.2", + "phpcsstandards/phpcsextra": "^1.5.0", + "phpcsstandards/phpcsutils": "^1.1.0", + "squizlabs/php_codesniffer": "^3.13.4" + }, + "require-dev": { + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpcompatibility/php-compatibility": "^10.0.0@dev", + "phpcsstandards/phpcsdevtools": "^1.2.0", + "phpunit/phpunit": "^8.0 || ^9.0" + }, + "suggest": { + "ext-iconv": "For improved results", + "ext-mbstring": "For improved results" + }, + "type": "phpcodesniffer-standard", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Contributors", + "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions", + "keywords": [ + "phpcs", + "standards", + "static analysis", + "wordpress" + ], + "support": { + "issues": "https://github.com/WordPress/WordPress-Coding-Standards/issues", + "source": "https://github.com/WordPress/WordPress-Coding-Standards", + "wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki" + }, + "funding": [ + { + "url": "https://opencollective.com/php_codesniffer", + "type": "custom" + } + ], + "time": "2025-11-25T12:08:04+00:00" + } + ], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "php": ">=7.4.0" }, - "plugin-api-version": "2.9.0" + "platform-dev": [], + "plugin-api-version": "2.6.0" } diff --git a/cooked.php b/cooked.php index 230b73b..e81ee76 100644 --- a/cooked.php +++ b/cooked.php @@ -1,32 +1,41 @@ 0, - 'errors' => [], - 'total' => 0 - ]; - - if ( ! file_exists( $file_path ) ) { - $results['errors'][] = __( 'CSV file not found.', 'cooked' ); - return $results; - } - - // Open and parse CSV file - $handle = fopen( $file_path, 'r' ); - if ( $handle === false ) { - $results['errors'][] = __( 'Could not open CSV file.', 'cooked' ); - return $results; - } - - // Read header row - $headers = fgetcsv( $handle ); - if ( $headers === false || empty( $headers ) ) { - $results['errors'][] = __( 'CSV file is empty or invalid.', 'cooked' ); - fclose( $handle ); - return $results; - } - - // Normalize headers (trim and lowercase) - $headers = array_map( 'trim', $headers ); - $headers = array_map( 'strtolower', $headers ); - - // Check for required title column - if ( ! in_array( 'title', $headers ) ) { - $results['errors'][] = __( 'CSV file must contain a "title" column.', 'cooked' ); - fclose( $handle ); - return $results; - } - - $row_number = 1; - while ( ( $row = fgetcsv( $handle ) ) !== false ) { - $row_number++; - $results['total']++; - - // Skip empty rows - if ( empty( array_filter( $row ) ) ) { - continue; - } - - // Map row data to headers - $data = []; - foreach ( $headers as $index => $header ) { - $data[ $header ] = isset( $row[ $index ] ) ? trim( $row[ $index ] ) : ''; - } - - // Import this recipe - try { - $import_result = self::import_recipe( $data, $row_number ); - if ( $import_result['success'] ) { - $results['success']++; - } else { - $error_msg = isset( $import_result['error'] ) ? $import_result['error'] : __( 'Unknown error', 'cooked' ); - $results['errors'][] = sprintf( __( 'Row %d: %s', 'cooked' ), $row_number, $error_msg ); - if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { - error_log( 'Cooked CSV Import Error Row ' . $row_number . ': ' . $error_msg ); - } - } - } catch ( Exception $e ) { - $error_msg = $e->getMessage(); - $results['errors'][] = sprintf( __( 'Row %d: %s', 'cooked' ), $row_number, $error_msg ); - if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { - error_log( 'Cooked CSV Import Exception Row ' . $row_number . ': ' . $error_msg ); - error_log( 'Stack trace: ' . $e->getTraceAsString() ); - } - } - } - - fclose( $handle ); - return $results; - } - - /** - * Import a single recipe from CSV data - * - * @param array $data Recipe data from CSV row - * @param int $row_number Row number for error reporting - * @return array Result with success status and error message if any - */ - public static function import_recipe( $data, $row_number = 0 ) { - global $_cooked_settings; - - // Validate required fields - if ( empty( $data['title'] ) ) { - return [ - 'success' => false, - 'error' => __( 'Title is required', 'cooked' ) - ]; - } - - // Get default content - if ( isset( $_cooked_settings['default_content'] ) ) { - $default_content = stripslashes( $_cooked_settings['default_content'] ); - } else { - $default_content = Cooked_Recipes::default_content(); - } - - // Create new recipe post - $new_recipe = [ - 'post_type' => 'cp_recipe', - 'post_status' => 'draft', - 'post_title' => sanitize_text_field( $data['title'] ), - 'post_content' => '', - 'post_author' => get_current_user_id(), - ]; - - $recipe_id = wp_insert_post( $new_recipe ); - if ( is_wp_error( $recipe_id ) ) { - return [ - 'success' => false, - 'error' => $recipe_id->get_error_message() - ]; - } - - // Prepare recipe meta - $recipe_meta = []; - $recipe_meta['cooked_version'] = COOKED_VERSION; - $recipe_meta['content'] = $default_content; - $recipe_meta['excerpt'] = isset( $data['excerpt'] ) ? sanitize_text_field( $data['excerpt'] ) : ''; - $recipe_meta['seo_description'] = isset( $data['seo_description'] ) ? sanitize_text_field( $data['seo_description'] ) : ( isset( $data['excerpt'] ) ? sanitize_text_field( $data['excerpt'] ) : '' ); - $recipe_meta['notes'] = isset( $data['notes'] ) ? wp_kses_post( $data['notes'] ) : ''; - - // Difficulty level - $difficulty_level = isset( $data['difficulty_level'] ) ? intval( $data['difficulty_level'] ) : 0; - if ( $difficulty_level < 1 || $difficulty_level > 3 ) { - $difficulty_level = 0; - } - $recipe_meta['difficulty_level'] = $difficulty_level; - - // Times - $recipe_meta['prep_time'] = isset( $data['prep_time'] ) ? intval( $data['prep_time'] ) : 0; - $recipe_meta['cook_time'] = isset( $data['cook_time'] ) ? intval( $data['cook_time'] ) : 0; - $recipe_meta['total_time'] = $recipe_meta['prep_time'] + $recipe_meta['cook_time']; - if ( isset( $data['total_time'] ) && ! empty( $data['total_time'] ) ) { - $recipe_meta['total_time'] = intval( $data['total_time'] ); - } - - // Parse ingredients - $recipe_meta['ingredients'] = []; - if ( ! empty( $data['ingredients'] ) ) { - $measurements = Cooked_Measurements::get(); - - // Split by | to get all parts - // Format: amount|measurement|name|amount|measurement|name||sub_amount|sub_measurement|sub_name|... - // When we see ||, it becomes two consecutive empty strings in the array - $all_parts = array_map( 'trim', explode( '|', $data['ingredients'] ) ); - $i = 0; - - while ( $i < count( $all_parts ) ) { - // Skip empty parts (they come from || separator) - if ( empty( $all_parts[ $i ] ) ) { - $i++; - continue; - } - - $part = $all_parts[ $i ]; - - // Check if it's a section heading (starts with #) - if ( strpos( $part, '#' ) === 0 ) { - $recipe_meta['ingredients'][] = [ - 'section_heading_name' => trim( $part, '#' ), - ]; - $i++; - continue; - } - - // Collect next 3 non-empty parts for an ingredient (amount|measurement|name) - $ingredient_parts = []; - $j = $i; - while ( count( $ingredient_parts ) < 3 && $j < count( $all_parts ) ) { - $p = trim( $all_parts[ $j ] ); - if ( ! empty( $p ) ) { - $ingredient_parts[] = $p; - } - $j++; - } - - if ( count( $ingredient_parts ) >= 3 ) { - $ingredient = self::parse_ingredient_parts( $ingredient_parts, $measurements ); - $i = $j; // Move past the collected parts - - // Check if next parts are empty (indicating || separator for substitution) - // Look ahead to see if we have empty parts followed by non-empty parts - $next_empty_count = 0; - $k = $i; - while ( $k < count( $all_parts ) && empty( trim( $all_parts[ $k ] ) ) ) { - $next_empty_count++; - $k++; - } - - // If we have empty parts (from ||) and then more parts, it's a substitution - if ( $next_empty_count > 0 && $k < count( $all_parts ) ) { - // Collect substitution parts (next 3 non-empty parts) - $sub_parts = []; - $sub_i = $k; - while ( count( $sub_parts ) < 3 && $sub_i < count( $all_parts ) ) { - $sub_part = trim( $all_parts[ $sub_i ] ); - if ( ! empty( $sub_part ) ) { - $sub_parts[] = $sub_part; - } - $sub_i++; - } - - // Parse substitution - if ( count( $sub_parts ) >= 3 ) { - $ingredient['sub_amount'] = sanitize_text_field( $sub_parts[0] ); - $sub_measurement = sanitize_text_field( $sub_parts[1] ); - $matched_sub_measurement = self::match_measurement( $sub_measurement, $measurements ); - if ( $matched_sub_measurement ) { - $ingredient['sub_measurement'] = $matched_sub_measurement; - } - $ingredient['sub_name'] = sanitize_text_field( $sub_parts[2] ); - } elseif ( count( $sub_parts ) == 2 ) { - $ingredient['sub_amount'] = sanitize_text_field( $sub_parts[0] ); - $ingredient['sub_name'] = sanitize_text_field( $sub_parts[1] ); - } elseif ( count( $sub_parts ) == 1 ) { - $ingredient['sub_name'] = sanitize_text_field( $sub_parts[0] ); - } - - $i = $sub_i; // Move past substitution - } - - $recipe_meta['ingredients'][] = $ingredient; - } else { - // Not enough parts for a complete ingredient, skip - $i++; - } - } - } - - // Parse directions - $recipe_meta['directions'] = []; - if ( ! empty( $data['directions'] ) ) { - $directions = explode( '|', $data['directions'] ); - foreach ( $directions as $direction_string ) { - $direction_string = trim( $direction_string ); - if ( empty( $direction_string ) ) { - continue; - } - - // Check if it's a section heading (starts with #) - if ( strpos( $direction_string, '#' ) === 0 ) { - $recipe_meta['directions'][] = [ - 'section_heading_name' => trim( $direction_string, '#' ), - ]; - continue; - } - - $recipe_meta['directions'][] = [ - 'content' => wp_kses_post( $direction_string ), - ]; - } - } - - // Nutrition data - $recipe_meta['nutrition'] = []; - if ( isset( $data['servings'] ) && ! empty( $data['servings'] ) ) { - $recipe_meta['nutrition']['servings'] = sanitize_text_field( $data['servings'] ); - } - if ( isset( $data['calories'] ) && ! empty( $data['calories'] ) ) { - $recipe_meta['nutrition']['calories'] = intval( $data['calories'] ); - } - - // Save recipe meta - $recipe_meta = Cooked_Recipe_Meta::meta_cleanup( $recipe_meta ); - update_post_meta( $recipe_id, '_recipe_settings', $recipe_meta ); - - // Update post excerpt - $recipe_excerpt = ! empty( $recipe_meta['excerpt'] ) ? $recipe_meta['excerpt'] : get_the_title( $recipe_id ); - $seo_content = apply_filters( 'cooked_seo_recipe_content', '

' . wp_kses_post( $recipe_excerpt ) . '

' . __( 'Ingredients', 'cooked' ) . '

[cooked-ingredients checkboxes=false]

' . __( 'Directions', 'cooked' ) . '

[cooked-directions numbers=false]' ); - $seo_content = do_shortcode( $seo_content ); - - $should_update_content = apply_filters( 'cooked_should_update_post_content', true, $recipe_id ); - if ( $should_update_content ) { - wp_update_post( [ - 'ID' => $recipe_id, - 'post_excerpt' => $recipe_excerpt, - 'post_content' => $seo_content - ] ); - } else { - wp_update_post( [ - 'ID' => $recipe_id, - 'post_excerpt' => $recipe_excerpt - ] ); - } - - // Handle taxonomies - if ( ! empty( $data['categories'] ) && taxonomy_exists( 'cp_recipe_category' ) ) { - $categories = array_map( 'trim', explode( ',', $data['categories'] ) ); - $category_ids = []; - foreach ( $categories as $category_name ) { - $category_name = sanitize_text_field( $category_name ); - if ( ! empty( $category_name ) ) { - $term = get_term_by( 'name', $category_name, 'cp_recipe_category' ); - if ( ! $term ) { - $term = wp_insert_term( $category_name, 'cp_recipe_category' ); - if ( ! is_wp_error( $term ) ) { - $category_ids[] = $term['term_id']; - } - } else { - $category_ids[] = $term->term_id; - } - } - } - if ( ! empty( $category_ids ) ) { - wp_set_object_terms( $recipe_id, $category_ids, 'cp_recipe_category' ); - } - } - - if ( defined('COOKED_PRO_VERSION') ) { - if ( ! empty( $data['cuisine'] ) && taxonomy_exists( 'cp_recipe_cuisine' ) ) { - $cuisines = array_map( 'trim', explode( ',', $data['cuisine'] ) ); - $cuisine_ids = []; - foreach ( $cuisines as $cuisine_name ) { - $cuisine_name = sanitize_text_field( $cuisine_name ); - if ( ! empty( $cuisine_name ) ) { - $term = get_term_by( 'name', $cuisine_name, 'cp_recipe_cuisine' ); - if ( ! $term ) { - $term = wp_insert_term( $cuisine_name, 'cp_recipe_cuisine' ); - if ( ! is_wp_error( $term ) ) { - $cuisine_ids[] = $term['term_id']; - } - } else { - $cuisine_ids[] = $term->term_id; - } - } - } - if ( ! empty( $cuisine_ids ) ) { - wp_set_object_terms( $recipe_id, $cuisine_ids, 'cp_recipe_cuisine' ); - } - } - - if ( ! empty( $data['cooking_method'] ) && taxonomy_exists( 'cp_recipe_cooking_method' ) ) { - $cooking_methods = array_map( 'trim', explode( ',', $data['cooking_method'] ) ); - $cooking_method_ids = []; - foreach ( $cooking_methods as $cooking_method_name ) { - $cooking_method_name = sanitize_text_field( $cooking_method_name ); - if ( ! empty( $cooking_method_name ) ) { - $term = get_term_by( 'name', $cooking_method_name, 'cp_recipe_cooking_method' ); - if ( ! $term ) { - $term = wp_insert_term( $cooking_method_name, 'cp_recipe_cooking_method' ); - if ( ! is_wp_error( $term ) ) { - $cooking_method_ids[] = $term['term_id']; - } - } else { - $cooking_method_ids[] = $term->term_id; - } - } - } - if ( ! empty( $cooking_method_ids ) ) { - wp_set_object_terms( $recipe_id, $cooking_method_ids, 'cp_recipe_cooking_method' ); - } - } - - if ( ! empty( $data['diet'] ) && taxonomy_exists( 'cp_recipe_diet' ) ) { - $diets = array_map( 'trim', explode( ',', $data['diet'] ) ); - $diet_ids = []; - foreach ( $diets as $diet_name ) { - $diet_name = sanitize_text_field( $diet_name ); - if ( empty( $diet_name ) ) { - continue; - } - // cp_recipe_diet is restricted to Schema.org RestrictedDiet values - only assign existing terms - $term = get_term_by( 'name', $diet_name, 'cp_recipe_diet' ); - - if ( $term ) { - $diet_ids[] = $term->term_id; - } - } - if ( ! empty( $diet_ids ) ) { - wp_set_object_terms( $recipe_id, $diet_ids, 'cp_recipe_diet' ); - } - } - - if ( ! empty( $data['tags'] ) && taxonomy_exists( 'cp_recipe_tags' ) ) { - $tags = array_map( 'trim', explode( ',', $data['tags'] ) ); - $tag_ids = []; - foreach ( $tags as $tag_name ) { - if ( ! empty( $tag_name ) ) { - $term = get_term_by( 'name', $tag_name, 'cp_recipe_tags' ); - if ( ! $term ) { - $term = wp_insert_term( $tag_name, 'cp_recipe_tags' ); - if ( ! is_wp_error( $term ) ) { - $tag_ids[] = $term['term_id']; - } - } else { - $tag_ids[] = $term->term_id; - } - } - } - if ( ! empty( $tag_ids ) ) { - wp_set_object_terms( $recipe_id, $tag_ids, 'cp_recipe_tags' ); - } - } - } - - return [ - 'success' => true, - 'recipe_id' => $recipe_id - ]; - } - - /** - * Match a measurement string to a measurement key - * Checks exact key match, variations, singular, and plural forms - * - * @param string $measurement_string The measurement string from CSV - * @param array $measurements Full measurements array - * @return string|false The measurement key or false if not found - */ - private static function match_measurement( $measurement_string, $measurements ) { - $measurement_string = strtolower( trim( $measurement_string ) ); - - // First, check for exact key match - if ( isset( $measurements[ $measurement_string ] ) ) { - return $measurement_string; - } - - // Check variations, singular, and plural for each measurement - foreach ( $measurements as $key => $measurement_data ) { - // Check variations - if ( isset( $measurement_data['variations'] ) && is_array( $measurement_data['variations'] ) ) { - foreach ( $measurement_data['variations'] as $variation ) { - if ( strtolower( $variation ) === $measurement_string ) { - return $key; - } - } - } - - // Check singular - if ( isset( $measurement_data['singular'] ) && strtolower( $measurement_data['singular'] ) === $measurement_string ) { - return $key; - } - - // Check plural - if ( isset( $measurement_data['plural'] ) && strtolower( $measurement_data['plural'] ) === $measurement_string ) { - return $key; - } - - // Check singular abbreviation - if ( isset( $measurement_data['singular_abbr'] ) && strtolower( $measurement_data['singular_abbr'] ) === $measurement_string ) { - return $key; - } - - // Check plural abbreviation - if ( isset( $measurement_data['plural_abbr'] ) && strtolower( $measurement_data['plural_abbr'] ) === $measurement_string ) { - return $key; - } - } - - return false; - } - - /** - * Parse ingredient parts into ingredient array - * - * @param array $parts Array of ingredient parts (amount, measurement, name, etc.) - * @param array $measurements Full measurements array - * @return array|false Ingredient array or false on error - */ - private static function parse_ingredient_parts( $parts, $measurements ) { - if ( empty( $parts ) ) { - return false; - } - - $ingredient = [ - 'amount' => '', - 'measurement' => '', - 'name' => '', - 'url' => '', - 'description' => '', - 'sub_amount' => '', - 'sub_measurement' => '', - 'sub_name' => '', - ]; - - if ( count( $parts ) >= 3 ) { - // Format: amount|measurement|name - $ingredient['amount'] = sanitize_text_field( $parts[0] ); - $measurement = sanitize_text_field( $parts[1] ); - $matched_measurement = self::match_measurement( $measurement, $measurements ); - if ( $matched_measurement ) { - $ingredient['measurement'] = $matched_measurement; - } - $ingredient['name'] = sanitize_text_field( $parts[2] ); - if ( isset( $parts[3] ) ) { - $ingredient['description'] = sanitize_text_field( $parts[3] ); - } - } elseif ( count( $parts ) == 2 ) { - // Format: amount|name (no measurement) - $ingredient['amount'] = sanitize_text_field( $parts[0] ); - $ingredient['name'] = sanitize_text_field( $parts[1] ); - } else { - // Format: name only - $ingredient['name'] = sanitize_text_field( $parts[0] ); - } - - return $ingredient; - } + /** + * Parse and import recipes from CSV file + * + * @param string $file_path Path to the CSV file. + * @return array Results array with success count and errors + */ + public static function import_from_file( $file_path ) { + global $_cooked_settings; + + $results = array( + 'success' => 0, + 'errors' => array(), + 'total' => 0, + ); + + if ( ! file_exists( $file_path ) ) { + $results['errors'][] = __( 'CSV file not found.', 'cooked' ); + return $results; + } + + /** + * Open and parse CSV file + */ + $handle = fopen( $file_path, 'r' ); + if ( false === $handle ) { + $results['errors'][] = __( 'Could not open CSV file.', 'cooked' ); + return $results; + } + + /** + * Read header row + */ + $headers = fgetcsv( $handle ); + if ( false === $headers || empty( $headers ) ) { + $results['errors'][] = __( 'CSV file is empty or invalid.', 'cooked' ); + fclose( $handle ); + return $results; + } + + /** + * Normalize headers (trim and lowercase) + */ + $headers = array_map( 'trim', $headers ); + $headers = array_map( 'strtolower', $headers ); + + /** + * Check for required title column + */ + if ( ! in_array( 'title', $headers ) ) { + $results['errors'][] = __( 'CSV file must contain a "title" column.', 'cooked' ); + fclose( $handle ); + return $results; + } + + $row_number = 1; + while ( ( $row = fgetcsv( $handle ) ) !== false ) { + ++$row_number; + ++$results['total']; + + /** + * Skip empty rows + */ + if ( empty( array_filter( $row ) ) ) { + continue; + } + + /** + * Map row data to headers + */ + $data = array(); + foreach ( $headers as $index => $header ) { + $data[ $header ] = isset( $row[ $index ] ) ? trim( $row[ $index ] ) : ''; + } + + /** + * Import this recipe + */ + try { + $import_result = self::import_recipe( $data, $row_number ); + if ( $import_result['success'] ) { + ++$results['success']; + } else { + $error_msg = isset( $import_result['error'] ) ? $import_result['error'] : sprintf( + /* translators: %d: row number */ + __( 'Row %1$d: Unknown error', 'cooked' ), + $row_number + ); + $results['errors'][] = $error_msg; + + if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { + // phpcs:disable + error_log( 'Cooked CSV Import Error Row ' . $row_number . ': ' . $error_msg ); + // phpcs:enable + } + } + } catch ( Exception $e ) { + $error_msg = $e->getMessage(); + $results['errors'][] = sprintf( __( 'Row %1$d: %2$s', 'cooked' ), $row_number, $error_msg ); + + if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { + // phpcs:disable + error_log( 'Cooked CSV Import Exception Row ' . $row_number . ': ' . $error_msg ); + error_log( 'Stack trace: ' . $e->getTraceAsString() ); + // phpcs:enable + } + } + } + + fclose( $handle ); + return $results; + } + + /** + * Import a single recipe from CSV data + * + * @param array $data Recipe data from CSV row. + * @param int $row_number Row number for error reporting. + * @return array Result with success status and error message if any + */ + public static function import_recipe( $data, $row_number = 0 ) { + global $_cooked_settings; + + /** + * Validate required fields + */ + if ( empty( $data['title'] ) ) { + return array( + 'success' => false, + 'error' => sprintf( + /* translators: %d: row number */ + __( 'Row %1$d: Title is required', 'cooked' ), + $row_number + ), + ); + } + + /** + * Get default content + */ + if ( isset( $_cooked_settings['default_content'] ) ) { + $default_content = stripslashes( $_cooked_settings['default_content'] ); + } else { + $default_content = Cooked_Recipes::default_content(); + } + + /** + * Create new recipe post + */ + $new_recipe = array( + 'post_type' => 'cp_recipe', + 'post_status' => 'draft', + 'post_title' => sanitize_text_field( $data['title'] ), + 'post_content' => '', + 'post_author' => get_current_user_id(), + ); + + $recipe_id = wp_insert_post( $new_recipe ); + if ( is_wp_error( $recipe_id ) ) { + return array( + 'success' => false, + 'error' => sprintf( + /* translators: 1: row number, 2: error message */ + __( 'Row %1$d: %2$s', 'cooked' ), + $row_number, + $recipe_id->get_error_message() + ), + ); + } + + /** + * Prepare recipe meta + */ + $recipe_meta = array(); + $recipe_meta['cooked_version'] = COOKED_VERSION; + $recipe_meta['content'] = $default_content; + $recipe_meta['excerpt'] = isset( $data['excerpt'] ) ? sanitize_text_field( $data['excerpt'] ) : ''; + $recipe_meta['seo_description'] = isset( $data['seo_description'] ) ? sanitize_text_field( $data['seo_description'] ) : ( isset( $data['excerpt'] ) ? sanitize_text_field( $data['excerpt'] ) : '' ); + $recipe_meta['notes'] = isset( $data['notes'] ) ? wp_kses_post( $data['notes'] ) : ''; + + /** + * Difficulty level + */ + $difficulty_level = isset( $data['difficulty_level'] ) ? intval( $data['difficulty_level'] ) : 0; + if ( $difficulty_level < 1 || $difficulty_level > 3 ) { + $difficulty_level = 0; + } + $recipe_meta['difficulty_level'] = $difficulty_level; + + /** + * Times + */ + $recipe_meta['prep_time'] = isset( $data['prep_time'] ) ? intval( $data['prep_time'] ) : 0; + $recipe_meta['cook_time'] = isset( $data['cook_time'] ) ? intval( $data['cook_time'] ) : 0; + $recipe_meta['total_time'] = $recipe_meta['prep_time'] + $recipe_meta['cook_time']; + if ( isset( $data['total_time'] ) && ! empty( $data['total_time'] ) ) { + $recipe_meta['total_time'] = intval( $data['total_time'] ); + } + + /** + * Parse ingredients + */ + $recipe_meta['ingredients'] = array(); + if ( ! empty( $data['ingredients'] ) ) { + $measurements = Cooked_Measurements::get(); + + /** Split by | to get all parts + * Format: amount|measurement|name|amount|measurement|name||sub_amount|sub_measurement|sub_name|... + * When we see ||, it becomes two consecutive empty strings in the array + */ + $all_parts = array_map( 'trim', explode( '|', $data['ingredients'] ) ); + $i = 0; + + while ( $i < count( $all_parts ) ) { + /** + * Skip empty parts (they come from || separator) + */ + if ( empty( $all_parts[ $i ] ) ) { + ++$i; + continue; + } + + $part = $all_parts[ $i ]; + + /** + * Check if it's a section heading (starts with #) + */ + if ( strpos( $part, '#' ) === 0 ) { + $recipe_meta['ingredients'][] = array( + 'section_heading_name' => trim( $part, '#' ), + ); + ++$i; + continue; + } + + /** + * Collect next 3 non-empty parts for an ingredient (amount|measurement|name) + */ + $ingredient_parts = array(); + $j = $i; + while ( count( $ingredient_parts ) < 3 && $j < count( $all_parts ) ) { + $p = trim( $all_parts[ $j ] ); + if ( ! empty( $p ) ) { + $ingredient_parts[] = $p; + } + ++$j; + } + + if ( count( $ingredient_parts ) >= 3 ) { + $ingredient = self::parse_ingredient_parts( $ingredient_parts, $measurements ); + /** + * Move past the collected parts + */ + $i = $j; + + /** + * Check if next parts are empty (indicating || separator for substitution) + * + * Look ahead to see if we have empty parts followed by non-empty parts + */ + $next_empty_count = 0; + $k = $i; + while ( $k < count( $all_parts ) && empty( trim( $all_parts[ $k ] ) ) ) { + ++$next_empty_count; + ++$k; + } + + /** + * If we have empty parts (from ||) and then more parts, it's a substitution + */ + if ( $next_empty_count > 0 && $k < count( $all_parts ) ) { + /** + * Collect substitution parts (next 3 non-empty parts) + */ + $sub_parts = array(); + $sub_i = $k; + while ( count( $sub_parts ) < 3 && $sub_i < count( $all_parts ) ) { + $sub_part = trim( $all_parts[ $sub_i ] ); + if ( ! empty( $sub_part ) ) { + $sub_parts[] = $sub_part; + } + ++$sub_i; + } + + /** + * Parse substitution + */ + if ( count( $sub_parts ) >= 3 ) { + $ingredient['sub_amount'] = sanitize_text_field( $sub_parts[0] ); + $sub_measurement = sanitize_text_field( $sub_parts[1] ); + $matched_sub_measurement = self::match_measurement( $sub_measurement, $measurements ); + if ( $matched_sub_measurement ) { + $ingredient['sub_measurement'] = $matched_sub_measurement; + } + $ingredient['sub_name'] = sanitize_text_field( $sub_parts[2] ); + } elseif ( count( $sub_parts ) === 2 ) { + $ingredient['sub_amount'] = sanitize_text_field( $sub_parts[0] ); + $ingredient['sub_name'] = sanitize_text_field( $sub_parts[1] ); + } elseif ( count( $sub_parts ) === 1 ) { + $ingredient['sub_name'] = sanitize_text_field( $sub_parts[0] ); + } + + /** + * Move past substitution + */ + $i = $sub_i; + } + + $recipe_meta['ingredients'][] = $ingredient; + } else { + /** + * Not enough parts for a complete ingredient, skip + */ + ++$i; + } + } + } + + /** + * Parse directions + */ + $recipe_meta['directions'] = array(); + if ( ! empty( $data['directions'] ) ) { + $directions = explode( '|', $data['directions'] ); + foreach ( $directions as $direction_string ) { + $direction_string = trim( $direction_string ); + if ( empty( $direction_string ) ) { + continue; + } + + /** + * Check if it's a section heading (starts with #) + */ + if ( strpos( $direction_string, '#' ) === 0 ) { + $recipe_meta['directions'][] = array( + 'section_heading_name' => trim( $direction_string, '#' ), + ); + continue; + } + + $recipe_meta['directions'][] = array( + 'content' => wp_kses_post( $direction_string ), + ); + } + } + + /** + * Nutrition data + */ + $recipe_meta['nutrition'] = array(); + if ( isset( $data['servings'] ) && ! empty( $data['servings'] ) ) { + $recipe_meta['nutrition']['servings'] = sanitize_text_field( $data['servings'] ); + } + if ( isset( $data['calories'] ) && ! empty( $data['calories'] ) ) { + $recipe_meta['nutrition']['calories'] = intval( $data['calories'] ); + } + + /** + * Save recipe meta + */ + $recipe_meta = Cooked_Recipe_Meta::meta_cleanup( $recipe_meta ); + update_post_meta( $recipe_id, '_recipe_settings', $recipe_meta ); + + /** + * Update post excerpt + */ + $recipe_excerpt = ! empty( $recipe_meta['excerpt'] ) ? $recipe_meta['excerpt'] : get_the_title( $recipe_id ); + $seo_content = apply_filters( 'cooked_seo_recipe_content', '

' . wp_kses_post( $recipe_excerpt ) . '

' . __( 'Ingredients', 'cooked' ) . '

[cooked-ingredients checkboxes=false]

' . __( 'Directions', 'cooked' ) . '

[cooked-directions numbers=false]' ); + $seo_content = do_shortcode( $seo_content ); + + $should_update_content = apply_filters( 'cooked_should_update_post_content', true, $recipe_id ); + if ( $should_update_content ) { + wp_update_post( + array( + 'ID' => $recipe_id, + 'post_excerpt' => $recipe_excerpt, + 'post_content' => $seo_content, + ) + ); + } else { + wp_update_post( + array( + 'ID' => $recipe_id, + 'post_excerpt' => $recipe_excerpt, + ) + ); + } + + /** + * Handle taxonomies + */ + if ( ! empty( $data['categories'] ) && taxonomy_exists( 'cp_recipe_category' ) ) { + $categories = array_map( 'trim', explode( ',', $data['categories'] ) ); + $category_ids = array(); + foreach ( $categories as $category_name ) { + $category_name = sanitize_text_field( $category_name ); + if ( ! empty( $category_name ) ) { + $term = get_term_by( 'name', $category_name, 'cp_recipe_category' ); + if ( ! $term ) { + $term = wp_insert_term( $category_name, 'cp_recipe_category' ); + if ( ! is_wp_error( $term ) ) { + $category_ids[] = $term['term_id']; + } + } else { + $category_ids[] = $term->term_id; + } + } + } + if ( ! empty( $category_ids ) ) { + wp_set_object_terms( $recipe_id, $category_ids, 'cp_recipe_category' ); + } + } + + if ( defined( 'COOKED_PRO_VERSION' ) ) { + if ( ! empty( $data['cuisine'] ) && taxonomy_exists( 'cp_recipe_cuisine' ) ) { + $cuisines = array_map( 'trim', explode( ',', $data['cuisine'] ) ); + $cuisine_ids = array(); + foreach ( $cuisines as $cuisine_name ) { + $cuisine_name = sanitize_text_field( $cuisine_name ); + if ( ! empty( $cuisine_name ) ) { + $term = get_term_by( 'name', $cuisine_name, 'cp_recipe_cuisine' ); + if ( ! $term ) { + $term = wp_insert_term( $cuisine_name, 'cp_recipe_cuisine' ); + if ( ! is_wp_error( $term ) ) { + $cuisine_ids[] = $term['term_id']; + } + } else { + $cuisine_ids[] = $term->term_id; + } + } + } + if ( ! empty( $cuisine_ids ) ) { + wp_set_object_terms( $recipe_id, $cuisine_ids, 'cp_recipe_cuisine' ); + } + } + + if ( ! empty( $data['cooking_method'] ) && taxonomy_exists( 'cp_recipe_cooking_method' ) ) { + $cooking_methods = array_map( 'trim', explode( ',', $data['cooking_method'] ) ); + $cooking_method_ids = array(); + foreach ( $cooking_methods as $cooking_method_name ) { + $cooking_method_name = sanitize_text_field( $cooking_method_name ); + if ( ! empty( $cooking_method_name ) ) { + $term = get_term_by( 'name', $cooking_method_name, 'cp_recipe_cooking_method' ); + if ( ! $term ) { + $term = wp_insert_term( $cooking_method_name, 'cp_recipe_cooking_method' ); + if ( ! is_wp_error( $term ) ) { + $cooking_method_ids[] = $term['term_id']; + } + } else { + $cooking_method_ids[] = $term->term_id; + } + } + } + if ( ! empty( $cooking_method_ids ) ) { + wp_set_object_terms( $recipe_id, $cooking_method_ids, 'cp_recipe_cooking_method' ); + } + } + + if ( ! empty( $data['diet'] ) && taxonomy_exists( 'cp_recipe_diet' ) ) { + $diets = array_map( 'trim', explode( ',', $data['diet'] ) ); + $diet_ids = array(); + foreach ( $diets as $diet_name ) { + $diet_name = sanitize_text_field( $diet_name ); + if ( empty( $diet_name ) ) { + continue; + } + /** + * The cp_recipe_diet taxonomy is restricted to Schema.org RestrictedDiet values - only assign existing terms + */ + $term = get_term_by( 'name', $diet_name, 'cp_recipe_diet' ); + + if ( $term ) { + $diet_ids[] = $term->term_id; + } + } + if ( ! empty( $diet_ids ) ) { + wp_set_object_terms( $recipe_id, $diet_ids, 'cp_recipe_diet' ); + } + } + + if ( ! empty( $data['tags'] ) && taxonomy_exists( 'cp_recipe_tags' ) ) { + $tags = array_map( 'trim', explode( ',', $data['tags'] ) ); + $tag_ids = array(); + foreach ( $tags as $tag_name ) { + if ( ! empty( $tag_name ) ) { + $term = get_term_by( 'name', $tag_name, 'cp_recipe_tags' ); + if ( ! $term ) { + $term = wp_insert_term( $tag_name, 'cp_recipe_tags' ); + if ( ! is_wp_error( $term ) ) { + $tag_ids[] = $term['term_id']; + } + } else { + $tag_ids[] = $term->term_id; + } + } + } + if ( ! empty( $tag_ids ) ) { + wp_set_object_terms( $recipe_id, $tag_ids, 'cp_recipe_tags' ); + } + } + } + + return array( + 'success' => true, + 'recipe_id' => $recipe_id, + ); + } + + /** + * Match a measurement string to a measurement key. + * Checks exact key match, variations, singular, and plural forms. + * + * @param string $measurement_string The measurement string from CSV. + * @param array $measurements Full measurements array. + * @return string|false The measurement key or false if not found + */ + private static function match_measurement( $measurement_string, $measurements ) { + $measurement_string = strtolower( trim( $measurement_string ) ); + + /** + * First, check for exact key match + */ + if ( isset( $measurements[ $measurement_string ] ) ) { + return $measurement_string; + } + + /** + * Check variations, singular, and plural for each measurement + */ + foreach ( $measurements as $key => $measurement_data ) { + /** + * Check variations + */ + if ( isset( $measurement_data['variations'] ) && is_array( $measurement_data['variations'] ) ) { + foreach ( $measurement_data['variations'] as $variation ) { + if ( strtolower( $variation ) === $measurement_string ) { + return $key; + } + } + } + + /** + * Check singular + */ + if ( isset( $measurement_data['singular'] ) && strtolower( $measurement_data['singular'] ) === $measurement_string ) { + return $key; + } + + /** + * Check plural + */ + if ( isset( $measurement_data['plural'] ) && strtolower( $measurement_data['plural'] ) === $measurement_string ) { + return $key; + } + + /** + * Check singular abbreviation + */ + if ( isset( $measurement_data['singular_abbr'] ) && strtolower( $measurement_data['singular_abbr'] ) === $measurement_string ) { + return $key; + } + + /** + * Check plural abbreviation + */ + if ( isset( $measurement_data['plural_abbr'] ) && strtolower( $measurement_data['plural_abbr'] ) === $measurement_string ) { + return $key; + } + } + + return false; + } + + /** + * Parse ingredient parts into ingredient array + * + * @param array $parts Array of ingredient parts (amount, measurement, name, etc.). + * @param array $measurements Full measurements array. + * @return array|false Ingredient array or false on error + */ + private static function parse_ingredient_parts( $parts, $measurements ) { + if ( empty( $parts ) ) { + return false; + } + + $ingredient = array( + 'amount' => '', + 'measurement' => '', + 'name' => '', + 'url' => '', + 'description' => '', + 'sub_amount' => '', + 'sub_measurement' => '', + 'sub_name' => '', + ); + + if ( count( $parts ) >= 3 ) { + /** + * Format: amount|measurement|name + */ + $ingredient['amount'] = sanitize_text_field( $parts[0] ); + $measurement = sanitize_text_field( $parts[1] ); + $matched_measurement = self::match_measurement( $measurement, $measurements ); + if ( $matched_measurement ) { + $ingredient['measurement'] = $matched_measurement; + } + $ingredient['name'] = sanitize_text_field( $parts[2] ); + if ( isset( $parts[3] ) ) { + $ingredient['description'] = sanitize_text_field( $parts[3] ); + } + } elseif ( count( $parts ) === 2 ) { + /** + * Format: amount|name (no measurement) + */ + $ingredient['amount'] = sanitize_text_field( $parts[0] ); + $ingredient['name'] = sanitize_text_field( $parts[1] ); + } else { + /** + * Format: name only + */ + $ingredient['name'] = sanitize_text_field( $parts[0] ); + } + + return $ingredient; + } } - diff --git a/includes/class.cooked-elementor.php b/includes/class.cooked-elementor.php index 6a13f25..ca5030e 100644 --- a/includes/class.cooked-elementor.php +++ b/includes/class.cooked-elementor.php @@ -4,7 +4,7 @@ * * @package Cooked * @subpackage ELementor Support - * @since 1.0.0 + * @since 1.5.3 */ // Exit if accessed directly @@ -15,7 +15,7 @@ * * This class handles Elementor support. * - * @since 1.0.0 + * @since 1.5.3 */ class Cooked_Elementor { diff --git a/includes/class.cooked-gutenberg.php b/includes/class.cooked-gutenberg.php index 9c45c20..8e06f68 100644 --- a/includes/class.cooked-gutenberg.php +++ b/includes/class.cooked-gutenberg.php @@ -4,7 +4,7 @@ * * @package Cooked * @subpackage Gutenberg Functions - * @since 1.0.0 + * @since 1.5.2 */ // Exit if accessed directly @@ -15,7 +15,7 @@ * * This class handles the Cooked Recipe Meta Box creation. * - * @since 1.0.0 + * @since 1.5.2 */ class Cooked_Gutenberg { diff --git a/includes/class.cooked-import.php b/includes/class.cooked-import.php index 9229c6d..4bf1ddc 100644 --- a/includes/class.cooked-import.php +++ b/includes/class.cooked-import.php @@ -4,7 +4,7 @@ * * @package Cooked * @subpackage Import - * @since 1.0.0 + * @since 1.8.2 */ // Exit if accessed directly @@ -15,7 +15,7 @@ * * This class handles the import of recipes from other plugins. * - * @since 1.0.0 + * @since 1.8.2 */ class Cooked_Import { diff --git a/includes/class.cooked-migration.php b/includes/class.cooked-migration.php index afc246c..3b49039 100644 --- a/includes/class.cooked-migration.php +++ b/includes/class.cooked-migration.php @@ -4,7 +4,7 @@ * * @package Cooked * @subpackage Migration - * @since 1.0.0 + * @since 1.3.0 */ // Exit if accessed directly @@ -15,7 +15,7 @@ * * This class handles the migration from Cooked Classic. * - * @since 1.0.0 + * @since 1.3.0 */ class Cooked_Migration { diff --git a/includes/class.cooked-multilingual.php b/includes/class.cooked-multilingual.php index d8ed9ba..be95c69 100644 --- a/includes/class.cooked-multilingual.php +++ b/includes/class.cooked-multilingual.php @@ -4,7 +4,7 @@ * * @package Cooked * @subpackage Multilingual Support - * @since 1.13.0 + * @since 1.12.0 */ // Exit if accessed directly @@ -15,7 +15,7 @@ * * This class handles multilingual plugin support (Polylang, WPML, etc.). * - * @since 1.13.0 + * @since 1.12.0 */ class Cooked_Multilingual { diff --git a/includes/class.cooked-plugin-extra.php b/includes/class.cooked-plugin-extra.php index a2215d5..6ef3d83 100644 --- a/includes/class.cooked-plugin-extra.php +++ b/includes/class.cooked-plugin-extra.php @@ -4,7 +4,7 @@ * * @package Cooked * @subpackage Widgets - * @since 1.0.0 + * @since 1.8.8 */ // Exit if accessed directly @@ -20,7 +20,7 @@ public function __construct() { * * Adds a "Upgrade to Pro" link to the plugin list page. * - * @since 1.0.0 + * @since 1.8.8 * @param array $links * @return array */ diff --git a/includes/class.cooked-rankmathseo.php b/includes/class.cooked-rankmathseo.php index e512e21..b3392a0 100644 --- a/includes/class.cooked-rankmathseo.php +++ b/includes/class.cooked-rankmathseo.php @@ -4,7 +4,7 @@ * * @package Cooked * @subpackage Rank Math SEO Support - * @since 1.0.0 + * @since 1.8.8 */ // Exit if accessed directly @@ -15,7 +15,7 @@ * * This class handles Rank Math SEO support. * - * @since 1.0.0 + * @since 1.8.8 */ class Cooked_RankMathSEO { diff --git a/includes/class.cooked-yoastseo.php b/includes/class.cooked-yoastseo.php index 3ebb5f5..4dcc069 100644 --- a/includes/class.cooked-yoastseo.php +++ b/includes/class.cooked-yoastseo.php @@ -4,7 +4,7 @@ * * @package Cooked * @subpackage Yoast SEO Support - * @since 1.0.0 + * @since 1.8.8 */ // Exit if accessed directly @@ -15,7 +15,7 @@ * * This class handles Yoast SEO support. * - * @since 1.0.0 + * @since 1.8.8 */ class Cooked_YoastSEO { diff --git a/includes/widgets/init.php b/includes/widgets/init.php index 7375744..90cec5c 100644 --- a/includes/widgets/init.php +++ b/includes/widgets/init.php @@ -1,4 +1,11 @@ + + PHPCS configuration for Cooked + + . + + + */vendor/* + */tests/* + */node_modules/* + + + + + + + + + + + + + + + + + + + + cooked.php + /includes/ + + + + /includes/ + + + + cooked.php + + + + \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..4f0e223 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,15 @@ + + + + + tests/phpunit + + + \ No newline at end of file diff --git a/tests/phpunit/CSVImportTest.php b/tests/phpunit/CSVImportTest.php new file mode 100644 index 0000000..130cdf7 --- /dev/null +++ b/tests/phpunit/CSVImportTest.php @@ -0,0 +1,73 @@ +setAccessible( true ); + return $ref->invoke( null, ...$args ); + } + + public function test_parse_ingredient_parts_returns_false_for_empty() { + $measurements = Cooked_Measurements::get(); + $result = self::call_private_method( 'parse_ingredient_parts', [ [], $measurements ] ); + $this->assertFalse( $result ); + } + + public function test_parse_ingredient_parts_with_three_parts() { + $measurements = Cooked_Measurements::get(); + $result = self::call_private_method( 'parse_ingredient_parts', [ [ '2', 'cups', 'Flour' ], $measurements ] ); + $this->assertIsArray( $result ); + $this->assertSame( '2', $result['amount'] ); + $this->assertSame( 'Flour', $result['name'] ); + } + + public function test_parse_ingredient_parts_with_two_parts() { + $measurements = Cooked_Measurements::get(); + $result = self::call_private_method( 'parse_ingredient_parts', [ [ '3', 'Eggs' ], $measurements ] ); + $this->assertIsArray( $result ); + $this->assertSame( '3', $result['amount'] ); + $this->assertSame( 'Eggs', $result['name'] ); + $this->assertSame( '', $result['measurement'] ); + } + + public function test_parse_ingredient_parts_with_one_part() { + $measurements = Cooked_Measurements::get(); + $result = self::call_private_method( 'parse_ingredient_parts', [ [ 'Salt' ], $measurements ] ); + $this->assertIsArray( $result ); + $this->assertSame( 'Salt', $result['name'] ); + $this->assertSame( '', $result['amount'] ); + } + + public function test_match_measurement_exact_key() { + $measurements = Cooked_Measurements::get(); + $result = self::call_private_method( 'match_measurement', [ 'cup', $measurements ] ); + $this->assertSame( 'cup', $result ); + } + + public function test_match_measurement_singular() { + $measurements = Cooked_Measurements::get(); + $result = self::call_private_method( 'match_measurement', [ 'teaspoon', $measurements ] ); + $this->assertSame( 'tsp', $result ); + } + + public function test_match_measurement_plural() { + $measurements = Cooked_Measurements::get(); + $result = self::call_private_method( 'match_measurement', [ 'teaspoons', $measurements ] ); + $this->assertSame( 'tsp', $result ); + } + + public function test_match_measurement_case_insensitive() { + $measurements = Cooked_Measurements::get(); + $result = self::call_private_method( 'match_measurement', [ 'CUP', $measurements ] ); + $this->assertSame( 'cup', $result ); + } + + public function test_match_measurement_returns_false_for_unknown() { + $measurements = Cooked_Measurements::get(); + $result = self::call_private_method( 'match_measurement', [ 'furlong', $measurements ] ); + $this->assertFalse( $result ); + } +} diff --git a/tests/phpunit/EnqueuesTest.php b/tests/phpunit/EnqueuesTest.php new file mode 100644 index 0000000..e5f61fe --- /dev/null +++ b/tests/phpunit/EnqueuesTest.php @@ -0,0 +1,48 @@ +enqueues = new Cooked_Enqueues(); + } + + public function test_compress_css_removes_newlines() { + $css = ".foo {\n color: red;\n}"; + $result = $this->enqueues->compress_css($css); + $this->assertStringNotContainsString("\n", $result); + } + + public function test_compress_css_removes_tabs() { + $css = ".foo {\tcolor: red;\t}"; + $result = $this->enqueues->compress_css($css); + $this->assertStringNotContainsString("\t", $result); + } + + public function test_compress_css_removes_carriage_returns() { + $css = ".foo {\r\n color: red;\r\n}"; + $result = $this->enqueues->compress_css($css); + $this->assertStringNotContainsString("\r", $result); + } + + public function test_compress_css_removes_double_spaces() { + $css = ".foo { color: red; }"; + $result = $this->enqueues->compress_css($css); + $this->assertStringNotContainsString(' ', $result); + } + + public function test_compress_css_preserves_content() { + $css = ".foo { color: red; }"; + $result = $this->enqueues->compress_css($css); + $this->assertStringContainsString('.foo', $result); + $this->assertStringContainsString('color: red;', $result); + } + + public function test_compress_css_empty_string() { + $result = $this->enqueues->compress_css(''); + $this->assertSame('', $result); + } +} diff --git a/tests/phpunit/FunctionsExtraTest.php b/tests/phpunit/FunctionsExtraTest.php new file mode 100644 index 0000000..7341214 --- /dev/null +++ b/tests/phpunit/FunctionsExtraTest.php @@ -0,0 +1,43 @@ +assertIsString($result); + $this->assertNotEmpty($result); + } + + public function test_set_transient_message_empty_returns_null() { + $result = Cooked_Functions::set_transient_message(''); + $this->assertNull($result); + } + + public function test_get_and_delete_transient_message_returns_false_when_none() { + $result = Cooked_Functions::get_and_delete_transient_message(); + $this->assertFalse($result); + } + + public function test_parse_readme_changelog_returns_string() { + $result = Cooked_Functions::parse_readme_changelog(COOKED_DIR . 'readme.txt', 'What\'s New'); + $this->assertIsString($result); + } + + public function test_parse_readme_changelog_contains_title() { + $result = Cooked_Functions::parse_readme_changelog(COOKED_DIR . 'readme.txt', 'Custom Title'); + $this->assertStringContainsString('Custom Title', $result); + } + + public function test_sanitize_text_field_encodes_html() { + $result = Cooked_Functions::sanitize_text_field('test'); + $this->assertStringContainsString('<', $result); + $this->assertStringNotContainsString('', $result); + } + + public function test_sanitize_text_field_strips_slashes() { + $result = Cooked_Functions::sanitize_text_field("O\'Brien"); + $this->assertStringNotContainsString('\\', $result); + } +} diff --git a/tests/phpunit/FunctionsTest.php b/tests/phpunit/FunctionsTest.php new file mode 100644 index 0000000..5079a86 --- /dev/null +++ b/tests/phpunit/FunctionsTest.php @@ -0,0 +1,113 @@ +assertSame( '255,0,0', Cooked_Functions::hex2rgb( '#ff0000' ) ); + } + + /** + * Test hex2rgb converts pure green. + */ + public function test_hex2rgb_green() { + $this->assertSame( '0,255,0', Cooked_Functions::hex2rgb( '#00ff00' ) ); + } + + /** + * Test hex2rgb converts pure blue. + */ + public function test_hex2rgb_blue() { + $this->assertSame( '0,0,255', Cooked_Functions::hex2rgb( '#0000ff' ) ); + } + + /** + * Test hex2rgb converts black. + */ + public function test_hex2rgb_black() { + $this->assertSame( '0,0,0', Cooked_Functions::hex2rgb( '#000000' ) ); + } + + /** + * Test hex2rgb converts white. + */ + public function test_hex2rgb_white() { + $this->assertSame( '255,255,255', Cooked_Functions::hex2rgb( '#ffffff' ) ); + } + + /** + * Test hex2rgb converts mixed color. + */ + public function test_hex2rgb_mixed() { + $this->assertSame( '22,167,128', Cooked_Functions::hex2rgb( '#16a780' ) ); + } + + /** + * Test array_splice_assoc splices by numeric offset. + */ + public function test_array_splice_assoc_numeric_offset() { + $input = [ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4 ]; + Cooked_Functions::array_splice_assoc( $input, 1, 1 ); + + $this->assertSame( [ 'a' => 1, 'c' => 3, 'd' => 4 ], $input ); + } + + /** + * Test array_splice_assoc splices by string key (offset is position after the key). + */ + public function test_array_splice_assoc_string_key() { + $input = [ 'first' => 1, 'second' => 2, 'third' => 3 ]; + Cooked_Functions::array_splice_assoc( $input, 'first', 1 ); + + $this->assertSame( [ 'first' => 1, 'third' => 3 ], $input ); + } + + /** + * Test array_splice_assoc replaces with new elements. + */ + public function test_array_splice_assoc_with_replacement() { + $input = [ 'a' => 1, 'b' => 2, 'c' => 3 ]; + Cooked_Functions::array_splice_assoc( $input, 1, 1, [ 'x' => 99 ] ); + + $this->assertSame( [ 'a' => 1, 'x' => 99, 'c' => 3 ], $input ); + } + + /** + * Test array_splice_assoc handles empty replacement. + */ + public function test_array_splice_assoc_empty_replacement() { + $input = [ 'a' => 1, 'b' => 2, 'c' => 3 ]; + Cooked_Functions::array_splice_assoc( $input, 0, 1, [] ); + + $this->assertSame( [ 'b' => 2, 'c' => 3 ], $input ); + } + + /** + * Test array_splice_assoc does nothing on non-array input. + */ + public function test_array_splice_assoc_non_array() { + $input = 'not an array'; + Cooked_Functions::array_splice_assoc( $input, 0, 1 ); + + $this->assertSame( 'not an array', $input ); + } + + /** + * Test sanitize_text_field strips tags and slashes. + */ + public function test_sanitize_text_field_strips_tags() { + $result = Cooked_Functions::sanitize_text_field( '' ); + + $this->assertStringNotContainsString( 'My Recipe']; + $result = Cooked_Recipe_Meta::meta_cleanup($input); + $this->assertStringNotContainsString('