Repository: symfony/ux
Pull request #2892 (2025-07-03 06:15:03)

[Toolkit] Fix comptability with Windows
| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no <!-- please update src/**/CHANGELOG.md files -->
| Docs?         | no <!-- required for new features -->
| Issues        | Fix #... <!-- prefix each issue number with "Fix #", no need to create an issue if none exist, explain below instead -->
| License       | MIT

<!--
Replace this notice by a description of your feature/bugfix.
This will help reviewers and should be a good start for the documentation.

Additionally (see https://symfony.com/releases):
 - Always add tests and ensure they pass.
 - For new features, provide some code snippets to help understand usage.
 - Features and deprecations must be submitted against branch main.
 - Update/add documentation as required (we can help!)
 - Changelog entry should follow https://symfony.com/doc/current/contributing/code/conventions.html#writing-a-changelog-entry
 - Never break backward compatibility (see https://symfony.com/bc).
-->
Following https://github.com/symfony/ux/pull/2816


Patch:
diff --git a/src/Toolkit/src/Kit/KitSynchronizer.php b/src/Toolkit/src/Kit/KitSynchronizer.php
index 0aaf9584..0f13f921 100644
--- a/src/Toolkit/src/Kit/KitSynchronizer.php
+++ b/src/Toolkit/src/Kit/KitSynchronizer.php
@@ -69,8 +69,8 @@ final class KitSynchronizer
         ;
 
         foreach ($finder as $file) {
-            $relativePathNameToKit = $file->getRelativePathname();
-            $relativePathName = str_replace($componentsPath.\DIRECTORY_SEPARATOR, '', $relativePathNameToKit);
+            $relativePathNameToKit = Path::normalize($file->getRelativePathname());
+            $relativePathName = str_replace($componentsPath.'/', '', $relativePathNameToKit);
             $componentName = $this->extractComponentName($relativePathName);
 
             $meta = null;
@@ -161,8 +161,8 @@ final class KitSynchronizer
         ;
 
         foreach ($finder as $file) {
-            $relativePathNameToKit = $file->getRelativePathname();
-            $relativePathName = str_replace($controllersPath.\DIRECTORY_SEPARATOR, '', $relativePathNameToKit);
+            $relativePathNameToKit = Path::normalize($file->getRelativePathname());
+            $relativePathName = str_replace($controllersPath.'/', '', $relativePathNameToKit);
             $controllerName = $this->extractStimulusControllerName($relativePathName);
             $controller = new StimulusController(
                 name: $controllerName,


Test patch:
diff --git a/src/Toolkit/tests/Command/DebugKitCommandTest.php b/src/Toolkit/tests/Command/DebugKitCommandTest.php
index 406d237d..7ce441cd 100644
--- a/src/Toolkit/tests/Command/DebugKitCommandTest.php
+++ b/src/Toolkit/tests/Command/DebugKitCommandTest.php
@@ -12,6 +12,7 @@
 namespace Symfony\UX\Toolkit\Tests\Command;
 
 use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
+use Symfony\Component\Filesystem\Path;
 use Zenstruck\Console\Test\InteractsWithConsole;
 
 class DebugKitCommandTest extends KernelTestCase
@@ -21,7 +22,7 @@ class DebugKitCommandTest extends KernelTestCase
     public function testShouldBeAbleToDebug(): void
     {
         $this->bootKernel();
-        $this->consoleCommand(\sprintf('ux:toolkit:debug-kit %s', __DIR__.'/../../kits/shadcn'))
+        $this->consoleCommand(\sprintf('ux:toolkit:debug-kit %s', Path::join(__DIR__, '/../../kits/shadcn')))
             ->execute()
             ->assertSuccessful()
             // Kit details
@@ -29,28 +30,26 @@ class DebugKitCommandTest extends KernelTestCase
             ->assertOutputContains('Homepage   https://ux.symfony.com/components')
             ->assertOutputContains('License    MIT')
             // Components details
-            ->assertOutputContains(<<<'EOF'
-+--------------+----------------------- Component: "Avatar" --------------------------------------+
-| File(s)      | templates/components/Avatar.html.twig                                            |
-| Dependencies | tales-from-a-dev/twig-tailwind-extra                                             |
-|              | Avatar:Image                                                                     |
-|              | Avatar:Text                                                                      |
-+--------------+----------------------------------------------------------------------------------+
-EOF
-            )
-            ->assertOutputContains(<<<'EOF'
-+--------------+----------------------- Component: "Table" ---------------------------------------+
-| File(s)      | templates/components/Table.html.twig                                             |
-| Dependencies | tales-from-a-dev/twig-tailwind-extra                                             |
-|              | Table:Body                                                                       |
-|              | Table:Caption                                                                    |
-|              | Table:Cell                                                                       |
-|              | Table:Footer                                                                     |
-|              | Table:Head                                                                       |
-|              | Table:Header                                                                     |
-|              | Table:Row                                                                        |
-+--------------+----------------------------------------------------------------------------------+
-EOF
-            );
+            ->assertOutputContains(implode(\PHP_EOL, [
+                '+--------------+----------------------- Component: "Avatar" --------------------------------------+',
+                '| File(s)      | templates/components/Avatar.html.twig                                            |',
+                '| Dependencies | tales-from-a-dev/twig-tailwind-extra                                             |',
+                '|              | Avatar:Image                                                                     |',
+                '|              | Avatar:Text                                                                      |',
+                '+--------------+----------------------------------------------------------------------------------+',
+            ]))
+            ->assertOutputContains(implode(\PHP_EOL, [
+                '+--------------+----------------------- Component: "Table" ---------------------------------------+',
+                '| File(s)      | templates/components/Table.html.twig                                             |',
+                '| Dependencies | tales-from-a-dev/twig-tailwind-extra                                             |',
+                '|              | Table:Body                                                                       |',
+                '|              | Table:Caption                                                                    |',
+                '|              | Table:Cell                                                                       |',
+                '|              | Table:Footer                                                                     |',
+                '|              | Table:Head                                                                       |',
+                '|              | Table:Header                                                                     |',
+                '|              | Table:Row                                                                        |',
+                '+--------------+----------------------------------------------------------------------------------+',
+            ]));
     }
 }
diff --git a/src/Toolkit/tests/Command/InstallComponentCommandTest.php b/src/Toolkit/tests/Command/InstallComponentCommandTest.php
index 79e7e811..d2c3274e 100644
--- a/src/Toolkit/tests/Command/InstallComponentCommandTest.php
+++ b/src/Toolkit/tests/Command/InstallComponentCommandTest.php
@@ -50,7 +50,7 @@ class InstallComponentCommandTest extends KernelTestCase
             $this->assertFileDoesNotExist($expectedFile);
         }
 
-        $testCommand = $this->consoleCommand('ux:toolkit:install-component Table --destination='.$this->tmpDir)
+        $testCommand = $this->consoleCommand(\sprintf('ux:toolkit:install-component Table --destination="%s"', str_replace('\\', '\\\\', $this->tmpDir)))
             ->execute()
             ->assertSuccessful()
             ->assertOutputContains('Installing component Table from the Shadcn UI kit...')