From 2a5a3c1746d986ed0950da38c9582f409c909265 Mon Sep 17 00:00:00 2001 From: brainshaker Date: Wed, 18 Oct 2023 21:44:49 +0200 Subject: [PATCH 1/6] refactor(visibilities): reduce visibilities wherever possible --- src/Command/DumpCommand.php | 4 +- src/Interface/Config.php | 78 ++++++++++++------------- src/Model/Config/FileType.php | 4 +- src/Model/Config/TypeDefinitionType.php | 4 +- src/Tool/Assert.php | 30 +++++----- src/Tool/Attribute.php | 6 +- src/Tool/Converter.php | 14 ++--- src/Tool/PhpStan.php | 24 ++++---- tests/DumpCommandTest.php | 74 +++++++++++------------ 9 files changed, 122 insertions(+), 116 deletions(-) diff --git a/src/Command/DumpCommand.php b/src/Command/DumpCommand.php index d240a4b..c1024b0 100644 --- a/src/Command/DumpCommand.php +++ b/src/Command/DumpCommand.php @@ -26,8 +26,8 @@ abstract class DumpCommand extends Command use HasConfiguration; use HasDumper; - final public const INDENT_STYLE_KEY = C::INDENT_KEY . '-' . C::INDENT_STYLE_KEY; - final public const INDENT_COUNT_KEY = C::INDENT_KEY . '-' . C::INDENT_COUNT_KEY; + final protected const INDENT_STYLE_KEY = C::INDENT_KEY . '-' . C::INDENT_STYLE_KEY; + final protected const INDENT_COUNT_KEY = C::INDENT_KEY . '-' . C::INDENT_COUNT_KEY; protected InputInterface $input; diff --git a/src/Interface/Config.php b/src/Interface/Config.php index c8d4fdb..9fbcea2 100644 --- a/src/Interface/Config.php +++ b/src/Interface/Config.php @@ -30,50 +30,50 @@ */ interface Config { - public const OUTPUT_DIR_KEY = 'output_dir'; - public const OUTPUT_DIR_DEFAULT = 'assets/ts/types/php-to-ts'; - public const OUTPUT_DIR_DESC = 'Directory in which to dump TypeScript interfaces'; - - public const INPUT_DIR_KEY = 'input_dir'; - public const INPUT_DIR_DEFAULT = 'src/Model'; - public const INPUT_DIR_DESC = 'Directory in which to look for models to include'; - - public const FILE_TYPE_KEY = 'file_type'; - public const FILE_TYPE_DEFAULT = FileType::TYPE_MODULE; - public const FILE_TYPE_DESC = 'File type to use for TypeScript interfaces'; - public const FILE_TYPE_VALID_VALUES = [FileType::TYPE_DECLARATION, FileType::TYPE_MODULE]; - - public const TYPE_DEFINITION_TYPE_KEY = 'type_definition_type'; - public const TYPE_DEFINITION_TYPE_DEFAULT = TypeDefinitionType::TYPE_INTERFACE; - public const TYPE_DEFINITION_TYPE_DESC = 'Type definition type to use for TypeScript interfaces'; - public const TYPE_DEFINITION_TYPE_VALID_VALUES = [TypeDefinitionType::TYPE_INTERFACE, TypeDefinitionType::TYPE_TYPE_ALIAS]; - - public const INDENT_KEY = 'indent'; - public const INDENT_DESC = 'Indentation used for TypeScript interfaces'; - public const INDENT_STYLE_KEY = 'style'; - public const INDENT_STYLE_DEFAULT = Indent::STYLE_SPACE; - public const INDENT_STYLE_DESC = 'Indent style used for TypeScript interfaces'; - public const INDENT_STYLE_VALID_VALUES = [Indent::STYLE_SPACE, Indent::STYLE_TAB]; - public const INDENT_COUNT_KEY = 'count'; - public const INDENT_COUNT_DEFAULT = 2; - public const INDENT_COUNT_DESC = 'Number of indent style characters per indent'; - - public const QUOTES_KEY = 'quotes'; - public const QUOTES_DESC = 'Quote style used for strings in TypeScript interfaces'; - public const QUOTES_DEFAULT = Quotes::STYLE_SINGLE; - public const QUOTES_VALID_VALUES = [Quotes::STYLE_DOUBLE, Quotes::STYLE_SINGLE]; - - public const SORT_STRATEGIES_KEY = 'sort_strategies'; - public const SORT_STRATEGIES_DEFAULT = [ + final public const OUTPUT_DIR_KEY = 'output_dir'; + final public const OUTPUT_DIR_DEFAULT = 'assets/ts/types/php-to-ts'; + final public const OUTPUT_DIR_DESC = 'Directory in which to dump TypeScript interfaces'; + + final public const INPUT_DIR_KEY = 'input_dir'; + final public const INPUT_DIR_DEFAULT = 'src/Model'; + final public const INPUT_DIR_DESC = 'Directory in which to look for models to include'; + + final public const FILE_TYPE_KEY = 'file_type'; + final public const FILE_TYPE_DEFAULT = FileType::TYPE_MODULE; + final public const FILE_TYPE_DESC = 'File type to use for TypeScript interfaces'; + final public const FILE_TYPE_VALID_VALUES = [FileType::TYPE_DECLARATION, FileType::TYPE_MODULE]; + + final public const TYPE_DEFINITION_TYPE_KEY = 'type_definition_type'; + final public const TYPE_DEFINITION_TYPE_DEFAULT = TypeDefinitionType::TYPE_INTERFACE; + final public const TYPE_DEFINITION_TYPE_DESC = 'Type definition type to use for TypeScript interfaces'; + final public const TYPE_DEFINITION_TYPE_VALID_VALUES = [TypeDefinitionType::TYPE_INTERFACE, TypeDefinitionType::TYPE_TYPE_ALIAS]; + + final public const INDENT_KEY = 'indent'; + final public const INDENT_DESC = 'Indentation used for TypeScript interfaces'; + final public const INDENT_STYLE_KEY = 'style'; + final public const INDENT_STYLE_DEFAULT = Indent::STYLE_SPACE; + final public const INDENT_STYLE_DESC = 'Indent style used for TypeScript interfaces'; + final public const INDENT_STYLE_VALID_VALUES = [Indent::STYLE_SPACE, Indent::STYLE_TAB]; + final public const INDENT_COUNT_KEY = 'count'; + final public const INDENT_COUNT_DEFAULT = 2; + final public const INDENT_COUNT_DESC = 'Number of indent style characters per indent'; + + final public const QUOTES_KEY = 'quotes'; + final public const QUOTES_DESC = 'Quote style used for strings in TypeScript interfaces'; + final public const QUOTES_DEFAULT = Quotes::STYLE_SINGLE; + final public const QUOTES_VALID_VALUES = [Quotes::STYLE_DOUBLE, Quotes::STYLE_SINGLE]; + + final public const SORT_STRATEGIES_KEY = 'sort_strategies'; + final public const SORT_STRATEGIES_DEFAULT = [ AlphabeticalAsc::class, ConstructorFirst::class, ReadonlyFirst::class, ]; - public const SORT_STRATEGIES_DESC = 'Class names of sort strategies used for TypeScript properties'; + final public const SORT_STRATEGIES_DESC = 'Class names of sort strategies used for TypeScript properties'; - public const FILE_NAME_STRATEGY_KEY = 'file_name_strategy'; - public const FILE_NAME_STRATEGY_DEFAULT = KebabCase::class; - public const FILE_NAME_STRATEGY_DESC = 'Class name of file name strategies used for TypeScript files'; + final public const FILE_NAME_STRATEGY_KEY = 'file_name_strategy'; + final public const FILE_NAME_STRATEGY_DEFAULT = KebabCase::class; + final public const FILE_NAME_STRATEGY_DESC = 'Class name of file name strategies used for TypeScript files'; public function getInputDir(): ?string; diff --git a/src/Model/Config/FileType.php b/src/Model/Config/FileType.php index b0b59de..4a1df9e 100644 --- a/src/Model/Config/FileType.php +++ b/src/Model/Config/FileType.php @@ -4,8 +4,10 @@ namespace Brainshaker95\PhpToTsBundle\Model\Config; -abstract class FileType +final class FileType { public const TYPE_DECLARATION = 'declaration'; public const TYPE_MODULE = 'module'; + + private function __construct() {} } diff --git a/src/Model/Config/TypeDefinitionType.php b/src/Model/Config/TypeDefinitionType.php index 4d7af4d..382e67c 100644 --- a/src/Model/Config/TypeDefinitionType.php +++ b/src/Model/Config/TypeDefinitionType.php @@ -4,8 +4,10 @@ namespace Brainshaker95\PhpToTsBundle\Model\Config; -abstract class TypeDefinitionType +final class TypeDefinitionType { public const TYPE_INTERFACE = 'interface'; public const TYPE_TYPE_ALIAS = 'type'; + + private function __construct() {} } diff --git a/src/Tool/Assert.php b/src/Tool/Assert.php index 53a4d07..e57dd1e 100644 --- a/src/Tool/Assert.php +++ b/src/Tool/Assert.php @@ -23,7 +23,7 @@ /** * @internal */ -abstract class Assert +final class Assert { private function __construct() {} @@ -32,7 +32,7 @@ private function __construct() {} * * @return non-empty-string */ - final public static function nonEmptyStringNonNullable(mixed $value): string + public static function nonEmptyStringNonNullable(mixed $value): string { if (!is_string($value) || !$value) { throw new AssertionFailedException(sprintf( @@ -49,7 +49,7 @@ final public static function nonEmptyStringNonNullable(mixed $value): string * * @return ?non-empty-string */ - final public static function nonEmptyStringNullable(mixed $value): ?string + public static function nonEmptyStringNullable(mixed $value): ?string { if ($value === null) { return $value; @@ -63,7 +63,7 @@ final public static function nonEmptyStringNullable(mixed $value): ?string * * @return int<0,max> */ - final public static function nonNegativeIntegerNonNullable(mixed $value): int + public static function nonNegativeIntegerNonNullable(mixed $value): int { $intval = is_numeric($value) ? (int) $value : -1; @@ -82,7 +82,7 @@ final public static function nonNegativeIntegerNonNullable(mixed $value): int * * @return ?int<0,max> */ - final public static function nonNegativeIntegerNullable(mixed $value): ?int + public static function nonNegativeIntegerNullable(mixed $value): ?int { if ($value === null) { return $value; @@ -96,7 +96,7 @@ final public static function nonNegativeIntegerNullable(mixed $value): ?int * * @return non-empty-string[] */ - final public static function nonEmptyStringArrayNonNullable(mixed $value): array + public static function nonEmptyStringArrayNonNullable(mixed $value): array { if (!is_array($value) || count(array_filter($value, static fn (mixed $val) => !is_string($val) || !$val))) { @@ -114,7 +114,7 @@ final public static function nonEmptyStringArrayNonNullable(mixed $value): array * * @return ?non-empty-string[] */ - final public static function nonEmptyStringArrayNullable(mixed $value): ?array + public static function nonEmptyStringArrayNullable(mixed $value): ?array { if ($value === null) { return $value; @@ -132,7 +132,7 @@ final public static function nonEmptyStringArrayNullable(mixed $value): ?array * * @return value-of */ - final public static function inStringArrayNonNullable(mixed $value, array $allowedStrings): string + public static function inStringArrayNonNullable(mixed $value, array $allowedStrings): string { if (!is_string($value) || !in_array($value, $allowedStrings, true)) { throw new AssertionFailedException(sprintf( @@ -154,7 +154,7 @@ final public static function inStringArrayNonNullable(mixed $value, array $allow * * @return ?value-of */ - final public static function inStringArrayNullable(mixed $value, array $allowedStrings): ?string + public static function inStringArrayNullable(mixed $value, array $allowedStrings): ?string { if ($value === null) { return $value; @@ -172,7 +172,7 @@ final public static function inStringArrayNullable(mixed $value, array $allowedS * * @return T */ - final public static function instanceOf(object $value, string $class): object + public static function instanceOf(object $value, string $class): object { if (!$value instanceof $class) { throw new AssertionFailedException(sprintf( @@ -194,7 +194,7 @@ final public static function instanceOf(object $value, string $class): object * * @return class-string */ - final public static function interfaceClassStringNonNullable(mixed $value, string $class): string + public static function interfaceClassStringNonNullable(mixed $value, string $class): string { if (!is_string($value) || !is_a($value, $class, true) @@ -218,7 +218,7 @@ final public static function interfaceClassStringNonNullable(mixed $value, strin * * @return ?class-string */ - final public static function interfaceClassStringNullable(mixed $value, string $class): ?string + public static function interfaceClassStringNullable(mixed $value, string $class): ?string { if ($value === null) { return $value; @@ -236,7 +236,7 @@ final public static function interfaceClassStringNullable(mixed $value, string $ * * @return class-string[] */ - final public static function interfaceClassStringArrayNonNullable(mixed $value, string $class): array + public static function interfaceClassStringArrayNonNullable(mixed $value, string $class): array { return array_map( static fn (string $val) => self::interfaceClassStringNonNullable($val, $class), @@ -253,7 +253,7 @@ final public static function interfaceClassStringArrayNonNullable(mixed $value, * * @return ?class-string[] */ - final public static function interfaceClassStringArrayNullable(mixed $value, string $class): ?array + public static function interfaceClassStringArrayNullable(mixed $value, string $class): ?array { if ($value === null) { return $value; @@ -265,7 +265,7 @@ final public static function interfaceClassStringArrayNullable(mixed $value, str /** * @param object|class-string $class */ - final public static function existingClassAttribute(object|string $class, string $attribute): void + public static function existingClassAttribute(object|string $class, string $attribute): void { if (!Attribute::existsOnClass($attribute, $class)) { throw new AssertionFailedException(sprintf( diff --git a/src/Tool/Attribute.php b/src/Tool/Attribute.php index e2dbc33..761e2bb 100644 --- a/src/Tool/Attribute.php +++ b/src/Tool/Attribute.php @@ -14,14 +14,14 @@ /** * @internal */ -abstract class Attribute +final class Attribute { private function __construct() {} /** * @param object|class-string $class */ - final public static function existsOnClass(string $attribute, object|string $class): bool + public static function existsOnClass(string $attribute, object|string $class): bool { return (is_string($class) && !class_exists($class)) ? false @@ -31,7 +31,7 @@ final public static function existsOnClass(string $attribute, object|string $cla /** * @param object|class-string $class */ - final public static function existsOnProperty(string $attribute, object|string $class, string $propertyName): bool + public static function existsOnProperty(string $attribute, object|string $class, string $propertyName): bool { if (is_string($class) && !class_exists($class)) { return false; diff --git a/src/Tool/Converter.php b/src/Tool/Converter.php index 2740fb1..f937b1c 100644 --- a/src/Tool/Converter.php +++ b/src/Tool/Converter.php @@ -59,7 +59,7 @@ /** * @internal */ -abstract class Converter +final class Converter { public const TYPE_ARRAY = 'array'; public const TYPE_ARRAY_KEY = 'array-key'; @@ -138,7 +138,7 @@ abstract class Converter private function __construct() {} - final public static function toInterface(Class_ $node, bool $isReadonly): TsInterface + public static function toInterface(Class_ $node, bool $isReadonly): TsInterface { $name = $node->name?->name; @@ -170,7 +170,7 @@ final public static function toInterface(Class_ $node, bool $isReadonly): TsInte /** * @throws InvalidEnumException */ - final public static function toEnum(Enum_ $node): TsEnum + public static function toEnum(Enum_ $node): TsEnum { $name = $node->name?->name; @@ -209,7 +209,7 @@ final public static function toEnum(Enum_ $node): TsEnum /** * @throws InvalidPropertyException */ - final public static function toProperty( + public static function toProperty( Param|Property|EnumCase $property, bool $isReadonly, ?Doc $docComment, @@ -275,7 +275,7 @@ classIdentifiers: $classIdentifiers, /** * @param Node[] $nodes */ - final public static function applyIndentAndQuotes( + public static function applyIndentAndQuotes( array $nodes, Indent $indent, Quotes $quotes, @@ -326,7 +326,7 @@ final public static function applyIndentAndQuotes( /** * @return Node[] */ - final public static function getNextLevelNodes(Node $node): array + public static function getNextLevelNodes(Node $node): array { return match (true) { default => [], @@ -343,7 +343,7 @@ final public static function getNextLevelNodes(Node $node): array }; } - final public static function getClassIdentifierNode(Node $node): ?IdentifierTypeNode + public static function getClassIdentifierNode(Node $node): ?IdentifierTypeNode { return match (true) { default => null, diff --git a/src/Tool/PhpStan.php b/src/Tool/PhpStan.php index a2db250..a10a260 100644 --- a/src/Tool/PhpStan.php +++ b/src/Tool/PhpStan.php @@ -41,12 +41,12 @@ /** * @internal */ -abstract class PhpStan +final class PhpStan { /** * @var array,class-string> */ - public const NODE_CLASS_MAP = [ + private const NODE_CLASS_MAP = [ PHPStanConstExpr\ConstExprFalseNode::class => ConstExpr\ConstExprFalseNode::class, PHPStanConstExpr\ConstExprFloatNode::class => ConstExpr\ConstExprFloatNode::class, PHPStanConstExpr\ConstExprIntegerNode::class => ConstExpr\ConstExprIntegerNode::class, @@ -73,7 +73,7 @@ abstract class PhpStan private function __construct() {} - final public static function toNode(PHPStanNode $node): Node + public static function toNode(PHPStanNode $node): Node { $nodeClass = self::NODE_CLASS_MAP[$node::class] ?? null; @@ -87,7 +87,7 @@ final public static function toNode(PHPStanNode $node): Node return $nodeClass::fromPhpStan($node); } - final public static function getDocNode(Doc $docComment): PhpDocNode + public static function getDocNode(Doc $docComment): PhpDocNode { self::$lexer ??= new Lexer(); self::$constExprParser ??= new ConstExprParser(); @@ -98,7 +98,7 @@ final public static function getDocNode(Doc $docComment): PhpDocNode )); } - final public static function getParamNode(PhpDocNode $docNode, string $name): ParamTagValueNode|TypelessParamTagValueNode|null + public static function getParamNode(PhpDocNode $docNode, string $name): ParamTagValueNode|TypelessParamTagValueNode|null { $values = [ ...$docNode->getParamTagValues('@param'), @@ -115,7 +115,7 @@ final public static function getParamNode(PhpDocNode $docNode, string $name): Pa )) ?: null; } - final public static function getVarNode(PhpDocNode $docNode): ?VarTagValueNode + public static function getVarNode(PhpDocNode $docNode): ?VarTagValueNode { $values = [ ...$docNode->getVarTagValues('@var'), @@ -126,7 +126,7 @@ final public static function getVarNode(PhpDocNode $docNode): ?VarTagValueNode return current($values) ?: null; } - final public static function getDeprecatedNode(PhpDocNode $docNode): ?DeprecatedTagValueNode + public static function getDeprecatedNode(PhpDocNode $docNode): ?DeprecatedTagValueNode { return current($docNode->getDeprecatedTagValues()) ?: null; } @@ -134,7 +134,7 @@ final public static function getDeprecatedNode(PhpDocNode $docNode): ?Deprecated /** * @return TemplateTagValueNode[] */ - final public static function getTemplateNodes(PhpDocNode $docNode): array + public static function getTemplateNodes(PhpDocNode $docNode): array { return [ ...$docNode->getTemplateTagValues('@template'), @@ -146,7 +146,7 @@ final public static function getTemplateNodes(PhpDocNode $docNode): array /** * @return PhpDocTextNode[] */ - final public static function getTextNodes(PhpDocNode $docNode): array + public static function getTextNodes(PhpDocNode $docNode): array { return array_filter( $docNode->children, @@ -157,7 +157,7 @@ final public static function getTextNodes(PhpDocNode $docNode): array /** * @param PhpDocTextNode[] $textNodes */ - final public static function textNodesToString(array $textNodes): string + public static function textNodesToString(array $textNodes): string { return implode("\n", array_map( static fn (PhpDocTextNode $textNode) => $textNode->text, @@ -165,7 +165,7 @@ final public static function textNodesToString(array $textNodes): string )); } - final public static function phpValueToTsType( + public static function phpValueToTsType( mixed $value, Indent $indent = new Indent(), Quotes $quotes = new Quotes(), @@ -191,7 +191,7 @@ final public static function phpValueToTsType( return $shapeNode->toString(); } - final public static function phpValueToNode(mixed $value): Node + public static function phpValueToNode(mixed $value): Node { $docComment = new Doc('/** @var ' . Str::displayType($value) . ' */'); $docNode = self::getDocNode($docComment); diff --git a/tests/DumpCommandTest.php b/tests/DumpCommandTest.php index 1bc5839..b0dd4c5 100644 --- a/tests/DumpCommandTest.php +++ b/tests/DumpCommandTest.php @@ -4,7 +4,6 @@ namespace App\Tests; -use Brainshaker95\PhpToTsBundle\Command\DumpCommand; use Brainshaker95\PhpToTsBundle\Interface\Config as C; use Brainshaker95\PhpToTsBundle\Model\Config\FileNameStrategy\PascalCase; use Brainshaker95\PhpToTsBundle\Model\Config\FileNameStrategy\SnakeCase; @@ -40,6 +39,9 @@ */ final class DumpCommandTest extends KernelTestCase { + private const INDENT_STYLE_KEY = C::INDENT_KEY . '-' . C::INDENT_STYLE_KEY; + private const INDENT_COUNT_KEY = C::INDENT_KEY . '-' . C::INDENT_COUNT_KEY; + private Filesystem $filesystem; private string $inputDir; @@ -80,15 +82,15 @@ public function testDumpDirWithAllOptionsChanged(): void { $this->assertCommandSuccess( code: self::runCommand('phptots:dump:dir', [ - Str::toKebab(C::INPUT_DIR_KEY) => $this->inputDir, - '--' . Str::toKebab(C::OUTPUT_DIR_KEY) => $this->outputDir . '/SubDir', - '--' . Str::toKebab(C::FILE_TYPE_KEY) => FileType::TYPE_DECLARATION, - '--' . Str::toKebab(C::TYPE_DEFINITION_TYPE_KEY) => TypeDefinitionType::TYPE_TYPE_ALIAS, - '--' . Str::toKebab(DumpCommand::INDENT_STYLE_KEY) => Indent::STYLE_TAB, - '--' . Str::toKebab(DumpCommand::INDENT_COUNT_KEY) => 3, - '--' . Str::toKebab(C::QUOTES_KEY) => Quotes::STYLE_DOUBLE, - '--' . Str::toKebab(C::SORT_STRATEGIES_KEY) => [AlphabeticalDesc::class], - '--' . Str::toKebab(C::FILE_NAME_STRATEGY_KEY) => SnakeCase::class, + Str::toKebab(C::INPUT_DIR_KEY) => $this->inputDir, + '--' . Str::toKebab(C::OUTPUT_DIR_KEY) => $this->outputDir . '/SubDir', + '--' . Str::toKebab(C::FILE_TYPE_KEY) => FileType::TYPE_DECLARATION, + '--' . Str::toKebab(C::TYPE_DEFINITION_TYPE_KEY) => TypeDefinitionType::TYPE_TYPE_ALIAS, + '--' . Str::toKebab(self::INDENT_STYLE_KEY) => Indent::STYLE_TAB, + '--' . Str::toKebab(self::INDENT_COUNT_KEY) => 3, + '--' . Str::toKebab(C::QUOTES_KEY) => Quotes::STYLE_DOUBLE, + '--' . Str::toKebab(C::SORT_STRATEGIES_KEY) => [AlphabeticalDesc::class], + '--' . Str::toKebab(C::FILE_NAME_STRATEGY_KEY) => SnakeCase::class, ], isVerbose: true), outputDir: $this->outputDir . '/SubDir', expectedFileCount: 3, @@ -99,8 +101,8 @@ public function testDumpDirWithSomeOptionsChanged(): void { $this->assertCommandSuccess( code: self::runCommand('phptots:dump:dir', [ - '--' . Str::toKebab(DumpCommand::INDENT_COUNT_KEY) => 3, - '--' . Str::toKebab(C::FILE_NAME_STRATEGY_KEY) => PascalCase::class, + '--' . Str::toKebab(self::INDENT_COUNT_KEY) => 3, + '--' . Str::toKebab(C::FILE_NAME_STRATEGY_KEY) => PascalCase::class, ]), outputDir: $this->outputDir, expectedFileCount: 3, @@ -159,15 +161,15 @@ public function testDumpFilesWithAllOptionsChanged(): void { $this->assertCommandSuccess( code: self::runCommand('phptots:dump:files', [ - 'input-files' => [$this->inputDir], - '--' . Str::toKebab(C::OUTPUT_DIR_KEY) => $this->outputDir . '/SubDir', - '--' . Str::toKebab(C::FILE_TYPE_KEY) => FileType::TYPE_DECLARATION, - '--' . Str::toKebab(C::TYPE_DEFINITION_TYPE_KEY) => TypeDefinitionType::TYPE_TYPE_ALIAS, - '--' . Str::toKebab(DumpCommand::INDENT_STYLE_KEY) => Indent::STYLE_TAB, - '--' . Str::toKebab(DumpCommand::INDENT_COUNT_KEY) => 3, - '--' . Str::toKebab(C::QUOTES_KEY) => Quotes::STYLE_DOUBLE, - '--' . Str::toKebab(C::SORT_STRATEGIES_KEY) => [AlphabeticalDesc::class], - '--' . Str::toKebab(C::FILE_NAME_STRATEGY_KEY) => SnakeCase::class, + 'input-files' => [$this->inputDir], + '--' . Str::toKebab(C::OUTPUT_DIR_KEY) => $this->outputDir . '/SubDir', + '--' . Str::toKebab(C::FILE_TYPE_KEY) => FileType::TYPE_DECLARATION, + '--' . Str::toKebab(C::TYPE_DEFINITION_TYPE_KEY) => TypeDefinitionType::TYPE_TYPE_ALIAS, + '--' . Str::toKebab(self::INDENT_STYLE_KEY) => Indent::STYLE_TAB, + '--' . Str::toKebab(self::INDENT_COUNT_KEY) => 3, + '--' . Str::toKebab(C::QUOTES_KEY) => Quotes::STYLE_DOUBLE, + '--' . Str::toKebab(C::SORT_STRATEGIES_KEY) => [AlphabeticalDesc::class], + '--' . Str::toKebab(C::FILE_NAME_STRATEGY_KEY) => SnakeCase::class, ], isVerbose: true), outputDir: $this->outputDir . '/SubDir', expectedFileCount: 3, @@ -178,9 +180,9 @@ public function testDumpFilesWithSomeOptionsChanged(): void { $this->assertCommandSuccess( code: self::runCommand('phptots:dump:files', [ - 'input-files' => [$this->inputDir], - '--' . Str::toKebab(DumpCommand::INDENT_COUNT_KEY) => 3, - '--' . Str::toKebab(C::FILE_NAME_STRATEGY_KEY) => PascalCase::class, + 'input-files' => [$this->inputDir], + '--' . Str::toKebab(self::INDENT_COUNT_KEY) => 3, + '--' . Str::toKebab(C::FILE_NAME_STRATEGY_KEY) => PascalCase::class, ]), outputDir: $this->outputDir, expectedFileCount: 3, @@ -211,15 +213,15 @@ public function testDumpFileWithAllOptionsChanged(): void { $this->assertCommandSuccess( code: self::runCommand('phptots:dump:file', [ - 'input-file' => $this->inputDir . '/SubDir/GenericTypes.php', - '--' . Str::toKebab(C::OUTPUT_DIR_KEY) => $this->outputDir . '/SubDir', - '--' . Str::toKebab(C::FILE_TYPE_KEY) => FileType::TYPE_DECLARATION, - '--' . Str::toKebab(C::TYPE_DEFINITION_TYPE_KEY) => TypeDefinitionType::TYPE_TYPE_ALIAS, - '--' . Str::toKebab(DumpCommand::INDENT_STYLE_KEY) => Indent::STYLE_TAB, - '--' . Str::toKebab(DumpCommand::INDENT_COUNT_KEY) => 3, - '--' . Str::toKebab(C::QUOTES_KEY) => Quotes::STYLE_DOUBLE, - '--' . Str::toKebab(C::SORT_STRATEGIES_KEY) => [AlphabeticalDesc::class], - '--' . Str::toKebab(C::FILE_NAME_STRATEGY_KEY) => SnakeCase::class, + 'input-file' => $this->inputDir . '/SubDir/GenericTypes.php', + '--' . Str::toKebab(C::OUTPUT_DIR_KEY) => $this->outputDir . '/SubDir', + '--' . Str::toKebab(C::FILE_TYPE_KEY) => FileType::TYPE_DECLARATION, + '--' . Str::toKebab(C::TYPE_DEFINITION_TYPE_KEY) => TypeDefinitionType::TYPE_TYPE_ALIAS, + '--' . Str::toKebab(self::INDENT_STYLE_KEY) => Indent::STYLE_TAB, + '--' . Str::toKebab(self::INDENT_COUNT_KEY) => 3, + '--' . Str::toKebab(C::QUOTES_KEY) => Quotes::STYLE_DOUBLE, + '--' . Str::toKebab(C::SORT_STRATEGIES_KEY) => [AlphabeticalDesc::class], + '--' . Str::toKebab(C::FILE_NAME_STRATEGY_KEY) => SnakeCase::class, ], isVerbose: true), outputDir: $this->outputDir . '/SubDir', expectedFileCount: 1, @@ -230,9 +232,9 @@ public function testDumpFileWithSomeOptionsChanged(): void { $this->assertCommandSuccess( code: self::runCommand('phptots:dump:file', [ - 'input-file' => $this->inputDir . '/NativeTypes.php', - '--' . Str::toKebab(DumpCommand::INDENT_COUNT_KEY) => 3, - '--' . Str::toKebab(C::FILE_NAME_STRATEGY_KEY) => PascalCase::class, + 'input-file' => $this->inputDir . '/NativeTypes.php', + '--' . Str::toKebab(self::INDENT_COUNT_KEY) => 3, + '--' . Str::toKebab(C::FILE_NAME_STRATEGY_KEY) => PascalCase::class, ]), outputDir: $this->outputDir, expectedFileCount: 1, From ac6925f0a1fa3cd3240baf730ea8700a74d0795c Mon Sep 17 00:00:00 2001 From: brainshaker Date: Wed, 18 Oct 2023 21:45:57 +0200 Subject: [PATCH 2/6] refactor(ast): use TsProperty constants wherever possible --- src/Model/Ast/ConstExpr/ConstExprFalseNode.php | 3 ++- src/Model/Ast/ConstExpr/ConstExprNullNode.php | 3 ++- src/Model/Ast/ConstExpr/ConstExprTrueNode.php | 3 ++- src/Model/Ast/Type/NullableTypeNode.php | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Model/Ast/ConstExpr/ConstExprFalseNode.php b/src/Model/Ast/ConstExpr/ConstExprFalseNode.php index 1ba54cb..eb53bcf 100644 --- a/src/Model/Ast/ConstExpr/ConstExprFalseNode.php +++ b/src/Model/Ast/ConstExpr/ConstExprFalseNode.php @@ -5,6 +5,7 @@ namespace Brainshaker95\PhpToTsBundle\Model\Ast\ConstExpr; use Brainshaker95\PhpToTsBundle\Interface\Node; +use Brainshaker95\PhpToTsBundle\Model\TsProperty; use Brainshaker95\PhpToTsBundle\Tool\Assert; use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprFalseNode as PHPStanConstExprFalseNode; use PHPStan\PhpDocParser\Ast\Node as PHPStanNode; @@ -21,7 +22,7 @@ public function __toString(): string public function toString(): string { - return 'false'; + return TsProperty::TYPE_FALSE; } public static function fromPhpStan(PHPStanNode $node): self diff --git a/src/Model/Ast/ConstExpr/ConstExprNullNode.php b/src/Model/Ast/ConstExpr/ConstExprNullNode.php index d473e50..51c677a 100644 --- a/src/Model/Ast/ConstExpr/ConstExprNullNode.php +++ b/src/Model/Ast/ConstExpr/ConstExprNullNode.php @@ -5,6 +5,7 @@ namespace Brainshaker95\PhpToTsBundle\Model\Ast\ConstExpr; use Brainshaker95\PhpToTsBundle\Interface\Node; +use Brainshaker95\PhpToTsBundle\Model\TsProperty; use Brainshaker95\PhpToTsBundle\Tool\Assert; use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNullNode as PHPStanConstExprNullNode; use PHPStan\PhpDocParser\Ast\Node as PHPStanNode; @@ -21,7 +22,7 @@ public function __toString(): string public function toString(): string { - return 'null'; + return TsProperty::TYPE_NULL; } public static function fromPhpStan(PHPStanNode $node): self diff --git a/src/Model/Ast/ConstExpr/ConstExprTrueNode.php b/src/Model/Ast/ConstExpr/ConstExprTrueNode.php index c6989ad..55aa266 100644 --- a/src/Model/Ast/ConstExpr/ConstExprTrueNode.php +++ b/src/Model/Ast/ConstExpr/ConstExprTrueNode.php @@ -5,6 +5,7 @@ namespace Brainshaker95\PhpToTsBundle\Model\Ast\ConstExpr; use Brainshaker95\PhpToTsBundle\Interface\Node; +use Brainshaker95\PhpToTsBundle\Model\TsProperty; use Brainshaker95\PhpToTsBundle\Tool\Assert; use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprTrueNode as PHPStanConstExprTrueNode; use PHPStan\PhpDocParser\Ast\Node as PHPStanNode; @@ -21,7 +22,7 @@ public function __toString(): string public function toString(): string { - return 'true'; + return TsProperty::TYPE_TRUE; } public static function fromPhpStan(PHPStanNode $node): self diff --git a/src/Model/Ast/Type/NullableTypeNode.php b/src/Model/Ast/Type/NullableTypeNode.php index 4e85821..c290954 100644 --- a/src/Model/Ast/Type/NullableTypeNode.php +++ b/src/Model/Ast/Type/NullableTypeNode.php @@ -5,6 +5,7 @@ namespace Brainshaker95\PhpToTsBundle\Model\Ast\Type; use Brainshaker95\PhpToTsBundle\Interface\Node; +use Brainshaker95\PhpToTsBundle\Model\TsProperty; use Brainshaker95\PhpToTsBundle\Tool\Assert; use Brainshaker95\PhpToTsBundle\Tool\PhpStan; use PHPStan\PhpDocParser\Ast\Node as PHPStanNode; @@ -26,7 +27,7 @@ public function __toString(): string public function toString(): string { - return '(' . $this->type . ' | null)'; + return '(' . $this->type . ' | ' . TsProperty::TYPE_NULL . ')'; } public static function fromPhpStan(PHPStanNode $node): self From 53a026f03578cb193b5b62a1ed92ff22c6642e4c Mon Sep 17 00:00:00 2001 From: brainshaker Date: Wed, 18 Oct 2023 21:47:33 +0200 Subject: [PATCH 3/6] chore(dependencies): update phpstan --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 6f9b91e..fe435dd 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ ], "require-dev": { "friendsofphp/php-cs-fixer": "3.35.1", - "phpstan/phpstan": "1.10.38", + "phpstan/phpstan": "1.10.39", "phpstan/phpstan-strict-rules": "1.5.1", "symplify/phpstan-rules": "12.3.1", "phpunit/phpunit": "10.4.1", From 7703f36f63ca4fad53db6428a58d5322c7ad3ef1 Mon Sep 17 00:00:00 2001 From: brainshaker Date: Wed, 3 Jan 2024 21:54:07 +0100 Subject: [PATCH 4/6] chore(deprecations): implement 'getSupportedTypes' in EnumNormalizer and prepare types for symfony 6.3 --- src/Serializer/Normalizer/EnumNormalizer.php | 34 ++++++++++++++------ 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/Serializer/Normalizer/EnumNormalizer.php b/src/Serializer/Normalizer/EnumNormalizer.php index 32b9f2c..87708f6 100644 --- a/src/Serializer/Normalizer/EnumNormalizer.php +++ b/src/Serializer/Normalizer/EnumNormalizer.php @@ -4,6 +4,7 @@ namespace Brainshaker95\PhpToTsBundle\Serializer\Normalizer; +use ArrayObject; use BackedEnum; use Brainshaker95\PhpToTsBundle\Attribute\AsTypeScriptable; use Brainshaker95\PhpToTsBundle\Tool\Attribute; @@ -17,33 +18,48 @@ final class EnumNormalizer implements NormalizerInterface { /** * @param mixed[] $context + * + * @return array|string|int|float|bool|ArrayObject|null */ public function normalize( - mixed $enum, + mixed $data, ?string $format = null, array $context = [], - ): int|string { - if (!is_object($enum)) { + ): array|string|int|float|bool|ArrayObject|null { + if (!is_object($data)) { throw new InvalidArgumentException(sprintf( - 'Expected paramteter 1 ($enum) to be of type "object" but got "%s".', - get_debug_type($enum), + 'Expected paramteter 1 ($data) to be of type "object" but got "%s".', + get_debug_type($data), )); } - if (!$enum instanceof BackedEnum) { + if (!$data instanceof BackedEnum) { throw new InvalidArgumentException(sprintf( 'Expected object to be an instance of "%s". Given instance was of class "%s".', BackedEnum::class, - $enum::class, + $data::class, )); } - return $enum->value; + return $data->value; } - public function supportsNormalization($data, ?string $format = null): bool + /** + * @param mixed[] $context + */ + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool { return $data instanceof BackedEnum && Attribute::existsOnClass(AsTypeScriptable::class, $data); } + + /** + * @return array + */ + public function getSupportedTypes(?string $format): array + { + return [ + BackedEnum::class => true, + ]; + } } From 6246c919253d4c6d4cc9b71daf59500b38a94cc4 Mon Sep 17 00:00:00 2001 From: brainshaker Date: Wed, 3 Jan 2024 22:11:35 +0100 Subject: [PATCH 5/6] chore(dependencies): update dev dependencies --- .php-cs-fixer.dist.php | 1 + composer.json | 14 +++++++------- phpstan.neon | 4 ---- src/Service/Visitor.php | 2 +- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 15dd5a0..aa2f9d2 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -55,6 +55,7 @@ 'strict_comparison' => true, 'strict_param' => true, 'trailing_comma_in_multiline' => ['elements' => ['arrays', 'arguments', 'match', 'parameters']], + 'unary_operator_spaces' => ['only_dec_inc' => true], 'yoda_style' => ['equal' => false, 'identical' => false, 'less_and_greater' => false], ]) ; diff --git a/composer.json b/composer.json index fe435dd..488d060 100644 --- a/composer.json +++ b/composer.json @@ -16,13 +16,13 @@ } ], "require-dev": { - "friendsofphp/php-cs-fixer": "3.35.1", - "phpstan/phpstan": "1.10.39", - "phpstan/phpstan-strict-rules": "1.5.1", - "symplify/phpstan-rules": "12.3.1", - "phpunit/phpunit": "10.4.1", - "symfony/framework-bundle": "6.3.5", - "symfony/yaml": "6.3.3", + "friendsofphp/php-cs-fixer": "3.45.0", + "phpstan/phpstan": "1.10.50", + "phpstan/phpstan-strict-rules": "1.5.2", + "symplify/phpstan-rules": "12.4.3", + "phpunit/phpunit": "10.5.5", + "symfony/framework-bundle": "6.4.2", + "symfony/yaml": "6.4.0", "cweagans/composer-patches": "1.7.3" }, "require": { diff --git a/phpstan.neon b/phpstan.neon index 2964695..c1a87f5 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -18,7 +18,6 @@ rules: - Symplify\PHPStanRules\Rules\CheckClassNamespaceFollowPsr4Rule - Symplify\PHPStanRules\Rules\CheckTypehintCallerTypeRule - Symplify\PHPStanRules\Rules\Complexity\ForbiddenSameNamedNewInstanceRule - - Symplify\PHPStanRules\Rules\Complexity\NoDuplicatedTraitMethodNameRule - Symplify\PHPStanRules\Rules\Domain\RequireAttributeNamespaceRule - Symplify\PHPStanRules\Rules\Domain\RequireExceptionNamespaceRule - Symplify\PHPStanRules\Rules\Enum\RequireUniqueEnumConstantRule @@ -31,17 +30,14 @@ rules: - Symplify\PHPStanRules\Rules\NarrowType\NarrowPublicClassMethodParamTypeByCallerTypeRule - Symplify\PHPStanRules\Rules\NoAbstractMethodRule - Symplify\PHPStanRules\Rules\NoArrayAccessOnObjectRule - - Symplify\PHPStanRules\Rules\NoConstructorInTestRule - Symplify\PHPStanRules\Rules\NoDynamicNameRule - Symplify\PHPStanRules\Rules\NoEmptyClassRule - Symplify\PHPStanRules\Rules\NoInlineStringRegexRule - Symplify\PHPStanRules\Rules\NoIssetOnObjectRule - Symplify\PHPStanRules\Rules\NoMissingDirPathRule - Symplify\PHPStanRules\Rules\NoNullableArrayPropertyRule - - Symplify\PHPStanRules\Rules\NoParentMethodCallOnNoOverrideProcessRule - Symplify\PHPStanRules\Rules\NoReferenceRule - Symplify\PHPStanRules\Rules\NoVoidGetterMethodRule - - Symplify\PHPStanRules\Rules\PHPUnit\NoRightPHPUnitAssertScalarRule - Symplify\PHPStanRules\Rules\PreventParentMethodVisibilityOverrideRule - Symplify\PHPStanRules\Rules\RegexSuffixInRegexConstantRule - Symplify\PHPStanRules\Rules\RequireAttributeNameRule diff --git a/src/Service/Visitor.php b/src/Service/Visitor.php index 54c5497..4538f90 100644 --- a/src/Service/Visitor.php +++ b/src/Service/Visitor.php @@ -250,7 +250,7 @@ private static function getFqcn(ClassLike $node): ?string * @var ?class-string */ return $node->namespacedName - ? implode('\\', $node->namespacedName->parts) + ? implode('\\', $node->namespacedName->getParts()) : $node->name?->name; } } From 925482bf74ced8c4391101f51929f40c1eb868c4 Mon Sep 17 00:00:00 2001 From: brainshaker Date: Wed, 3 Jan 2024 22:12:07 +0100 Subject: [PATCH 6/6] chore(version): bump version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 488d060..50a10aa 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "brainshaker95/php-to-ts-bundle", "description": "Convert PHP model classes to TypeScript interfaces", - "version": "0.4.2", + "version": "0.4.3", "keywords": [ "bundle", "symfony",