diff --git a/src/Installer.php b/src/Installer.php index a42cdab..4e26dcd 100644 --- a/src/Installer.php +++ b/src/Installer.php @@ -360,12 +360,39 @@ protected function copyFrameworkFiles(PackageInterface $package): void */ protected function flattenFrameworkFiles(string $jsRoot, string $framework): void { + $targetPaths = []; + if (is_dir($jsRoot.'/'.$framework)) { + foreach ((new Finder)->files()->in($jsRoot.'/'.$framework) as $f) { + $targetPaths[$f->getRelativePathname()] = true; + } + } + + $stale = []; + foreach (self::KNOWN_FRAMEWORKS as $fw) { + if ($fw === $framework || ! is_dir($jsRoot.'/'.$fw)) { + continue; + } + foreach ((new Finder)->files()->in($jsRoot.'/'.$fw) as $f) { + $rel = $f->getRelativePathname(); + if (! isset($targetPaths[$rel])) { + $stale[] = $rel; + } + } + } + $this->copyDirectory($jsRoot.'/'.$framework, $jsRoot); $fs = new Filesystem; foreach (self::KNOWN_FRAMEWORKS as $fw) { $fs->removeDirectory($jsRoot.'/'.$fw); } + + $sfFs = new SymfonyFilesystem; + foreach ($stale as $rel) { + if (file_exists($jsRoot.'/'.$rel)) { + $sfFs->remove($jsRoot.'/'.$rel); + } + } } /** diff --git a/tests/ModuleInstallerTest.php b/tests/ModuleInstallerTest.php index 8f6723b..ce79b22 100644 --- a/tests/ModuleInstallerTest.php +++ b/tests/ModuleInstallerTest.php @@ -1036,4 +1036,24 @@ private function makeInstallerWithModuleDir(string $baseDir): TestableInstaller return new TestableInstaller($io, $composer); } + + public function test_flatten_framework_files_removes_stale_root_file_from_other_framework(): void + { + $jsRoot = sys_get_temp_dir().'/flatten-stale-'.uniqid('', true); + mkdir($jsRoot.'/vue', 0755, true); + mkdir($jsRoot.'/react', 0755, true); + file_put_contents($jsRoot.'/app.ts', 'stale vue root file'); + file_put_contents($jsRoot.'/vue/app.ts', 'vue app'); + file_put_contents($jsRoot.'/react/app.tsx', 'react app'); + + $installer = new TestableInstaller($this->createStub(IOInterface::class), null); + $installer->callFlattenFrameworkFiles($jsRoot, 'react'); + + $this->assertFileExists($jsRoot.'/app.tsx'); + $this->assertFileDoesNotExist($jsRoot.'/app.ts'); + $this->assertDirectoryDoesNotExist($jsRoot.'/vue'); + $this->assertDirectoryDoesNotExist($jsRoot.'/react'); + + (new Filesystem)->remove($jsRoot); + } }