}
},
"require": {
- "cuyz/valinor": "^1.4.0",
- "dragonmantank/cron-expression": "^3.3.2",
+ "cuyz/valinor": "^1.5.0",
+ "dragonmantank/cron-expression": "^3.3.3",
"erusev/parsedown": "^1.7.4",
"ezyang/htmlpurifier": "^4.16",
"guzzlehttp/guzzle": "^7.7.0",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "d94553c231572f020140e0c1ed535635",
+ "content-hash": "19268d8275d6b8c74c4fc8303d9cb0f2",
"packages": [
{
"name": "cuyz/valinor",
- "version": "1.4.0",
+ "version": "1.5.0",
"source": {
"type": "git",
"url": "https://github.com/CuyZ/Valinor.git",
- "reference": "229098184cf5877ec01305461cdcb8a73379bf5b"
+ "reference": "668cd3f0f95c57d75981a31d63b5b1422606bc7e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/CuyZ/Valinor/zipball/229098184cf5877ec01305461cdcb8a73379bf5b",
- "reference": "229098184cf5877ec01305461cdcb8a73379bf5b",
+ "url": "https://api.github.com/repos/CuyZ/Valinor/zipball/668cd3f0f95c57d75981a31d63b5b1422606bc7e",
+ "reference": "668cd3f0f95c57d75981a31d63b5b1422606bc7e",
"shasum": ""
},
"require": {
],
"support": {
"issues": "https://github.com/CuyZ/Valinor/issues",
- "source": "https://github.com/CuyZ/Valinor/tree/1.4.0"
+ "source": "https://github.com/CuyZ/Valinor/tree/1.5.0"
},
"funding": [
{
"type": "github"
}
],
- "time": "2023-04-17T11:25:01+00:00"
+ "time": "2023-08-07T18:29:08+00:00"
},
{
"name": "dragonmantank/cron-expression",
- "version": "v3.3.2",
+ "version": "v3.3.3",
"source": {
"type": "git",
"url": "https://github.com/dragonmantank/cron-expression.git",
- "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8"
+ "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/782ca5968ab8b954773518e9e49a6f892a34b2a8",
- "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8",
+ "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/adfb1f505deb6384dc8b39804c5065dd3c8c8c0a",
+ "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a",
"shasum": ""
},
"require": {
],
"support": {
"issues": "https://github.com/dragonmantank/cron-expression/issues",
- "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.2"
+ "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.3"
},
"funding": [
{
"type": "github"
}
],
- "time": "2022-09-10T18:51:20+00:00"
+ "time": "2023-08-10T19:36:49+00:00"
},
{
"name": "erusev/parsedown",
'CuyZ\\Valinor\\Utility\\Reflection\\PhpParser' => $vendorDir . '/cuyz/valinor/src/Utility/Reflection/PhpParser.php',
'CuyZ\\Valinor\\Utility\\Reflection\\Reflection' => $vendorDir . '/cuyz/valinor/src/Utility/Reflection/Reflection.php',
'CuyZ\\Valinor\\Utility\\Reflection\\TokenParser' => $vendorDir . '/cuyz/valinor/src/Utility/Reflection/TokenParser.php',
+ 'CuyZ\\Valinor\\Utility\\String\\StringCutter' => $vendorDir . '/cuyz/valinor/src/Utility/String/StringCutter.php',
'CuyZ\\Valinor\\Utility\\String\\StringFormatter' => $vendorDir . '/cuyz/valinor/src/Utility/String/StringFormatter.php',
'CuyZ\\Valinor\\Utility\\String\\StringFormatterError' => $vendorDir . '/cuyz/valinor/src/Utility/String/StringFormatterError.php',
'CuyZ\\Valinor\\Utility\\TypeHelper' => $vendorDir . '/cuyz/valinor/src/Utility/TypeHelper.php',
'CuyZ\\Valinor\\Utility\\Reflection\\PhpParser' => __DIR__ . '/..' . '/cuyz/valinor/src/Utility/Reflection/PhpParser.php',
'CuyZ\\Valinor\\Utility\\Reflection\\Reflection' => __DIR__ . '/..' . '/cuyz/valinor/src/Utility/Reflection/Reflection.php',
'CuyZ\\Valinor\\Utility\\Reflection\\TokenParser' => __DIR__ . '/..' . '/cuyz/valinor/src/Utility/Reflection/TokenParser.php',
+ 'CuyZ\\Valinor\\Utility\\String\\StringCutter' => __DIR__ . '/..' . '/cuyz/valinor/src/Utility/String/StringCutter.php',
'CuyZ\\Valinor\\Utility\\String\\StringFormatter' => __DIR__ . '/..' . '/cuyz/valinor/src/Utility/String/StringFormatter.php',
'CuyZ\\Valinor\\Utility\\String\\StringFormatterError' => __DIR__ . '/..' . '/cuyz/valinor/src/Utility/String/StringFormatterError.php',
'CuyZ\\Valinor\\Utility\\TypeHelper' => __DIR__ . '/..' . '/cuyz/valinor/src/Utility/TypeHelper.php',
"packages": [
{
"name": "cuyz/valinor",
- "version": "1.4.0",
- "version_normalized": "1.4.0.0",
+ "version": "1.5.0",
+ "version_normalized": "1.5.0.0",
"source": {
"type": "git",
"url": "https://github.com/CuyZ/Valinor.git",
- "reference": "229098184cf5877ec01305461cdcb8a73379bf5b"
+ "reference": "668cd3f0f95c57d75981a31d63b5b1422606bc7e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/CuyZ/Valinor/zipball/229098184cf5877ec01305461cdcb8a73379bf5b",
- "reference": "229098184cf5877ec01305461cdcb8a73379bf5b",
+ "url": "https://api.github.com/repos/CuyZ/Valinor/zipball/668cd3f0f95c57d75981a31d63b5b1422606bc7e",
+ "reference": "668cd3f0f95c57d75981a31d63b5b1422606bc7e",
"shasum": ""
},
"require": {
"rector/rector": "~0.15.0",
"vimeo/psalm": "^5.0"
},
- "time": "2023-04-17T11:25:01+00:00",
+ "time": "2023-08-07T18:29:08+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
],
"support": {
"issues": "https://github.com/CuyZ/Valinor/issues",
- "source": "https://github.com/CuyZ/Valinor/tree/1.4.0"
+ "source": "https://github.com/CuyZ/Valinor/tree/1.5.0"
},
"funding": [
{
},
{
"name": "dragonmantank/cron-expression",
- "version": "v3.3.2",
- "version_normalized": "3.3.2.0",
+ "version": "v3.3.3",
+ "version_normalized": "3.3.3.0",
"source": {
"type": "git",
"url": "https://github.com/dragonmantank/cron-expression.git",
- "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8"
+ "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/782ca5968ab8b954773518e9e49a6f892a34b2a8",
- "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8",
+ "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/adfb1f505deb6384dc8b39804c5065dd3c8c8c0a",
+ "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a",
"shasum": ""
},
"require": {
"phpstan/phpstan-webmozart-assert": "^1.0",
"phpunit/phpunit": "^7.0|^8.0|^9.0"
},
- "time": "2022-09-10T18:51:20+00:00",
+ "time": "2023-08-10T19:36:49+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
],
"support": {
"issues": "https://github.com/dragonmantank/cron-expression/issues",
- "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.2"
+ "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.3"
},
"funding": [
{
'dev_requirement' => false,
),
'cuyz/valinor' => array(
- 'pretty_version' => '1.4.0',
- 'version' => '1.4.0.0',
- 'reference' => '229098184cf5877ec01305461cdcb8a73379bf5b',
+ 'pretty_version' => '1.5.0',
+ 'version' => '1.5.0.0',
+ 'reference' => '668cd3f0f95c57d75981a31d63b5b1422606bc7e',
'type' => 'library',
'install_path' => __DIR__ . '/../cuyz/valinor',
'aliases' => array(),
'dev_requirement' => false,
),
'dragonmantank/cron-expression' => array(
- 'pretty_version' => 'v3.3.2',
- 'version' => '3.3.2.0',
- 'reference' => '782ca5968ab8b954773518e9e49a6f892a34b2a8',
+ 'pretty_version' => 'v3.3.3',
+ 'version' => '3.3.3.0',
+ 'reference' => 'adfb1f505deb6384dc8b39804c5065dd3c8c8c0a',
'type' => 'library',
'install_path' => __DIR__ . '/../dragonmantank/cron-expression',
'aliases' => array(),
'psr/http-factory-implementation' => array(
'dev_requirement' => false,
'provided' => array(
- 0 => '^1.1 || ^2.0',
- 1 => '1.0',
+ 0 => '1.0',
+ 1 => '^1.1 || ^2.0',
),
),
'psr/http-message' => array(
'psr/http-message-implementation' => array(
'dev_requirement' => false,
'provided' => array(
- 0 => '^1.1 || ^2.0',
- 1 => '1.0',
+ 0 => '1.0',
+ 1 => '^1.1 || ^2.0',
),
),
'psr/http-server-handler' => array(
"psalm --config=tests/StaticAnalysis/psalm-with-plugin.xml",
"phpstan --configuration=tests/StaticAnalysis/phpstan-without-extension.neon.dist",
"phpstan --configuration=tests/StaticAnalysis/phpstan-with-extension.neon.dist",
- "@putenv PHP_CS_FIXER_IGNORE_ENV=1",
"php-cs-fixer fix --dry-run",
- "rector --dry-run"
+ "rector --dry-run",
+ "@check-todo"
+ ],
+ "check-todo": [
+ "! git --no-pager grep --extended-regexp --ignore-case 'todo|fixme' -- ':!composer.json' ':!*/quality-assurance.yml'"
],
"fix": [
"@putenv XDEBUG_MODE=off",
- "@putenv PHP_CS_FIXER_IGNORE_ENV=1",
"php-cs-fixer fix",
"rector"
],
final class TreeMapperPHPStanExtension implements DynamicMethodReturnTypeExtension
{
- public function __construct(private TypeStringResolver $resolver)
- {
- }
+ public function __construct(private TypeStringResolver $resolver) {}
public function getClass(): string
{
public function __construct(
private string $cacheDir,
private CacheCompiler $compiler
- ) {
- }
+ ) {}
public function has($key): bool
{
public function clear(): bool
{
+ if (! is_dir($this->cacheDir)) {
+ return true;
+ }
+
$success = true;
/** @var FilesystemIterator $file */
public function __construct(
/** @var CacheInterface<EntryType|TimestampsArray> */
private CacheInterface $delegate
- ) {
- }
+ ) {}
public function has($key): bool
{
private ObjectImplementations $implementations,
private ClassDefinitionRepository $classDefinitionRepository,
private ObjectBuilderFactory $objectBuilderFactory
- ) {
- }
+ ) {}
public function warmup(string ...$signatures): void
{
private Methods $methods,
private bool $isFinal,
private bool $isAbstract,
- ) {
- }
+ ) {}
/**
* @return class-string
private bool $isClosure,
private Parameters $parameters,
private Type $returnType
- ) {
- }
+ ) {}
public function name(): string
{
private FunctionDefinitionRepository $functionDefinitionRepository,
/** @var array<callable> */
private array $callables
- ) {
- }
+ ) {}
public function has(string|int $key): bool
{
private bool $isStatic,
private bool $isPublic,
private Type $returnType
- ) {
- }
+ ) {}
public function name(): string
{
{
private AttributesContainer $delegate;
- /** @var array<ReflectionAttribute<object>> */
- private array $reflectionAttributes;
+ /** @var array<class-string, array<mixed>> */
+ private array $definition = [];
/**
* @param ReflectionClass<object>|ReflectionProperty|ReflectionMethod|ReflectionFunction|ReflectionParameter $reflection
*/
public function __construct(ReflectionClass|ReflectionProperty|ReflectionMethod|ReflectionFunction|ReflectionParameter $reflection)
{
- $this->reflectionAttributes = $reflection->getAttributes();
-
$attributes = array_filter(
array_map(
static function (ReflectionAttribute $attribute) {
return null;
}
},
- $this->reflectionAttributes,
+ $reflection->getAttributes(),
),
);
+ foreach ($reflection->getAttributes() as $attribute) {
+ $this->definition[$attribute->getName()] = $attribute->getArguments();
+ }
+
$this->delegate = new AttributesContainer(...$attributes);
}
}
/**
- * @return array<ReflectionAttribute<object>>
+ * @return array<class-string, array<mixed>>
*/
- public function reflectionAttributes(): array
+ public function definition(): array
{
- return $this->reflectionAttributes;
+ return $this->definition;
}
}
private bool $isVariadic,
private mixed $defaultValue,
private Attributes $attributes
- ) {
- }
+ ) {}
public function name(): string
{
private mixed $defaultValue,
private bool $isPublic,
private Attributes $attributes
- ) {
- }
+ ) {}
public function name(): string
{
private ClassDefinitionRepository $delegate,
/** @var CacheInterface<ClassDefinition> */
private CacheInterface $cache
- ) {
- }
+ ) {}
public function for(ClassType $type): ClassDefinition
{
private FunctionDefinitionRepository $delegate,
/** @var CacheInterface<FunctionDefinition> */
private CacheInterface $cache
- ) {
- }
+ ) {}
public function for(callable $function): FunctionDefinition
{
use CuyZ\Valinor\Definition\Attributes;
use CuyZ\Valinor\Definition\AttributesContainer;
use CuyZ\Valinor\Definition\NativeAttributes;
-use ReflectionAttribute;
-use function array_map;
use function count;
use function implode;
use function var_export;
PHP;
}
- /**
- * @param ReflectionAttribute<object> $reflectionAttribute
- */
- private function compileNativeAttribute(ReflectionAttribute $reflectionAttribute): string
+ private function compileNativeAttributes(NativeAttributes $attributes): string
{
- $name = $reflectionAttribute->getName();
- $arguments = $reflectionAttribute->getArguments();
-
- /** @infection-ignore-all */
- if (count($arguments) > 0) {
- $arguments = serialize($arguments);
- $arguments = 'unserialize(' . var_export($arguments, true) . ')';
+ $attributes = $attributes->definition();
- return "new $name(...$arguments)";
+ if (count($attributes) === 0) {
+ return '[]';
}
- return "new $name()";
- }
+ $attributesListCode = [];
- private function compileNativeAttributes(NativeAttributes $attributes): string
- {
- $attributesListCode = array_map(
- fn (ReflectionAttribute $attribute) => $this->compileNativeAttribute($attribute),
- $attributes->reflectionAttributes()
- );
+ foreach ($attributes as $className => $arguments) {
+ if (count($arguments) === 0) {
+ $argumentsCode = '';
+ } else {
+ $argumentsCode = '...unserialize(' . var_export(serialize($arguments), true) . ')';
+ }
+
+ $attributesListCode[] = "new $className($argumentsCode)";
+ }
return '...[' . implode(",\n", $attributesListCode) . ']';
}
use CuyZ\Valinor\Definition\ParameterDefinition;
-use function is_scalar;
-
/** @internal */
final class ParameterDefinitionCompiler
{
public function __construct(
private TypeCompiler $typeCompiler,
private AttributesCompiler $attributesCompiler
- ) {
- }
+ ) {}
public function compile(ParameterDefinition $parameter): string
{
{
$defaultValue = $parameter->defaultValue();
- return is_scalar($defaultValue)
- ? var_export($parameter->defaultValue(), true)
- : 'unserialize(' . var_export(serialize($defaultValue), true) . ')';
+ return is_object($defaultValue)
+ ? 'unserialize(' . var_export(serialize($defaultValue), true) . ')'
+ : var_export($defaultValue, true);
}
}
public function __construct(
private TypeCompiler $typeCompiler,
private AttributesCompiler $attributesCompiler
- ) {
- }
+ ) {}
public function compile(PropertyDefinition $property): string
{
return "new $class($enumName, $pattern, [$cases])";
case $type instanceof UnresolvableType:
$raw = var_export($type->toString(), true);
- $message = var_export($type->getMessage(), true);
+ $message = var_export($type->message(), true);
return "new $class($raw, $message)";
default:
/** @internal */
final class ReflectionParameterDefinitionBuilder
{
- public function __construct(private AttributesRepository $attributesFactory)
- {
- }
+ public function __construct(private AttributesRepository $attributesFactory) {}
public function for(ReflectionParameter $reflection, ReflectionTypeResolver $typeResolver): ParameterDefinition
{
/** @internal */
final class ReflectionPropertyDefinitionBuilder
{
- public function __construct(private AttributesRepository $attributesRepository)
- {
- }
+ public function __construct(private AttributesRepository $attributesRepository) {}
public function for(ReflectionProperty $reflection, ReflectionTypeResolver $typeResolver): PropertyDefinition
{
public function __construct(
private TypeParser $nativeParser,
private TypeParser $advancedParser
- ) {
- }
+ ) {}
public function resolveType(\ReflectionProperty|\ReflectionParameter|\ReflectionFunctionAbstract $reflection): Type
{
$factory = new ReflectionObjectBuilderFactory();
$factory = new ConstructorObjectBuilderFactory($factory, $settings->nativeConstructors, $constructors);
$factory = new DateTimeZoneObjectBuilderFactory($factory, $this->get(FunctionDefinitionRepository::class));
- $factory = new DateTimeObjectBuilderFactory($factory, $this->get(FunctionDefinitionRepository::class));
+ $factory = new DateTimeObjectBuilderFactory($factory, $settings->supportedDateFormats, $this->get(FunctionDefinitionRepository::class));
$factory = new CollisionObjectBuilderFactory($factory);
if (! $settings->allowPermissiveTypes) {
/** @internal */
final class Settings
{
+ /** @var non-empty-array<non-empty-string> */
+ public const DEFAULT_SUPPORTED_DATETIME_FORMATS = [DATE_ATOM, 'U'];
+
/** @var array<class-string|interface-string, callable> */
public array $inferredMapping = [];
/** @var CacheInterface<mixed> */
public CacheInterface $cache;
+ /** @var non-empty-array<non-empty-string> */
+ public array $supportedDateFormats = self::DEFAULT_SUPPORTED_DATETIME_FORMATS;
+
public bool $enableFlexibleCasting = false;
public bool $allowSuperfluousKeys = false;
/**
* @param class-string<DateTime|DateTimeImmutable> $className
- * @param non-empty-string|positive-int $value
+ * @param non-empty-string|int $value
*/
#[DynamicConstructor]
public function __invoke(string $className, string|int $value): DateTimeInterface
* @api
*/
#[Attribute(Attribute::TARGET_FUNCTION | Attribute::TARGET_METHOD)]
-final class DynamicConstructor
-{
-}
+final class DynamicConstructor {}
$returnType = $function->returnType();
if ($returnType instanceof UnresolvableType) {
- $message = $returnType->getMessage();
- $previous = $returnType;
+ $message = $returnType->message();
} else {
$message = "Invalid return type `{$returnType->toString()}` for constructor `{$function->signature()}`, it must be a valid class name.";
- $previous = null;
}
- parent::__construct($message, 1659446121, $previous);
+ parent::__construct($message, 1659446121);
}
}
private ObjectBuilderFactory $delegate,
/** @var CacheInterface<list<ObjectBuilder>> */
private CacheInterface $cache
- ) {
- }
+ ) {}
public function for(ClassDefinition $class): array
{
/** @internal */
final class CollisionObjectBuilderFactory implements ObjectBuilderFactory
{
- public function __construct(private ObjectBuilderFactory $delegate)
- {
- }
+ public function __construct(private ObjectBuilderFactory $delegate) {}
public function for(ClassDefinition $class): array
{
/** @var array<class-string, null> */
private array $nativeConstructors,
private FunctionsContainer $constructors
- ) {
- }
+ ) {}
public function for(ClassDefinition $class): array
{
use CuyZ\Valinor\Definition\ClassDefinition;
use CuyZ\Valinor\Definition\FunctionObject;
use CuyZ\Valinor\Definition\Repository\FunctionDefinitionRepository;
+use CuyZ\Valinor\Library\Settings;
use CuyZ\Valinor\Mapper\Object\DateTimeFormatConstructor;
use CuyZ\Valinor\Mapper\Object\FunctionObjectBuilder;
use CuyZ\Valinor\Mapper\Object\NativeConstructorObjectBuilder;
{
public function __construct(
private ObjectBuilderFactory $delegate,
+ /** @var non-empty-array<non-empty-string> */
+ private array $supportedDateFormats,
private FunctionDefinitionRepository $functionDefinitionRepository
- ) {
- }
+ ) {}
public function for(ClassDefinition $class): array
{
// Remove `DateTime` & `DateTimeImmutable` native constructors
$builders = array_filter($builders, fn (ObjectBuilder $builder) => ! $builder instanceof NativeConstructorObjectBuilder);
- $useDefaultBuilder = true;
-
- foreach ($builders as $builder) {
- if (count($builder->describeArguments()) === 1) {
- $useDefaultBuilder = false;
- // @infection-ignore-all
- break;
- }
- }
+ $buildersWithOneArgument = array_filter($builders, fn (ObjectBuilder $builder) => count($builder->describeArguments()) === 1);
- if ($useDefaultBuilder) {
- // @infection-ignore-all / Ignore memoization
- $builders[] = $this->defaultBuilder($class->type());
+ if (count($buildersWithOneArgument) === 0 || $this->supportedDateFormats !== Settings::DEFAULT_SUPPORTED_DATETIME_FORMATS) {
+ $builders[] = $this->internalDateTimeBuilder($class->type());
}
return $builders;
}
- private function defaultBuilder(ClassType $type): FunctionObjectBuilder
+ private function internalDateTimeBuilder(ClassType $type): FunctionObjectBuilder
{
- $constructor = new DateTimeFormatConstructor(DATE_ATOM, 'U');
+ $constructor = new DateTimeFormatConstructor(...$this->supportedDateFormats);
$function = new FunctionObject($this->functionDefinitionRepository->for($constructor), $constructor);
return new FunctionObjectBuilder($function, $type);
/** @internal */
final class StrictTypesObjectBuilderFactory implements ObjectBuilderFactory
{
- public function __construct(private ObjectBuilderFactory $delegate)
- {
- }
+ public function __construct(private ObjectBuilderFactory $delegate) {}
public function for(ClassDefinition $class): array
{
private string $className,
private string $methodName,
private Parameters $parameters
- ) {
- }
+ ) {}
public function describeArguments(): Arguments
{
{
private Arguments $arguments;
- public function __construct(private ClassDefinition $class)
- {
- }
+ public function __construct(private ClassDefinition $class) {}
public function describeArguments(): Arguments
{
{
private Arguments $arguments;
- public function __construct(private ClassDefinition $class)
- {
- }
+ public function __construct(private ClassDefinition $class) {}
public function describeArguments(): Arguments
{
namespace CuyZ\Valinor\Mapper\Source\Exception;
+use JsonException;
use RuntimeException;
/** @internal */
final class InvalidJson extends RuntimeException implements InvalidSource
{
- public function __construct(private string $source)
+ public function __construct(private string $source, ?JsonException $previous = null)
{
parent::__construct(
'Invalid JSON source.',
- 1566307185
+ 1566307185,
+ $previous
);
}
use CuyZ\Valinor\Mapper\Source\Exception\SourceNotIterable;
use Iterator;
use IteratorAggregate;
+use JsonException;
use Traversable;
use function is_iterable;
use function json_decode;
+use const JSON_THROW_ON_ERROR;
+
/**
* @api
*
*/
public function __construct(string $jsonSource)
{
- $source = json_decode($jsonSource, true);
-
- if ($source === null) {
- throw new InvalidJson($jsonSource);
+ try {
+ $source = json_decode($jsonSource, associative: true, flags: JSON_THROW_ON_ERROR);
+ } catch (JsonException $e) {
+ throw new InvalidJson($jsonSource, $e);
}
if (! is_iterable($source)) {
private function __construct(
/** @var iterable<mixed> */
private iterable $delegate
- ) {
- }
+ ) {}
/**
* @param iterable<mixed> $data
/** @internal */
final class ArrayNodeBuilder implements NodeBuilder
{
- public function __construct(private bool $enableFlexibleCasting)
- {
- }
+ public function __construct(private bool $enableFlexibleCasting) {}
public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode
{
public function __construct(
/** @var array<class-string, NodeBuilder> */
private array $builders
- ) {
- }
+ ) {}
public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode
{
/** @internal */
final class CasterProxyNodeBuilder implements NodeBuilder
{
- public function __construct(private NodeBuilder $delegate)
- {
- }
+ public function __construct(private NodeBuilder $delegate) {}
public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode
{
private ObjectBuilderFactory $objectBuilderFactory,
private ObjectNodeBuilder $objectNodeBuilder,
private bool $enableFlexibleCasting
- ) {
- }
+ ) {}
public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode
{
/** @internal */
final class IterableNodeBuilder implements NodeBuilder
{
- public function __construct(private NodeBuilder $delegate)
- {
- }
+ public function __construct(private NodeBuilder $delegate) {}
public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode
{
/** @internal */
final class ListNodeBuilder implements NodeBuilder
{
- public function __construct(private bool $enableFlexibleCasting)
- {
- }
+ public function __construct(private bool $enableFlexibleCasting) {}
public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode
{
private ObjectBuilderFactory $objectBuilderFactory,
private ObjectNodeBuilder $objectNodeBuilder,
private bool $enableFlexibleCasting,
- ) {
- }
+ ) {}
public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode
{
/** @internal */
final class ObjectNodeBuilder
{
- public function __construct(private bool $allowSuperfluousKeys)
- {
- }
+ public function __construct(private bool $allowSuperfluousKeys) {}
public function build(ObjectBuilder $builder, Shell $shell, RootNodeBuilder $rootBuilder): TreeNode
{
/** @internal */
final class RootNodeBuilder
{
- public function __construct(private NodeBuilder $root)
- {
- }
+ public function __construct(private NodeBuilder $root) {}
public function build(Shell $shell): TreeNode
{
/** @internal */
final class ScalarNodeBuilder implements NodeBuilder
{
- public function __construct(private bool $enableFlexibleCasting)
- {
- }
+ public function __construct(private bool $enableFlexibleCasting) {}
public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode
{
/** @internal */
final class ShapedArrayNodeBuilder implements NodeBuilder
{
- public function __construct(private bool $allowSuperfluousKeys)
- {
- }
+ public function __construct(private bool $allowSuperfluousKeys) {}
public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode
{
private NodeBuilder $delegate,
private bool $allowPermissiveTypes,
private bool $enableFlexibleCasting
- ) {
- }
+ ) {}
public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode
{
private ObjectBuilderFactory $objectBuilderFactory,
private ObjectNodeBuilder $objectNodeBuilder,
private bool $enableFlexibleCasting
- ) {
- }
+ ) {}
public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode
{
public function __construct(
private NodeBuilder $delegate,
private FunctionsContainer $functions
- ) {
- }
+ ) {}
public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode
{
use Throwable;
/** @api */
-interface ErrorMessage extends Message, Throwable
-{
-}
+interface ErrorMessage extends Message, Throwable {}
/** @api */
final class LocaleMessageFormatter implements MessageFormatter
{
- public function __construct(private string $locale)
- {
- }
+ public function __construct(private string $locale) {}
public function format(NodeMessage $message): NodeMessage
{
public function __construct(
/** @var array<string|callable(NodeMessage): string> */
private array $map
- ) {
- }
+ ) {}
public function format(NodeMessage $message): NodeMessage
{
/** @var array<string, string> */
private array $parameters = [];
- private function __construct(private string $body)
- {
- }
+ private function __construct(private string $body) {}
/**
* @return self<Message>
/**
* @param array<string, string> $parameters
*/
- public function __construct(private string $body, private string $code, private array $parameters)
- {
- }
+ public function __construct(
+ private string $body,
+ private string $code,
+ private array $parameters
+ ) {}
public function body(): string
{
public function __construct(
private TypeParser $typeParser,
private RootNodeBuilder $nodeBuilder
- ) {
- }
+ ) {}
/** @pure */
public function map(string $signature, mixed $source): mixed
use CuyZ\Valinor\Library\Container;
use CuyZ\Valinor\Library\Settings;
use CuyZ\Valinor\Mapper\ArgumentsMapper;
-use CuyZ\Valinor\Mapper\Object\DateTimeFormatConstructor;
use CuyZ\Valinor\Mapper\Tree\Message\ErrorMessage;
use CuyZ\Valinor\Mapper\TreeMapper;
use Psr\SimpleCache\CacheInterface;
use Throwable;
+use function array_unique;
use function is_callable;
/** @api */
*/
public function supportDateFormats(string $format, string ...$formats): self
{
- return $this->registerConstructor(new DateTimeFormatConstructor($format, ...$formats));
+ $clone = clone $this;
+ $clone->settings->supportedDateFormats = array_unique([$format, ...$formats]);
+
+ return $clone;
+ }
+
+ /**
+ * Returns the date formats supported during mapping.
+ *
+ * By default, any valid timestamp or ATOM-formatted value are accepted.
+ * Custom formats can be set using method `supportDateFormats()`.
+ *
+ * @return non-empty-array<non-empty-string>
+ */
+ public function supportedDateFormats(): array
+ {
+ return $this->settings->supportedDateFormats;
}
/**
namespace CuyZ\Valinor\Type;
/** @internal */
-interface ClassType extends ObjectType
-{
-}
+interface ClassType extends ObjectType {}
/** @var array<string, Type> */
private array $types = [];
- public function __construct(private TypeParser $delegate)
- {
- }
+ public function __construct(private TypeParser $delegate) {}
public function parse(string $raw): Type
{
use Throwable;
/** @internal */
-interface InvalidType extends Throwable
-{
-}
+interface InvalidType extends Throwable {}
use Throwable;
/** @internal */
-interface InvalidTemplate extends Throwable
-{
-}
+interface InvalidTemplate extends Throwable {}
{
private TypeParser $nativeParser;
- public function __construct(private TemplateParser $templateParser)
- {
- }
+ public function __construct(private TemplateParser $templateParser) {}
public function get(TypeParserSpecification ...$specifications): TypeParser
{
public function __construct(
/** @var ReflectionClass<object>|ReflectionFunction */
private Reflector $reflection
- ) {
- }
+ ) {}
public function transform(TypeLexer $lexer): TypeLexer
{
public function __construct(
/** @var class-string */
private string $className
- ) {
- }
+ ) {}
public function transform(TypeLexer $lexer): TypeLexer
{
public function __construct(
/** @var array<string, Type> */
private array $aliases
- ) {
- }
+ ) {}
public function transform(TypeLexer $lexer): TypeLexer
{
private TypeLexer $delegate,
private TypeParserFactory $typeParserFactory,
private TemplateParser $templateParser
- ) {
- }
+ ) {}
public function tokenize(string $symbol): Token
{
private TypeLexer $delegate,
/** @var ReflectionClass<object>|ReflectionFunction */
private Reflector $reflection
- ) {
- }
+ ) {}
public function tokenize(string $symbol): Token
{
private ClassNameToken $delegate,
private TypeParserFactory $typeParserFactory,
private TemplateParser $templateParser
- ) {
- }
+ ) {}
public function traverse(TokenStream $stream): Type
{
/** @var class-string<ArrayType|NonEmptyArrayType> */
private string $arrayType,
private string $symbol
- ) {
- }
+ ) {}
public static function array(): self
{
public function __construct(
/** @var array<string, CaseType> */
private array $cases
- ) {
- }
+ ) {}
/**
* @param list<string> $tokens
public function __construct(
/** @var class-string<UnitEnum> */
private string $enumName
- ) {
- }
+ ) {}
public function traverse(TokenStream $stream): Type
{
/** @internal */
final class FloatValueToken implements TraversingToken
{
- public function __construct(private float $value)
- {
- }
+ public function __construct(private float $value) {}
public function traverse(TokenStream $stream): Type
{
/** @internal */
final class IntegerValueToken implements TraversingToken
{
- public function __construct(private int $value)
- {
- }
+ public function __construct(private int $value) {}
public function traverse(TokenStream $stream): Type
{
/** @var class-string<ListType|NonEmptyListType> */
private string $listType,
private string $symbol
- ) {
- }
+ ) {}
public static function list(): self
{
private function __construct(
private Type $type,
private string $symbol
- ) {
- }
+ ) {}
public static function accepts(string $symbol): bool
{
/** @internal */
final class QuoteToken implements TraversingToken
{
- public function __construct(private string $quoteType)
- {
- }
+ public function __construct(private string $quoteType) {}
public function traverse(TokenStream $stream): Type
{
public function __construct(
private Type $type,
private string $symbol
- ) {
- }
+ ) {}
public function traverse(TokenStream $stream): Type
{
/** @internal */
final class UnknownSymbolToken implements TraversingToken
{
- public function __construct(private string $symbol)
- {
- }
+ public function __construct(private string $symbol) {}
public function traverse(TokenStream $stream): Type
{
private TypeLexer $delegate,
/** @var array<string, Type> */
private array $aliases
- ) {
- }
+ ) {}
public function tokenize(string $symbol): Token
{
/** @internal */
final class LexingParser implements TypeParser
{
- public function __construct(private TypeLexer $lexer)
- {
- }
+ public function __construct(private TypeLexer $lexer) {}
public function parse(string $raw): Type
{
/**
* @codeCoverageIgnore
*/
- private function __construct(private bool $value)
- {
- }
+ private function __construct(private bool $value) {}
public static function true(): self
{
/** @internal */
final class FloatValueType implements FloatType, FixedType
{
- public function __construct(private float $value)
- {
- }
+ public function __construct(private float $value) {}
public function accepts(mixed $value): bool
{
/** @internal */
final class IntegerValueType implements IntegerType, FixedType
{
- public function __construct(private int $value)
- {
- }
+ public function __construct(private int $value) {}
public function accepts(mixed $value): bool
{
private string $interfaceName,
/** @var array<string, Type> */
private array $generics = []
- ) {
- }
+ ) {}
public function className(): string
{
private StringValueType|IntegerValueType $key,
private Type $type,
private bool $optional = false
- ) {
- }
+ ) {}
public function key(): StringValueType|IntegerValueType
{
{
private string $quoteChar;
- public function __construct(private string $value)
- {
- }
+ public function __construct(private string $value) {}
public static function singleQuote(string $value): self
{
use CuyZ\Valinor\Type\Type;
use CuyZ\Valinor\Utility\ValueDumper;
use LogicException;
-use Throwable;
/** @internal */
-final class UnresolvableType extends LogicException implements Type
+final class UnresolvableType implements Type
{
- private string $rawType;
-
- public function __construct(string $rawType, string $message, ?Throwable $previous = null)
- {
- $this->rawType = $rawType;
-
- parent::__construct($message, 1679578492, $previous);
- }
+ public function __construct(
+ private string $rawType,
+ private string $message,
+ ) {}
public static function forProperty(string $raw, string $signature, InvalidType $exception): self
{
return new self(
$raw,
- "The type `$raw` for property `$signature` could not be resolved: {$exception->getMessage()}",
- $exception
+ "The type `$raw` for property `$signature` could not be resolved: {$exception->getMessage()}"
);
}
{
return new self(
$raw,
- "The type `$raw` for parameter `$signature` could not be resolved: {$exception->getMessage()}",
- $exception
+ "The type `$raw` for parameter `$signature` could not be resolved: {$exception->getMessage()}"
);
}
{
return new self(
$raw,
- "The type `$raw` for return type of method `$signature` could not be resolved: {$exception->getMessage()}",
- $exception
+ "The type `$raw` for return type of method `$signature` could not be resolved: {$exception->getMessage()}"
);
}
{
return new self(
$raw,
- "The type `$raw` for local alias `$name` of the class `{$type->className()}` could not be resolved: {$exception->getMessage()}",
- $exception
+ "The type `$raw` for local alias `$name` of the class `{$type->className()}` could not be resolved: {$exception->getMessage()}"
);
}
+ public function message(): string
+ {
+ return $this->message;
+ }
+
public function accepts(mixed $value): bool
{
- throw $this;
+ throw new LogicException();
}
public function matches(Type $other): bool
{
- throw $this;
+ throw new LogicException();
}
public function toString(): string
--- /dev/null
+<?php
+
+declare(strict_types=1);
+
+namespace CuyZ\Valinor\Utility\String;
+
+use function substr;
+
+/** @internal */
+final class StringCutter
+{
+ public static function cut(string $s, int $length): string
+ {
+ if (function_exists('mb_strcut')) {
+ return mb_strcut($s, 0, $length);
+ }
+
+ return self::cutPolyfill($s, $length);
+ }
+
+ public static function cutPolyfill(string $s, int $length): string
+ {
+ $s = substr($s, 0, $length);
+ $cur = strlen($s) - 1;
+ // U+0000 - U+007F
+ if ((ord($s[$cur]) & 0b1000_0000) === 0) {
+ return $s;
+ }
+ $cnt = 0;
+ while ((ord($s[$cur]) & 0b1100_0000) === 0b1000_0000) {
+ ++$cnt;
+ if ($cur === 0) {
+ // @infection-ignore-all // Causes infinite loop
+ break;
+ }
+ --$cur;
+ }
+
+ assert($cur >= 0);
+
+ return match (true) {
+ default => substr($s, 0, $cur),
+ // U+0080 - U+07FF
+ $cnt === 1 && (ord($s[$cur]) & 0b1110_0000) === 0b1100_0000,
+ // U+0800 - U+FFFF
+ $cnt === 2 && (ord($s[$cur]) & 0b1111_0000) === 0b1110_0000,
+ // U+10000 - U+10FFFF
+ $cnt === 3 && (ord($s[$cur]) & 0b1111_1000) === 0b1111_0000 => $s
+ };
+ }
+}
private static function formatWithIntl(string $locale, string $body, array $parameters): string
{
return MessageFormatter::formatMessage($locale, $body, $parameters)
- ?: throw new StringFormatterError($body);
+ ?: throw new StringFormatterError($body, intl_get_error_message());
}
/**
/** @internal */
final class StringFormatterError extends RuntimeException
{
- public function __construct(string $body)
+ public function __construct(string $body, string $message = '')
{
- parent::__construct("Message formatter error using `$body`.", 1652901203);
+ if ($message !== '') {
+ $message = ": $message";
+ }
+ parent::__construct("Message formatter error using `$body`$message.", 1652901203);
}
}
namespace CuyZ\Valinor\Utility;
use BackedEnum;
+use CuyZ\Valinor\Utility\String\StringCutter;
use DateTimeInterface;
use UnitEnum;
return $string;
}
- $string = substr($string, 0, self::MAX_STRING_LENGTH + 1);
+ $string = StringCutter::cut($string, self::MAX_STRING_LENGTH + 1);
for ($i = strlen($string) - 1; $i > 10; $i--) {
if ($string[$i] === ' ') {
- return substr($string, 0, $i) . '…';
+ return StringCutter::cut($string, $i) . '…';
}
}
# Change Log
+## [3.3.3] - 2024-08-10
+
+### Added
+- N/A
+
+### Changed
+- N/A
+
+### Fixed
+- Added fixes for making sure `?` is not passed for both DOM and DOW (#148, thank you https://github.com/LeoVie)
+- Fixed bug in Next Execution Time by sorting minutes properly (#160, thank you https://github.com/imyip)
+
## [3.3.2] - 2022-09-19
### Added
=================================
* Part of the [Laravel Framework](https://github.com/laravel/framework/)
* Available as a [Symfony Bundle - setono/cron-expression-bundle](https://github.com/Setono/CronExpressionBundle)
-* Framework agnostic, PHP-based job scheduler - [Crunz](https://github.com/lavary/crunz)
+* Framework agnostic, PHP-based job scheduler - [Crunz](https://github.com/crunzphp/crunz)
+++ /dev/null
-parameters:
- checkMissingIterableValueType: false
-
- ignoreErrors:
- - '#Call to an undefined method DateTimeInterface::add\(\)#'
- - '#Call to an undefined method DateTimeInterface::modify\(\)#'
- - '#Call to an undefined method DateTimeInterface::setDate\(\)#'
- - '#Call to an undefined method DateTimeInterface::setTime\(\)#'
- - '#Call to an undefined method DateTimeInterface::setTimezone\(\)#'
- - '#Call to an undefined method DateTimeInterface::sub\(\)#'
-
- level: max
-
- paths:
- - src/
*
* @param string $expression CRON expression (e.g. '8 * * * *')
* @param null|FieldFactoryInterface $fieldFactory Factory to create cron fields
+ * @throws InvalidArgumentException
*/
public function __construct(string $expression, FieldFactoryInterface $fieldFactory = null)
{
$split = preg_split('/\s/', $value, -1, PREG_SPLIT_NO_EMPTY);
Assert::isArray($split);
- $this->cronParts = $split;
- if (\count($this->cronParts) < 5) {
+ $notEnoughParts = \count($split) < 5;
+
+ $questionMarkInInvalidPart = array_key_exists(0, $split) && $split[0] === '?'
+ || array_key_exists(1, $split) && $split[1] === '?'
+ || array_key_exists(3, $split) && $split[3] === '?';
+
+ $tooManyQuestionMarks = array_key_exists(2, $split) && $split[2] === '?'
+ && array_key_exists(4, $split) && $split[4] === '?';
+
+ if ($notEnoughParts || $questionMarkInInvalidPart || $tooManyQuestionMarks) {
throw new InvalidArgumentException(
$value . ' is not a valid CRON expression'
);
}
+ $this->cronParts = $split;
foreach ($this->cronParts as $position => $part) {
$this->setPart($position, $part);
}
$current_minute = (int) $date->format('i');
$parts = false !== strpos($parts, ',') ? explode(',', $parts) : [$parts];
+ sort($parts);
$minutes = [];
foreach ($parts as $part) {
$minutes = array_merge($minutes, $this->getRangeForExpression($part, 59));