diff --git a/.TypeVisitor.php-cs-fixer.dist.php b/.alpha-sort.php-cs-fixer.dist.php similarity index 94% rename from .TypeVisitor.php-cs-fixer.dist.php rename to .alpha-sort.php-cs-fixer.dist.php index 6b1a718..079fa78 100644 --- a/.TypeVisitor.php-cs-fixer.dist.php +++ b/.alpha-sort.php-cs-fixer.dist.php @@ -8,6 +8,7 @@ $finder = Finder::create()->append([ __FILE__, + __DIR__ . '/src/types.php', __DIR__ . '/src/TypeVisitor.php', ]); diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 6f3e13b..8fa8ffb 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -8,7 +8,10 @@ $finder = Finder::create() ->in(__DIR__ . '/src') - ->notName(['TypeVisitor.php']) + ->notName([ + 'TypeVisitor.php', + 'types.php', + ]) ->append([__FILE__]) ->append(Finder::create()->in(__DIR__ . '/tests')); diff --git a/composer.json b/composer.json index 079295a..618464b 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,7 @@ "scripts": { "fixcs": [ "vendor/bin/php-cs-fixer fix --verbose", - "vendor/bin/php-cs-fixer fix --config=.TypeVisitor.php-cs-fixer.dist.php --verbose" + "vendor/bin/php-cs-fixer fix --config=.alpha-sort.php-cs-fixer.dist.php --verbose" ], "pre-command-run": "mkdir -p var", "psalm": "psalm --show-info --no-diff", diff --git a/src/types.php b/src/types.php index 6391451..05d9036 100644 --- a/src/types.php +++ b/src/types.php @@ -9,30 +9,30 @@ */ final class types { - public const never = NeverType::type; - public const void = VoidType::type; - public const null = NullType::type; - public const false = __false; - public const true = __true; + public const arrayKey = __arrayKey; public const bool = BoolType::type; + public const classString = ClassStringType::type; + public const false = __false; + public const float = FloatType::type; public const int = IntType::type; - public const positiveInt = __positiveInt; + public const mixed = MixedType::type; public const negativeInt = __negativeInt; - public const nonPositiveInt = __nonPositiveInt; - public const nonNegativeInt = __nonNegativeInt; - public const float = FloatType::type; - public const numericString = NumericStringType::type; - public const classString = ClassStringType::type; + public const never = NeverType::type; public const nonEmptyString = __nonEmptyString; - public const truthyString = TruthyStringType::type; public const nonFalsyString = TruthyStringType::type; - public const string = StringType::type; + public const nonNegativeInt = __nonNegativeInt; + public const nonPositiveInt = __nonPositiveInt; + public const null = NullType::type; public const numeric = __numeric; - public const scalar = __scalar; + public const numericString = NumericStringType::type; public const object = ObjectType::type; + public const positiveInt = __positiveInt; public const resource = ResourceType::type; - public const arrayKey = __arrayKey; - public const mixed = MixedType::type; + public const scalar = __scalar; + public const string = StringType::type; + public const true = __true; + public const truthyString = TruthyStringType::type; + public const void = VoidType::type; /** * @psalm-suppress UnusedConstructor @@ -40,13 +40,12 @@ final class types private function __construct() {} /** - * @template TValue of bool|int|float|string - * @param TValue $value - * @return LiteralType + * @param non-empty-string $class + * @param non-empty-string $name */ - public static function literal(bool|int|float|string $value): LiteralType + public static function alias(string $class, string $name): AliasType { - return new LiteralType($value); + return new AliasType($class, $name); } /** @@ -60,73 +59,38 @@ public static function anyLiteral(Type $type): AnyLiteralType } /** - * @template TClass of non-empty-string - * @param TClass $class - * @return ClassStringLiteralType - */ - public static function classStringLiteral(string $class): ClassStringLiteralType - { - return new ClassStringLiteralType($class); - } - - /** - * @no-named-arguments - * @param non-negative-int $int - * @param non-negative-int ...$ints - */ - public static function intMask(int $int, int ...$ints): IntMaskType - { - return new IntMaskType([$int, ...$ints]); - } - - /** - * @template TIntMask of positive-int - * @param Type $type - * @return IntMaskOfType - */ - public static function intMaskOf(Type $type): IntMaskOfType - { - return new IntMaskOfType($type); - } - - public static function intRange(?int $min = null, ?int $max = null): IntType|IntRangeType - { - if ($min === null && $max === null) { - return IntType::type; - } - - return new IntRangeType($min, $max); - } - - /** - * @template TObject of object - * @param Type $type - * @return NamedClassStringType + * @param non-empty-string $name */ - public static function classString(Type $type): NamedClassStringType + public static function arg(string $name): Argument { - return new NamedClassStringType($type); + return new Argument($name); } /** + * @template TKey of array-key * @template TValue + * @param Type $keyType * @param Type $valueType - * @return Type> - * @psalm-suppress InvalidReturnType, InvalidReturnStatement + * @return ArrayType + * @psalm-suppress MixedReturnTypeCoercion */ - public static function nonEmptyList(Type $valueType = self::mixed): Type + public static function array(Type $keyType = self::arrayKey, Type $valueType = self::mixed): ArrayType { - return new NonEmptyType(self::list($valueType)); + if ($keyType === self::arrayKey && $valueType === self::mixed) { + return __array; + } + + return new ArrayType($keyType, $valueType); } /** - * @template TValue - * @param Type $valueType - * @return ListType + * @template TType + * @param Type $type + * @return ArrayElement */ - public static function list(Type $valueType = self::mixed): ListType + public static function arrayElement(Type $type, bool $optional = false): ArrayElement { - return new ListType($valueType); + return new ArrayElement($type, $optional); } /** @@ -146,100 +110,80 @@ public static function arrayShape(array $elements = [], bool $sealed = true): Ar } /** - * @template TType - * @param Type $type - * @return ArrayElement + * @param non-empty-string $name */ - public static function arrayElement(Type $type, bool $optional = false): ArrayElement + public static function atClass(string $name): AtClass { - return new ArrayElement($type, $optional); + return new AtClass($name); } /** - * @template TKey of array-key - * @template TValue - * @param Type $keyType - * @param Type $valueType - * @return Type> - * @psalm-suppress MoreSpecificReturnType, LessSpecificReturnStatement + * @param non-empty-string $name */ - public static function nonEmptyArray(Type $keyType = self::arrayKey, Type $valueType = self::mixed): Type + public static function atFunction(string $name): AtFunction { - return new NonEmptyType(self::array($keyType, $valueType)); + return new AtFunction($name); } /** - * @template TKey of array-key - * @template TValue - * @param Type $keyType - * @param Type $valueType - * @return ArrayType - * @psalm-suppress MixedReturnTypeCoercion + * @param non-empty-string $class + * @param non-empty-string $name */ - public static function array(Type $keyType = self::arrayKey, Type $valueType = self::mixed): ArrayType + public static function atMethod(string $class, string $name): AtMethod { - if ($keyType === self::arrayKey && $valueType === self::mixed) { - return __array; - } - - return new ArrayType($keyType, $valueType); + return new AtMethod($class, $name); } /** - * @template TKey - * @template TValue - * @param Type $keyType - * @param Type $valueType - * @return IterableType + * @template TReturn + * @param list $parameters + * @param Type $returnType + * @return CallableType */ - public static function iterable(Type $keyType = self::mixed, Type $valueType = self::mixed): IterableType + public static function callable(array $parameters = [], ?Type $returnType = null): CallableType { - if ($keyType === self::mixed && $valueType === self::mixed) { - return __iterable; + if ($parameters === [] && $returnType === null) { + return __callable; } - return new IterableType($keyType, $valueType); - } - - /** - * @param array $properties - */ - public static function objectShape(array $properties = []): ObjectShapeType - { - return new ObjectShapeType( + return new CallableType( array_map( - static fn(Type|Property $property): Property => $property instanceof Type ? new Property($property) : $property, - $properties, + static fn(Type|Parameter $parameter): Parameter => $parameter instanceof Type + ? new Parameter($parameter) + : $parameter, + $parameters, ), + $returnType, ); } - public static function prop(Type $type, bool $optional = false): Property + /** + * @param non-empty-string $class + * @param non-empty-string $constant + */ + public static function classConstant(string $class, string $constant): ClassConstantType { - return new Property($type, $optional); + return new ClassConstantType($class, $constant); } /** - * @no-named-arguments * @template TObject of object - * @param class-string|non-empty-string $class - * @return ($class is class-string ? NamedObjectType : NamedObjectType) - * @psalm-suppress MixedReturnTypeCoercion + * @param Type $type + * @return NamedClassStringType */ - public static function object(string $class, Type ...$templateArguments): NamedObjectType + public static function classString(Type $type): NamedClassStringType { - return new NamedObjectType($class, $templateArguments); + return new NamedClassStringType($type); } /** - * @no-named-arguments - * @template TObject of object - * @param class-string $declaredAtClass - * @return StaticType + * @template TClass of non-empty-string + * @param TClass $class + * @return ClassStringLiteralType */ - public static function static(string $declaredAtClass, Type ...$templateArguments): StaticType + public static function classStringLiteral(string $class): ClassStringLiteralType { - return new StaticType($declaredAtClass, $templateArguments); + return new ClassStringLiteralType($class); } /** @@ -265,147 +209,198 @@ public static function closure(array $parameters = [], ?Type $returnType = null) ); } + public static function conditional(Argument|TemplateType $subject, Type $if, Type $then, Type $else): ConditionalType + { + return new ConditionalType($subject, $if, $then, $else); + } + /** - * @template TReturn - * @param list $parameters - * @param Type $returnType - * @return CallableType + * @param non-empty-string $constant */ - public static function callable(array $parameters = [], ?Type $returnType = null): CallableType + public static function constant(string $constant): ConstantType { - if ($parameters === [] && $returnType === null) { - return __callable; - } - - return new CallableType( - array_map( - static fn(Type|Parameter $parameter): Parameter => $parameter instanceof Type - ? new Parameter($parameter) - : $parameter, - $parameters, - ), - $returnType, - ); + return new ConstantType($constant); } /** - * @template TType - * @param Type $type - * @param ?non-empty-string $name - * @return Parameter + * @no-named-arguments */ - public static function param(Type $type = self::mixed, bool $hasDefault = false, bool $variadic = false, bool $byReference = false, ?string $name = null): Parameter + public static function intersection(Type $type1, Type $type2, Type ...$moreTypes): IntersectionType { - return new Parameter($type, $hasDefault, $variadic, $byReference, $name); + return new IntersectionType([$type1, $type2, ...$moreTypes]); } /** - * @param non-empty-string $constant + * @no-named-arguments + * @param non-negative-int $int + * @param non-negative-int ...$ints */ - public static function constant(string $constant): ConstantType + public static function intMask(int $int, int ...$ints): IntMaskType { - return new ConstantType($constant); + return new IntMaskType([$int, ...$ints]); } /** - * @param non-empty-string $class - * @param non-empty-string $constant + * @template TIntMask of positive-int + * @param Type $type + * @return IntMaskOfType */ - public static function classConstant(string $class, string $constant): ClassConstantType + public static function intMaskOf(Type $type): IntMaskOfType { - return new ClassConstantType($class, $constant); + return new IntMaskOfType($type); } - public static function keyOf(Type $type): KeyOfType + public static function intRange(?int $min = null, ?int $max = null): IntType|IntRangeType { - return new KeyOfType($type); + if ($min === null && $max === null) { + return IntType::type; + } + + return new IntRangeType($min, $max); } - public static function valueOf(Type $type): ValueOfType + /** + * @template TKey + * @template TValue + * @param Type $keyType + * @param Type $valueType + * @return IterableType + */ + public static function iterable(Type $keyType = self::mixed, Type $valueType = self::mixed): IterableType { - return new ValueOfType($type); + if ($keyType === self::mixed && $valueType === self::mixed) { + return __iterable; + } + + return new IterableType($keyType, $valueType); } - public static function offset(Type $subject, Type $offset): OffsetType + public static function keyOf(Type $type): KeyOfType { - return new OffsetType($subject, $offset); + return new KeyOfType($type); } /** - * @template TType - * @param non-empty-string $name - * @param Type $constraint - * @return TemplateType + * @template TValue + * @param Type $valueType + * @return ListType */ - public static function template(string $name, AtMethod|AtClass|AtFunction $declaredAt, Type $constraint = self::mixed): TemplateType + public static function list(Type $valueType = self::mixed): ListType { - return new TemplateType($name, $declaredAt, $constraint); + return new ListType($valueType); } /** - * @param non-empty-string $name + * @template TValue of bool|int|float|string + * @param TValue $value + * @return LiteralType */ - public static function atFunction(string $name): AtFunction + public static function literal(bool|int|float|string $value): LiteralType { - return new AtFunction($name); + return new LiteralType($value); } /** - * @param non-empty-string $name + * @template TKey of array-key + * @template TValue + * @param Type $keyType + * @param Type $valueType + * @return Type> + * @psalm-suppress MoreSpecificReturnType, LessSpecificReturnStatement */ - public static function atClass(string $name): AtClass + public static function nonEmptyArray(Type $keyType = self::arrayKey, Type $valueType = self::mixed): Type { - return new AtClass($name); + return new NonEmptyType(self::array($keyType, $valueType)); } /** - * @param non-empty-string $class - * @param non-empty-string $name + * @template TValue + * @param Type $valueType + * @return Type> + * @psalm-suppress InvalidReturnType, InvalidReturnStatement */ - public static function atMethod(string $class, string $name): AtMethod + public static function nonEmptyList(Type $valueType = self::mixed): Type { - return new AtMethod($class, $name); + return new NonEmptyType(self::list($valueType)); } - public static function conditional(Argument|TemplateType $subject, Type $if, Type $then, Type $else): ConditionalType + /** + * @no-named-arguments + * @template TType + * @param Type $type + * @return UnionType + */ + public static function nullable(Type $type): UnionType { - return new ConditionalType($subject, $if, $then, $else); + return new UnionType([self::null, $type]); } /** - * @param non-empty-string $class - * @param non-empty-string $name + * @no-named-arguments + * @template TObject of object + * @param class-string|non-empty-string $class + * @return ($class is class-string ? NamedObjectType : NamedObjectType) + * @psalm-suppress MixedReturnTypeCoercion */ - public static function alias(string $class, string $name): AliasType + public static function object(string $class, Type ...$templateArguments): NamedObjectType { - return new AliasType($class, $name); + return new NamedObjectType($class, $templateArguments); } /** - * @param non-empty-string $name + * @param array $properties */ - public static function arg(string $name): Argument + public static function objectShape(array $properties = []): ObjectShapeType { - return new Argument($name); + return new ObjectShapeType( + array_map( + static fn(Type|Property $property): Property => $property instanceof Type ? new Property($property) : $property, + $properties, + ), + ); + } + + public static function offset(Type $subject, Type $offset): OffsetType + { + return new OffsetType($subject, $offset); } /** - * @no-named-arguments * @template TType * @param Type $type - * @return UnionType + * @param ?non-empty-string $name + * @return Parameter */ - public static function nullable(Type $type): UnionType + public static function param(Type $type = self::mixed, bool $hasDefault = false, bool $variadic = false, bool $byReference = false, ?string $name = null): Parameter { - return new UnionType([self::null, $type]); + return new Parameter($type, $hasDefault, $variadic, $byReference, $name); + } + + public static function prop(Type $type, bool $optional = false): Property + { + return new Property($type, $optional); } /** * @no-named-arguments + * @template TObject of object + * @param class-string $declaredAtClass + * @return StaticType */ - public static function intersection(Type $type1, Type $type2, Type ...$moreTypes): IntersectionType + public static function static(string $declaredAtClass, Type ...$templateArguments): StaticType { - return new IntersectionType([$type1, $type2, ...$moreTypes]); + return new StaticType($declaredAtClass, $templateArguments); + } + + /** + * @template TType + * @param non-empty-string $name + * @param Type $constraint + * @return TemplateType + */ + public static function template(string $name, AtMethod|AtClass|AtFunction $declaredAt, Type $constraint = self::mixed): TemplateType + { + return new TemplateType($name, $declaredAt, $constraint); } /** @@ -420,6 +415,11 @@ public static function union(Type $type1, Type $type2, Type ...$moreTypes): Unio { return new UnionType([$type1, $type2, ...$moreTypes]); } + + public static function valueOf(Type $type): ValueOfType + { + return new ValueOfType($type); + } } /**