diff --git a/src/Toolkit/kits/shadcn/Alert/manifest.json b/src/Toolkit/kits/shadcn/Alert/manifest.json index 7aed0768409..876b4c06230 100644 --- a/src/Toolkit/kits/shadcn/Alert/manifest.json +++ b/src/Toolkit/kits/shadcn/Alert/manifest.json @@ -6,19 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "twig/extra-bundle" - }, - { - "type": "php", - "name": "twig/html-extra", - "version": "^3.12.0" - }, - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": ["twig/extra-bundle", "twig/html-extra:^3.12.0", "tales-from-a-dev/twig-tailwind-extra"] + } } diff --git a/src/Toolkit/kits/shadcn/AlertDialog/manifest.json b/src/Toolkit/kits/shadcn/AlertDialog/manifest.json index 4333819bb77..f38a2221dd8 100644 --- a/src/Toolkit/kits/shadcn/AlertDialog/manifest.json +++ b/src/Toolkit/kits/shadcn/AlertDialog/manifest.json @@ -6,31 +6,10 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "twig/extra-bundle" - }, - { - "type": "php", - "name": "twig/html-extra", - "version": "^3.12.0" - }, - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - }, - { - "type": "npm", - "name": "el-transition" - }, - { - "type": "importmap", - "package": "el-transition" - }, - { - "type": "recipe", - "name": "Button" - } - ] + "dependencies": { + "recipe": ["Button"], + "composer": ["twig/extra-bundle", "twig/html-extra:^3.12.0", "tales-from-a-dev/twig-tailwind-extra"], + "npm": ["el-transition"], + "importmap": ["el-transition"] + } } diff --git a/src/Toolkit/kits/shadcn/AspectRatio/manifest.json b/src/Toolkit/kits/shadcn/AspectRatio/manifest.json index 9ad0bca70b3..bb2526077d6 100644 --- a/src/Toolkit/kits/shadcn/AspectRatio/manifest.json +++ b/src/Toolkit/kits/shadcn/AspectRatio/manifest.json @@ -6,10 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "twig/extra-bundle" - } - ] + "dependencies": { + "composer": ["twig/extra-bundle"] + } } diff --git a/src/Toolkit/kits/shadcn/Avatar/manifest.json b/src/Toolkit/kits/shadcn/Avatar/manifest.json index 6154e377859..b387f862861 100644 --- a/src/Toolkit/kits/shadcn/Avatar/manifest.json +++ b/src/Toolkit/kits/shadcn/Avatar/manifest.json @@ -6,10 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": ["tales-from-a-dev/twig-tailwind-extra"] + } } diff --git a/src/Toolkit/kits/shadcn/Badge/manifest.json b/src/Toolkit/kits/shadcn/Badge/manifest.json index 1791976b1ab..4777970ac73 100644 --- a/src/Toolkit/kits/shadcn/Badge/manifest.json +++ b/src/Toolkit/kits/shadcn/Badge/manifest.json @@ -6,19 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "twig/extra-bundle" - }, - { - "type": "php", - "name": "twig/html-extra", - "version": "^3.12.0" - }, - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": ["twig/extra-bundle", "twig/html-extra:^3.12.0", "tales-from-a-dev/twig-tailwind-extra"] + } } diff --git a/src/Toolkit/kits/shadcn/Breadcrumb/manifest.json b/src/Toolkit/kits/shadcn/Breadcrumb/manifest.json index 9c8a5ecae18..f1ad0193731 100644 --- a/src/Toolkit/kits/shadcn/Breadcrumb/manifest.json +++ b/src/Toolkit/kits/shadcn/Breadcrumb/manifest.json @@ -6,10 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": ["tales-from-a-dev/twig-tailwind-extra"] + } } diff --git a/src/Toolkit/kits/shadcn/Button/manifest.json b/src/Toolkit/kits/shadcn/Button/manifest.json index 6b97f83a9a4..52c9f9f26fe 100644 --- a/src/Toolkit/kits/shadcn/Button/manifest.json +++ b/src/Toolkit/kits/shadcn/Button/manifest.json @@ -6,19 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "twig/extra-bundle" - }, - { - "type": "php", - "name": "twig/html-extra", - "version": "^3.12.0" - }, - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": ["twig/extra-bundle", "twig/html-extra:^3.12.0", "tales-from-a-dev/twig-tailwind-extra"] + } } diff --git a/src/Toolkit/kits/shadcn/Card/manifest.json b/src/Toolkit/kits/shadcn/Card/manifest.json index ce24f3ced1f..f9b0864ff86 100644 --- a/src/Toolkit/kits/shadcn/Card/manifest.json +++ b/src/Toolkit/kits/shadcn/Card/manifest.json @@ -6,10 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": ["tales-from-a-dev/twig-tailwind-extra"] + } } diff --git a/src/Toolkit/kits/shadcn/Checkbox/manifest.json b/src/Toolkit/kits/shadcn/Checkbox/manifest.json index 3e36e4cc3a5..06431609f31 100644 --- a/src/Toolkit/kits/shadcn/Checkbox/manifest.json +++ b/src/Toolkit/kits/shadcn/Checkbox/manifest.json @@ -6,10 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": ["tales-from-a-dev/twig-tailwind-extra"] + } } diff --git a/src/Toolkit/kits/shadcn/Input/manifest.json b/src/Toolkit/kits/shadcn/Input/manifest.json index 37710cff064..318e9f8d1ff 100644 --- a/src/Toolkit/kits/shadcn/Input/manifest.json +++ b/src/Toolkit/kits/shadcn/Input/manifest.json @@ -6,10 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": ["tales-from-a-dev/twig-tailwind-extra"] + } } diff --git a/src/Toolkit/kits/shadcn/Label/manifest.json b/src/Toolkit/kits/shadcn/Label/manifest.json index 83947d1c9e5..c254c2d786f 100644 --- a/src/Toolkit/kits/shadcn/Label/manifest.json +++ b/src/Toolkit/kits/shadcn/Label/manifest.json @@ -6,10 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": ["tales-from-a-dev/twig-tailwind-extra"] + } } diff --git a/src/Toolkit/kits/shadcn/Pagination/manifest.json b/src/Toolkit/kits/shadcn/Pagination/manifest.json index 98daba20f12..9d074fd6b70 100644 --- a/src/Toolkit/kits/shadcn/Pagination/manifest.json +++ b/src/Toolkit/kits/shadcn/Pagination/manifest.json @@ -6,10 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": ["tales-from-a-dev/twig-tailwind-extra"] + } } diff --git a/src/Toolkit/kits/shadcn/Progress/manifest.json b/src/Toolkit/kits/shadcn/Progress/manifest.json index 07615b3d75f..25972065ea6 100644 --- a/src/Toolkit/kits/shadcn/Progress/manifest.json +++ b/src/Toolkit/kits/shadcn/Progress/manifest.json @@ -6,10 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": ["tales-from-a-dev/twig-tailwind-extra"] + } } diff --git a/src/Toolkit/kits/shadcn/Select/manifest.json b/src/Toolkit/kits/shadcn/Select/manifest.json index 273f2f91190..74c302921e0 100644 --- a/src/Toolkit/kits/shadcn/Select/manifest.json +++ b/src/Toolkit/kits/shadcn/Select/manifest.json @@ -6,10 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": ["tales-from-a-dev/twig-tailwind-extra"] + } } diff --git a/src/Toolkit/kits/shadcn/Separator/manifest.json b/src/Toolkit/kits/shadcn/Separator/manifest.json index e308fff9df9..4891eb75456 100644 --- a/src/Toolkit/kits/shadcn/Separator/manifest.json +++ b/src/Toolkit/kits/shadcn/Separator/manifest.json @@ -6,19 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "twig/extra-bundle" - }, - { - "type": "php", - "name": "twig/html-extra", - "version": "^3.12.0" - }, - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": ["twig/extra-bundle", "twig/html-extra:^3.12.0", "tales-from-a-dev/twig-tailwind-extra"] + } } diff --git a/src/Toolkit/kits/shadcn/Skeleton/manifest.json b/src/Toolkit/kits/shadcn/Skeleton/manifest.json index e873bbe0ecd..7f2779ccb97 100644 --- a/src/Toolkit/kits/shadcn/Skeleton/manifest.json +++ b/src/Toolkit/kits/shadcn/Skeleton/manifest.json @@ -6,10 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": ["tales-from-a-dev/twig-tailwind-extra"] + } } diff --git a/src/Toolkit/kits/shadcn/Switch/manifest.json b/src/Toolkit/kits/shadcn/Switch/manifest.json index 8d9649a2ce4..5e9925afe17 100644 --- a/src/Toolkit/kits/shadcn/Switch/manifest.json +++ b/src/Toolkit/kits/shadcn/Switch/manifest.json @@ -6,10 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": ["tales-from-a-dev/twig-tailwind-extra"] + } } diff --git a/src/Toolkit/kits/shadcn/Table/manifest.json b/src/Toolkit/kits/shadcn/Table/manifest.json index a7d9772a0ce..be4252f32bb 100644 --- a/src/Toolkit/kits/shadcn/Table/manifest.json +++ b/src/Toolkit/kits/shadcn/Table/manifest.json @@ -6,10 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": ["tales-from-a-dev/twig-tailwind-extra"] + } } diff --git a/src/Toolkit/kits/shadcn/Textarea/manifest.json b/src/Toolkit/kits/shadcn/Textarea/manifest.json index 3649bb01fce..498d84841c5 100644 --- a/src/Toolkit/kits/shadcn/Textarea/manifest.json +++ b/src/Toolkit/kits/shadcn/Textarea/manifest.json @@ -6,10 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": ["tales-from-a-dev/twig-tailwind-extra"] + } } diff --git a/src/Toolkit/schema-kit-recipe-v1.json b/src/Toolkit/schema-kit-recipe-v1.json index 81891bfa6c7..415a216a888 100644 --- a/src/Toolkit/schema-kit-recipe-v1.json +++ b/src/Toolkit/schema-kit-recipe-v1.json @@ -5,101 +5,54 @@ "type": "object", "required": ["name", "description"], "properties": { - "type": { - "type": "string", - "enum": ["component"] - }, "name": { "type": "string", - "description": "The name of the component" + "description": "The name of the Recipe" }, "description": { - "description": "A brief description of the component", + "description": "A brief description of the Recipe", "type": "string" }, "copy-files": { "description": "Relative files or directories to copy into the project", "type": "object" }, - "examples-dir": { - "description": "Relative path to the directory containing example files for the component, must end with a slash", - "type": "string", - "pattern": "^.+/$" - }, "dependencies": { - "description": "List of dependencies required by the component", - "type": "array", - "items": { - "oneOf": [ - { - "description": "A dependency on a PHP package", - "type": "object", - "required": ["type", "name"], - "properties": { - "type": { - "type": "string", - "enum": ["php"] - }, - "name": { - "type": "string", - "description": "Package name and optional version constraint (e.g., 'vendor/package')" - }, - "version": { - "type": "string", - "description": "Optional version constraint (e.g., '^1.0')" - } - } - }, - { - "description": "A dependency on an NPM package", - "type": "object", - "required": ["type", "name"], - "properties": { - "type": { - "type": "string", - "enum": ["npm"] - }, - "name": { - "type": "string", - "description": "Package name and optional version constraint (e.g., 'vendor/package')" - }, - "version": { - "type": "string", - "description": "Optional version constraint (e.g., '^1.0')" - } - } - }, - { - "description": "A dependency on an Importmap package", - "type": "object", - "required": ["type", "package"], - "properties": { - "type": { - "type": "string", - "enum": ["importmap"] - }, - "package": { - "type": "string", - "description": "Importmap package name (e.g., 'lodash', 'bootstrap/dist/css/bootstrap.min.css')" - } - } - }, - { - "description": "A dependency on a Recipe", - "type": "object", - "required": ["type", "name"], - "properties": { - "type": { - "type": "string", - "enum": ["recipe"] - }, - "name": { - "type": "string", - "description": "The name of the Recipe this component depends on, e.g., 'Button'" - } - } + "description": "List of dependencies required by the Recipe", + "type": "object", + "properties": { + "recipe": { + "description": "List of Recipe dependencies", + "type": "array", + "items": { + "type": "string", + "description": "The name of the Recipe this component depends on, e.g., 'Button'" + } + }, + "composer": { + "description": "List of Composer package dependencies", + "type": "array", + "items": { + "type": "string", + "description": "A dependency on a Composer package, e.g., 'twig/extra-bundle' or 'twig/html-extra:^3.12.0'" + } + }, + "npm": { + "description": "List of NPM package dependencies", + "type": "array", + "items": { + "type": "string", + "description": "A dependency on an NPM package, e.g., 'el-transition' or '@tailwindplus/elements@1'" + } + }, + "importmap": { + "description": "List of Importmap package dependencies", + "type": "array", + "items": { + "type": "string", + "description": "A dependency on an Importmap package, e.g., 'lodash' or 'bootstrap/dist/css/bootstrap.min.css'" } - ] + } } } } diff --git a/src/Toolkit/src/Command/CreateKitCommand.php b/src/Toolkit/src/Command/CreateKitCommand.php index ac0a79fb1aa..c57eb2aa8cb 100644 --- a/src/Toolkit/src/Command/CreateKitCommand.php +++ b/src/Toolkit/src/Command/CreateKitCommand.php @@ -100,8 +100,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int }, ) -%} - @@ -116,9 +117,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int 'templates/' => 'templates/', ], 'dependencies' => [ - ['type' => 'php', 'package' => 'twig/extra-bundle'], - ['type' => 'php', 'package' => 'twig/html-extra:^3.12.0'], - ['type' => 'php', 'package' => 'tales-from-a-dev/twig-tailwind-extra'], + 'composer' => [ + 'twig/extra-bundle', + 'twig/html-extra:^3.12.0', + 'tales-from-a-dev/twig-tailwind-extra', + ], ], ], \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES)); diff --git a/src/Toolkit/src/Dependency/Version.php b/src/Toolkit/src/Dependency/ConstraintVersion.php similarity index 93% rename from src/Toolkit/src/Dependency/Version.php rename to src/Toolkit/src/Dependency/ConstraintVersion.php index 541d936b35e..954d4251c82 100644 --- a/src/Toolkit/src/Dependency/Version.php +++ b/src/Toolkit/src/Dependency/ConstraintVersion.php @@ -18,7 +18,7 @@ * * @author Hugo Alliaume */ -final class Version implements \Stringable +final class ConstraintVersion implements \Stringable { /** * @param non-empty-string diff --git a/src/Toolkit/src/Dependency/NpmPackageDependency.php b/src/Toolkit/src/Dependency/NpmPackageDependency.php index 3b789a6c626..02c36d9ce59 100644 --- a/src/Toolkit/src/Dependency/NpmPackageDependency.php +++ b/src/Toolkit/src/Dependency/NpmPackageDependency.php @@ -27,7 +27,7 @@ final class NpmPackageDependency implements DependencyInterface */ public function __construct( public readonly string $name, - public readonly ?Version $constraintVersion = null, + public readonly ?ConstraintVersion $constraintVersion = null, ) { Assert::npmPackageName($name); } diff --git a/src/Toolkit/src/Dependency/PhpPackageDependency.php b/src/Toolkit/src/Dependency/PhpPackageDependency.php index 28cf9044804..766b55567ba 100644 --- a/src/Toolkit/src/Dependency/PhpPackageDependency.php +++ b/src/Toolkit/src/Dependency/PhpPackageDependency.php @@ -27,7 +27,7 @@ final class PhpPackageDependency implements DependencyInterface */ public function __construct( public readonly string $name, - public readonly ?Version $constraintVersion = null, + public readonly ?ConstraintVersion $constraintVersion = null, ) { Assert::phpPackageName($name); } diff --git a/src/Toolkit/src/Recipe/RecipeManifest.php b/src/Toolkit/src/Recipe/RecipeManifest.php index 40ccc0accba..ecd3862b9d3 100644 --- a/src/Toolkit/src/Recipe/RecipeManifest.php +++ b/src/Toolkit/src/Recipe/RecipeManifest.php @@ -12,12 +12,12 @@ namespace Symfony\UX\Toolkit\Recipe; use Symfony\Component\Filesystem\Path; +use Symfony\UX\Toolkit\Dependency\ConstraintVersion; use Symfony\UX\Toolkit\Dependency\DependencyInterface; use Symfony\UX\Toolkit\Dependency\ImportmapPackageDependency; use Symfony\UX\Toolkit\Dependency\NpmPackageDependency; use Symfony\UX\Toolkit\Dependency\PhpPackageDependency; use Symfony\UX\Toolkit\Dependency\RecipeDependency; -use Symfony\UX\Toolkit\Dependency\Version; /** * @author Hugo Alliaume @@ -63,30 +63,64 @@ public static function fromJson(string $json): self } $dependencies = []; - foreach ($data['dependencies'] ?? [] as $i => $dependency) { - if (!\is_array($dependency)) { - throw new \InvalidArgumentException('Each dependency must be an associative array.'); - } - if (!isset($dependency['type'])) { - throw new \InvalidArgumentException(\sprintf('The dependency #%d is missing "type" field.', $i)); + if (isset($data['dependencies'])) { + if (!\is_array($data['dependencies']) || array_values($data['dependencies']) === $data['dependencies']) { + throw new \InvalidArgumentException('The "dependencies" property must be an object.'); } - if ('php' === $dependency['type']) { - $name = $dependency['name'] ?? throw new \InvalidArgumentException(\sprintf('The dependency #%d of type "php" is missing "name" field.', $i)); - $version = $dependency['version'] ?? null; - $dependencies[] = new PhpPackageDependency($name, null === $version ? null : new Version($version)); - } elseif ('recipe' === $dependency['type']) { - $name = $dependency['name'] ?? throw new \InvalidArgumentException(\sprintf('The dependency #%d of type "recipe" is missing "name" field.', $i)); + foreach ($data['dependencies']['recipe'] ?? [] as $i => $name) { + if (!\is_string($name) || '' === $name) { + throw new \InvalidArgumentException(\sprintf('The dependency #%d of type "recipe" must be a non-empty string.', $i)); + } + $dependencies[] = new RecipeDependency($name); - } elseif ('npm' === $dependency['type']) { - $name = $dependency['name'] ?? throw new \InvalidArgumentException(\sprintf('The dependency #%d of type "npm" is missing "name" field.', $i)); - $version = $dependency['version'] ?? null; - $dependencies[] = new NpmPackageDependency($name, null === $version ? null : new Version($version)); - } elseif ('importmap' === $dependency['type']) { - $package = $dependency['package'] ?? throw new \InvalidArgumentException(\sprintf('The dependency #%d of type "importmap" is missing "package" field.', $i)); + } + foreach ($data['dependencies']['composer'] ?? [] as $i => $package) { + if (!\is_string($package) || '' === $package) { + throw new \InvalidArgumentException(\sprintf('The dependency #%d of type "composer" must be a non-empty string.', $i)); + } + + // format: "package:version" + if (str_contains($package, ':')) { + [$name, $version] = explode(':', $package, 2); + $dependencies[] = new PhpPackageDependency($name, new ConstraintVersion($version)); + } else { + $dependencies[] = new PhpPackageDependency($package); + } + } + + foreach ($data['dependencies']['npm'] ?? [] as $i => $package) { + if (!\is_string($package) || '' === $package) { + throw new \InvalidArgumentException(\sprintf('The dependency #%d of type "npm" must be a non-empty string.', $i)); + } + + // format: "package@version" or "@scope/package@version" + if (str_contains($package, '@')) { + if (substr_count($package, '@') > 1) { + $pos = strrpos($package, '@'); + $name = substr($package, 0, $pos); + $version = substr($package, $pos + 1); + } else { + [$name, $version] = explode('@', $package, 2); + } + $dependencies[] = new NpmPackageDependency($name, new ConstraintVersion($version)); + } else { + $dependencies[] = new NpmPackageDependency($package); + } + } + + foreach ($data['dependencies']['importmap'] ?? [] as $i => $package) { + if (!\is_string($package) || '' === $package) { + throw new \InvalidArgumentException(\sprintf('The dependency #%d of type "importmap" must be a non-empty string.', $i)); + } + $dependencies[] = new ImportmapPackageDependency($package); - } else { - throw new \InvalidArgumentException(\sprintf('The dependency type "%s" is not supported.', $dependency['type'])); + } + + unset($data['dependencies']['recipe'], $data['dependencies']['composer'], $data['dependencies']['npm'], $data['dependencies']['importmap']); + + if ([] !== $data['dependencies'] ?? []) { + throw new \InvalidArgumentException(\sprintf('The dependency types "%s" are not supported.', implode('", "', array_keys($data['dependencies'])))); } } diff --git a/src/Toolkit/tests/Command/CreateKitCommandTest.php b/src/Toolkit/tests/Command/CreateKitCommandTest.php index 2041cb293d6..27371c3f695 100644 --- a/src/Toolkit/tests/Command/CreateKitCommandTest.php +++ b/src/Toolkit/tests/Command/CreateKitCommandTest.php @@ -75,20 +75,13 @@ public function testShouldBeAbleToCreateAKit() "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "php", - "package": "twig/extra-bundle" - }, - { - "type": "php", - "package": "twig/html-extra:^3.12.0" - }, - { - "type": "php", - "package": "tales-from-a-dev/twig-tailwind-extra" - } - ] + "dependencies": { + "composer": [ + "twig/extra-bundle", + "twig/html-extra:^3.12.0", + "tales-from-a-dev/twig-tailwind-extra" + ] + } } JSON ); @@ -106,8 +99,9 @@ public function testShouldBeAbleToCreateAKit() }, ) -%} - diff --git a/src/Toolkit/tests/Command/DebugKitCommandTest.php b/src/Toolkit/tests/Command/DebugKitCommandTest.php index f5e65e3f25a..29723c625f8 100644 --- a/src/Toolkit/tests/Command/DebugKitCommandTest.php +++ b/src/Toolkit/tests/Command/DebugKitCommandTest.php @@ -68,11 +68,12 @@ public function testShouldBeAbleToDebugFixtureKitWithManyDependencies() ->assertOutputContains(implode(\PHP_EOL, [ '+--------------+------------------------- Recipe: "Alert" ----------------------------------------+', '| File(s) | N/A |', - '| Dependencies | twig/html-extra:^3.12.0 |', + '| Dependencies | Button |', + '| | twig/html-extra:^3.12.0 |', '| | tales-from-a-dev/twig-tailwind-extra |', '| | tailwindcss:^4.0.0 |', + '| | @tailwindplus/elements:1 |', '| | @hotwired/stimulus |', - '| | Button |', '+--------------+----------------------------------------------------------------------------------+', ])) ->assertOutputContains(implode(\PHP_EOL, [ diff --git a/src/Toolkit/tests/Dependency/ConstraintVersionTest.php b/src/Toolkit/tests/Dependency/ConstraintVersionTest.php new file mode 100644 index 00000000000..ad5a1618b08 --- /dev/null +++ b/src/Toolkit/tests/Dependency/ConstraintVersionTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\UX\Toolkit\Tests\Dependency; + +use PHPUnit\Framework\TestCase; +use Symfony\UX\Toolkit\Dependency\ConstraintVersion; + +final class ConstraintVersionTest extends TestCase +{ + public function testCanBeInstantiated() + { + $version = new ConstraintVersion('1.2.3'); + + $this->assertSame('1.2.3', (string) $version); + } + + public function testCanBeCompared() + { + $this->assertTrue((new ConstraintVersion('1.2.3'))->isHigherThan(new ConstraintVersion('1.2.2'))); + $this->assertFalse((new ConstraintVersion('1.2.3'))->isHigherThan(new ConstraintVersion('1.2.4'))); + $this->assertTrue((new ConstraintVersion('1.2.3'))->isHigherThan(new ConstraintVersion('1.1.99'))); + $this->assertFalse((new ConstraintVersion('1.2.3'))->isHigherThan(new ConstraintVersion('1.2.3'))); + $this->assertTrue((new ConstraintVersion('1.2.3'))->isHigherThan(new ConstraintVersion('0.99.99'))); + $this->assertFalse((new ConstraintVersion('1.2.3'))->isHigherThan(new ConstraintVersion('2.0.0'))); + } +} diff --git a/src/Toolkit/tests/Dependency/NpmPackageDependencyTest.php b/src/Toolkit/tests/Dependency/NpmPackageDependencyTest.php index e5378d938df..69d849e48b2 100644 --- a/src/Toolkit/tests/Dependency/NpmPackageDependencyTest.php +++ b/src/Toolkit/tests/Dependency/NpmPackageDependencyTest.php @@ -12,8 +12,8 @@ namespace Symfony\UX\Toolkit\Tests\Dependency; use PHPUnit\Framework\TestCase; +use Symfony\UX\Toolkit\Dependency\ConstraintVersion; use Symfony\UX\Toolkit\Dependency\NpmPackageDependency; -use Symfony\UX\Toolkit\Dependency\Version; class NpmPackageDependencyTest extends TestCase { @@ -25,7 +25,7 @@ public function testShouldBeInstantiable() $this->assertSame('NPM package "react"', $dependency->toDebug()); $this->assertSame('react', (string) $dependency); - $dependency = new NpmPackageDependency('react', new Version('^18.0.0')); + $dependency = new NpmPackageDependency('react', new ConstraintVersion('^18.0.0')); $this->assertSame('react', $dependency->name); $this->assertSame('NPM package "react:^18.0.0"', $dependency->toDebug()); $this->assertSame('react:^18.0.0', (string) $dependency); diff --git a/src/Toolkit/tests/Dependency/PhpPackageDependencyTest.php b/src/Toolkit/tests/Dependency/PhpPackageDependencyTest.php index 6c0ea38e042..74de27337ee 100644 --- a/src/Toolkit/tests/Dependency/PhpPackageDependencyTest.php +++ b/src/Toolkit/tests/Dependency/PhpPackageDependencyTest.php @@ -12,8 +12,8 @@ namespace Symfony\UX\Toolkit\Tests\Dependency; use PHPUnit\Framework\TestCase; +use Symfony\UX\Toolkit\Dependency\ConstraintVersion; use Symfony\UX\Toolkit\Dependency\PhpPackageDependency; -use Symfony\UX\Toolkit\Dependency\Version; final class PhpPackageDependencyTest extends TestCase { @@ -25,7 +25,7 @@ public function testShouldBeInstantiable() $this->assertSame('PHP package "twig/html-extra"', $dependency->toDebug()); $this->assertSame('twig/html-extra', (string) $dependency); - $dependency = new PhpPackageDependency('twig/html-extra', new Version('^3.2.1')); + $dependency = new PhpPackageDependency('twig/html-extra', new ConstraintVersion('^3.2.1')); $this->assertSame('twig/html-extra', $dependency->name); $this->assertSame('PHP package "twig/html-extra:^3.2.1"', $dependency->toDebug()); $this->assertSame('twig/html-extra:^3.2.1', (string) $dependency); diff --git a/src/Toolkit/tests/Dependency/VersionTest.php b/src/Toolkit/tests/Dependency/VersionTest.php deleted file mode 100644 index c6b73c0c328..00000000000 --- a/src/Toolkit/tests/Dependency/VersionTest.php +++ /dev/null @@ -1,35 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\UX\Toolkit\Tests\Dependency; - -use PHPUnit\Framework\TestCase; -use Symfony\UX\Toolkit\Dependency\Version; - -final class VersionTest extends TestCase -{ - public function testCanBeInstantiated() - { - $version = new Version('1.2.3'); - - $this->assertSame('1.2.3', (string) $version); - } - - public function testCanBeCompared() - { - $this->assertTrue((new Version('1.2.3'))->isHigherThan(new Version('1.2.2'))); - $this->assertFalse((new Version('1.2.3'))->isHigherThan(new Version('1.2.4'))); - $this->assertTrue((new Version('1.2.3'))->isHigherThan(new Version('1.1.99'))); - $this->assertFalse((new Version('1.2.3'))->isHigherThan(new Version('1.2.3'))); - $this->assertTrue((new Version('1.2.3'))->isHigherThan(new Version('0.99.99'))); - $this->assertFalse((new Version('1.2.3'))->isHigherThan(new Version('2.0.0'))); - } -} diff --git a/src/Toolkit/tests/Fixtures/kits/with-circular-components-dependencies/A/manifest.json b/src/Toolkit/tests/Fixtures/kits/with-circular-components-dependencies/A/manifest.json index 31a7f4fa360..aa062da576f 100644 --- a/src/Toolkit/tests/Fixtures/kits/with-circular-components-dependencies/A/manifest.json +++ b/src/Toolkit/tests/Fixtures/kits/with-circular-components-dependencies/A/manifest.json @@ -6,10 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "recipe", - "name": "B" - } - ] + "dependencies": { + "recipe": ["B"] + } } diff --git a/src/Toolkit/tests/Fixtures/kits/with-circular-components-dependencies/B/manifest.json b/src/Toolkit/tests/Fixtures/kits/with-circular-components-dependencies/B/manifest.json index 3fa3c7de582..3b37d54ebbf 100644 --- a/src/Toolkit/tests/Fixtures/kits/with-circular-components-dependencies/B/manifest.json +++ b/src/Toolkit/tests/Fixtures/kits/with-circular-components-dependencies/B/manifest.json @@ -6,10 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "recipe", - "name": "C" - } - ] + "dependencies": { + "recipe": ["C"] + } } diff --git a/src/Toolkit/tests/Fixtures/kits/with-circular-components-dependencies/C/manifest.json b/src/Toolkit/tests/Fixtures/kits/with-circular-components-dependencies/C/manifest.json index 49bfa56475c..7b899ab889b 100644 --- a/src/Toolkit/tests/Fixtures/kits/with-circular-components-dependencies/C/manifest.json +++ b/src/Toolkit/tests/Fixtures/kits/with-circular-components-dependencies/C/manifest.json @@ -6,10 +6,7 @@ "copy-files": { "templates/": "templates/" }, - "dependencies": [ - { - "type": "recipe", - "name": "A" - } - ] + "dependencies": { + "recipe": ["A"] + } } diff --git a/src/Toolkit/tests/Fixtures/kits/with-many-dependencies/Alert/manifest.json b/src/Toolkit/tests/Fixtures/kits/with-many-dependencies/Alert/manifest.json index 23f2ef6f210..6a4c3f47775 100644 --- a/src/Toolkit/tests/Fixtures/kits/with-many-dependencies/Alert/manifest.json +++ b/src/Toolkit/tests/Fixtures/kits/with-many-dependencies/Alert/manifest.json @@ -3,28 +3,10 @@ "type": "component", "name": "Alert", "description": "Component Alert", - "dependencies": [ - { - "type": "php", - "name": "twig/html-extra", - "version": "^3.12.0" - }, - { - "type": "php", - "name": "tales-from-a-dev/twig-tailwind-extra" - }, - { - "type": "npm", - "name": "tailwindcss", - "version": "^4.0.0" - }, - { - "type": "importmap", - "package": "@hotwired/stimulus" - }, - { - "type": "recipe", - "name": "Button" - } - ] + "dependencies": { + "recipe": ["Button"], + "composer": ["twig/html-extra:^3.12.0", "tales-from-a-dev/twig-tailwind-extra"], + "npm": ["tailwindcss@^4.0.0", "@tailwindplus/elements@1"], + "importmap": ["@hotwired/stimulus"] + } } diff --git a/src/Toolkit/tests/Fixtures/kits/with-many-dependencies/Button/manifest.json b/src/Toolkit/tests/Fixtures/kits/with-many-dependencies/Button/manifest.json index 12278e237ae..54139b72795 100644 --- a/src/Toolkit/tests/Fixtures/kits/with-many-dependencies/Button/manifest.json +++ b/src/Toolkit/tests/Fixtures/kits/with-many-dependencies/Button/manifest.json @@ -3,25 +3,9 @@ "type": "component", "name": "Button", "description": "Component Button", - "dependencies": [ - { - "type": "php", - "name": "twig/html-extra", - "version": "^3.12.0" - }, - { - "type": "php", - "name": "another/php-package", - "version": "^2.0" - }, - { - "type": "npm", - "name": "another-npm-package", - "version": "^1.0.0" - }, - { - "type": "importmap", - "package": "another-importmap-package" - } - ] + "dependencies": { + "composer": ["twig/html-extra:^3.12.0", "another/php-package:^2.0"], + "npm": ["another-npm-package@^1.0.0"], + "importmap": ["another-importmap-package"] + } } diff --git a/src/Toolkit/tests/Installer/PoolResolverTest.php b/src/Toolkit/tests/Installer/PoolResolverTest.php index bbb7c54039c..10796693328 100644 --- a/src/Toolkit/tests/Installer/PoolResolverTest.php +++ b/src/Toolkit/tests/Installer/PoolResolverTest.php @@ -15,11 +15,11 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Filesystem\Filesystem; +use Symfony\UX\Toolkit\Dependency\ConstraintVersion; use Symfony\UX\Toolkit\Dependency\ImportmapPackageDependency; use Symfony\UX\Toolkit\Dependency\NpmPackageDependency; use Symfony\UX\Toolkit\Dependency\PhpPackageDependency; use Symfony\UX\Toolkit\Dependency\RecipeDependency; -use Symfony\UX\Toolkit\Dependency\Version; use Symfony\UX\Toolkit\Installer\PoolResolver; use Symfony\UX\Toolkit\Kit\KitSynchronizer; use Symfony\UX\Toolkit\Recipe\RecipeSynchronizer; @@ -96,17 +96,18 @@ public function testCanHandleAllPossibleDependencies() $recipeButton = $kit->getRecipe('Button'); $this->assertEquals([ - new PhpPackageDependency('twig/html-extra', new Version('^3.12.0')), + new RecipeDependency('Button'), + new PhpPackageDependency('twig/html-extra', new ConstraintVersion('^3.12.0')), new PhpPackageDependency('tales-from-a-dev/twig-tailwind-extra'), - new NpmPackageDependency('tailwindcss', new Version('^4.0.0')), + new NpmPackageDependency('tailwindcss', new ConstraintVersion('^4.0.0')), + new NpmPackageDependency('@tailwindplus/elements', new ConstraintVersion('1')), new ImportmapPackageDependency('@hotwired/stimulus'), - new RecipeDependency('Button'), ], $recipeAlert->manifest->dependencies); $this->assertEquals([ - new PhpPackageDependency('twig/html-extra', new Version('^3.12.0')), - new PhpPackageDependency('another/php-package', new Version('^2.0')), - new NpmPackageDependency('another-npm-package', new Version('^1.0.0')), + new PhpPackageDependency('twig/html-extra', new ConstraintVersion('^3.12.0')), + new PhpPackageDependency('another/php-package', new ConstraintVersion('^2.0')), + new NpmPackageDependency('another-npm-package', new ConstraintVersion('^1.0.0')), new ImportmapPackageDependency('another-importmap-package'), ], $recipeButton->manifest->dependencies); @@ -115,14 +116,15 @@ public function testCanHandleAllPossibleDependencies() $this->assertCount(0, $pool->getFiles()); $this->assertEquals([ - 'twig/html-extra' => new PhpPackageDependency('twig/html-extra', new Version('^3.12.0')), + 'twig/html-extra' => new PhpPackageDependency('twig/html-extra', new ConstraintVersion('^3.12.0')), 'tales-from-a-dev/twig-tailwind-extra' => new PhpPackageDependency('tales-from-a-dev/twig-tailwind-extra'), - 'another/php-package' => new PhpPackageDependency('another/php-package', new Version('^2.0')), + 'another/php-package' => new PhpPackageDependency('another/php-package', new ConstraintVersion('^2.0')), ], $pool->getPhpPackageDependencies()); $this->assertEquals([ - 'tailwindcss' => new NpmPackageDependency('tailwindcss', new Version('^4.0.0')), - 'another-npm-package' => new NpmPackageDependency('another-npm-package', new Version('^1.0.0')), + 'tailwindcss' => new NpmPackageDependency('tailwindcss', new ConstraintVersion('^4.0.0')), + '@tailwindplus/elements' => new NpmPackageDependency('@tailwindplus/elements', new ConstraintVersion('1')), + 'another-npm-package' => new NpmPackageDependency('another-npm-package', new ConstraintVersion('^1.0.0')), ], $pool->getNpmPackageDependencies()); $this->assertEquals([ diff --git a/src/Toolkit/tests/Installer/PoolTest.php b/src/Toolkit/tests/Installer/PoolTest.php index c180d5fe658..f378b73859d 100644 --- a/src/Toolkit/tests/Installer/PoolTest.php +++ b/src/Toolkit/tests/Installer/PoolTest.php @@ -14,10 +14,10 @@ namespace Symfony\UX\Toolkit\Tests\Installer; use PHPUnit\Framework\TestCase; +use Symfony\UX\Toolkit\Dependency\ConstraintVersion; use Symfony\UX\Toolkit\Dependency\ImportmapPackageDependency; use Symfony\UX\Toolkit\Dependency\NpmPackageDependency; use Symfony\UX\Toolkit\Dependency\PhpPackageDependency; -use Symfony\UX\Toolkit\Dependency\Version; use Symfony\UX\Toolkit\File; use Symfony\UX\Toolkit\Installer\Pool; use Symfony\UX\Toolkit\Recipe\Recipe; @@ -84,17 +84,17 @@ public function testCanAddPhpPackageDependencyWithHigherVersion() { $pool = new Pool(); - $pool->addPhpPackageDependency(new PhpPackageDependency('twig/html-extra', new Version('^3.11.0'))); + $pool->addPhpPackageDependency(new PhpPackageDependency('twig/html-extra', new ConstraintVersion('^3.11.0'))); $this->assertCount(1, $pool->getPhpPackageDependencies()); $this->assertEquals('twig/html-extra:^3.11.0', (string) $pool->getPhpPackageDependencies()['twig/html-extra']); - $pool->addPhpPackageDependency(new PhpPackageDependency('twig/html-extra', new Version('^3.12.0'))); + $pool->addPhpPackageDependency(new PhpPackageDependency('twig/html-extra', new ConstraintVersion('^3.12.0'))); $this->assertCount(1, $pool->getPhpPackageDependencies()); $this->assertEquals('twig/html-extra:^3.12.0', (string) $pool->getPhpPackageDependencies()['twig/html-extra']); - $pool->addPhpPackageDependency(new PhpPackageDependency('twig/html-extra', new Version('^3.11.0'))); + $pool->addPhpPackageDependency(new PhpPackageDependency('twig/html-extra', new ConstraintVersion('^3.11.0'))); $this->assertCount(1, $pool->getPhpPackageDependencies()); $this->assertEquals('twig/html-extra:^3.12.0', (string) $pool->getPhpPackageDependencies()['twig/html-extra']); @@ -123,17 +123,17 @@ public function testCanAddNpmPackageDependencyWithHigherVersion() { $pool = new Pool(); - $pool->addNpmPackageDependency(new NpmPackageDependency('tailwindcss', new Version('^3.0.0'))); + $pool->addNpmPackageDependency(new NpmPackageDependency('tailwindcss', new ConstraintVersion('^3.0.0'))); $this->assertCount(1, $pool->getNpmPackageDependencies()); $this->assertEquals('tailwindcss:^3.0.0', (string) $pool->getNpmPackageDependencies()['tailwindcss']); - $pool->addNpmPackageDependency(new NpmPackageDependency('tailwindcss', new Version('^4.0.0'))); + $pool->addNpmPackageDependency(new NpmPackageDependency('tailwindcss', new ConstraintVersion('^4.0.0'))); $this->assertCount(1, $pool->getNpmPackageDependencies()); $this->assertEquals('tailwindcss:^4.0.0', (string) $pool->getNpmPackageDependencies()['tailwindcss']); - $pool->addNpmPackageDependency(new NpmPackageDependency('tailwindcss', new Version('^3.0.0'))); + $pool->addNpmPackageDependency(new NpmPackageDependency('tailwindcss', new ConstraintVersion('^3.0.0'))); $this->assertCount(1, $pool->getNpmPackageDependencies()); $this->assertEquals('tailwindcss:^4.0.0', (string) $pool->getNpmPackageDependencies()['tailwindcss']); diff --git a/src/Toolkit/tests/Kit/KitSynchronizerTest.php b/src/Toolkit/tests/Kit/KitSynchronizerTest.php index 16cdcff3d2c..311a58f5346 100644 --- a/src/Toolkit/tests/Kit/KitSynchronizerTest.php +++ b/src/Toolkit/tests/Kit/KitSynchronizerTest.php @@ -13,8 +13,8 @@ use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\Filesystem\Filesystem; +use Symfony\UX\Toolkit\Dependency\ConstraintVersion; use Symfony\UX\Toolkit\Dependency\PhpPackageDependency; -use Symfony\UX\Toolkit\Dependency\Version; use Symfony\UX\Toolkit\Kit\KitSynchronizer; use Symfony\UX\Toolkit\Recipe\RecipeSynchronizer; use Symfony\UX\Toolkit\Tests\TestHelperTrait; @@ -39,7 +39,7 @@ public function testCanResolveDependencies() $this->assertEquals([ new PhpPackageDependency('twig/extra-bundle'), - new PhpPackageDependency('twig/html-extra', new Version('^3.12.0')), + new PhpPackageDependency('twig/html-extra', new ConstraintVersion('^3.12.0')), new PhpPackageDependency('tales-from-a-dev/twig-tailwind-extra'), ], $kit->getRecipe('Button')->manifest->dependencies); } diff --git a/src/Toolkit/tests/Recipe/RecipeManifestTest.php b/src/Toolkit/tests/Recipe/RecipeManifestTest.php index a5002ce21eb..f38c72cd281 100644 --- a/src/Toolkit/tests/Recipe/RecipeManifestTest.php +++ b/src/Toolkit/tests/Recipe/RecipeManifestTest.php @@ -14,11 +14,11 @@ namespace Symfony\UX\Toolkit\Tests\Recipe; use PHPUnit\Framework\TestCase; +use Symfony\UX\Toolkit\Dependency\ConstraintVersion; use Symfony\UX\Toolkit\Dependency\ImportmapPackageDependency; use Symfony\UX\Toolkit\Dependency\NpmPackageDependency; use Symfony\UX\Toolkit\Dependency\PhpPackageDependency; use Symfony\UX\Toolkit\Dependency\RecipeDependency; -use Symfony\UX\Toolkit\Dependency\Version; use Symfony\UX\Toolkit\Recipe\RecipeManifest; use Symfony\UX\Toolkit\Recipe\RecipeType; @@ -80,7 +80,7 @@ public function testFromJsonWithMissingDescription() public function testFromJsonWithInvalidDependencies() { $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Each dependency must be an associative array.'); + $this->expectExceptionMessage('The "dependencies" property must be an object.'); RecipeManifest::fromJson(<<expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The dependency #0 is missing "type" field.'); - - RecipeManifest::fromJson(<<expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The dependency #0 of type "php" is missing "name" field.'); + $this->expectExceptionMessage('The dependency #0 of type "composer" must be a non-empty string.'); RecipeManifest::fromJson(<<expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The dependency #1 of type "npm" is missing "name" field.'); + $this->expectExceptionMessage('The dependency #0 of type "npm" must be a non-empty string.'); RecipeManifest::fromJson(<<expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The dependency #2 of type "importmap" is missing "package" field.'); + $this->expectExceptionMessage('The dependency #0 of type "importmap" must be a non-empty string.'); RecipeManifest::fromJson(<<expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('The dependency #3 of type "recipe" is missing "name" field.'); + $this->expectExceptionMessage('The dependency #0 of type "recipe" must be a non-empty string.'); RecipeManifest::fromJson(<<assertSame('An incredible component', $manifest->description); $this->assertSame(['templates/' => 'templates/'], $manifest->copyFiles); $this->assertEquals([ + new RecipeDependency('OtherComponent'), new PhpPackageDependency('tales-from-a-dev/twig-tailwind-extra', null), - new PhpPackageDependency('symfony/ux-twig-component', new Version('^2.29')), - new NpmPackageDependency('tailwindcss', new Version('^4.0.0')), + new PhpPackageDependency('symfony/ux-twig-component', new ConstraintVersion('^2.29')), + new NpmPackageDependency('tailwindcss', new ConstraintVersion('^4.0.0')), + new NpmPackageDependency('@tailwindplus/elements', new ConstraintVersion('1')), new ImportmapPackageDependency('@hotwired/stimulus'), - new RecipeDependency('OtherComponent'), ], $manifest->dependencies); } }