1313
1414use Composer \Json \JsonFile ;
1515use Composer \Json \JsonManipulator ;
16+ use Composer \Semver \Constraint \ConstraintInterface ;
17+ use Composer \Semver \Intervals ;
18+ use Composer \Semver \VersionParser ;
1619
1720/**
1821 * Synchronize package.json files detected in installed PHP packages with
@@ -41,6 +44,8 @@ public function synchronize(array $packagesNames)
4144 $ this ->addPackageJsonLink ($ packageName );
4245 }
4346
47+ $ this ->registerPeerDependencies ($ packagesNames );
48+
4449 // Register controllers and entrypoints in controllers.json
4550 $ this ->registerWebpackResources ($ packagesNames );
4651 }
@@ -98,11 +103,8 @@ private function registerWebpackResources(array $phpPackages)
98103 continue ;
99104 }
100105
101- if (!file_exists ($ packageJsonPath = $ this ->rootDir .'/vendor/ ' .$ phpPackage .$ assetsDir .'/package.json ' )) {
102- continue ;
103- }
104-
105106 // Register in config
107+ $ packageJsonPath = $ this ->rootDir .'/vendor/ ' .$ phpPackage .$ assetsDir .'/package.json ' ;
106108 $ packageJson = (new JsonFile ($ packageJsonPath ))->read ();
107109
108110 foreach ($ packageJson ['symfony ' ]['controllers ' ] ?? [] as $ controllerName => $ defaultConfig ) {
@@ -150,6 +152,41 @@ private function registerWebpackResources(array $phpPackages)
150152 file_put_contents ($ controllersJsonPath , json_encode ($ newControllersJson , \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES )."\n" );
151153 }
152154
155+ public function registerPeerDependencies (array $ phpPackages )
156+ {
157+ $ peerDependencies = [];
158+
159+ foreach ($ phpPackages as $ phpPackage ) {
160+ if (!$ assetsDir = $ this ->resolveAssetsDir ($ phpPackage )) {
161+ continue ;
162+ }
163+
164+ $ packageJsonPath = $ this ->rootDir .'/vendor/ ' .$ phpPackage .$ assetsDir .'/package.json ' ;
165+ $ packageJson = (new JsonFile ($ packageJsonPath ))->read ();
166+ $ versionParser = new VersionParser ();
167+
168+ foreach ($ packageJson ['peerDependencies ' ] ?? [] as $ peerDependency => $ constraint ) {
169+ $ peerDependencies [$ peerDependency ][$ constraint ] = $ versionParser ->parseConstraints ($ constraint );
170+ }
171+ }
172+
173+ if (!$ peerDependencies ) {
174+ return ;
175+ }
176+
177+ $ manipulator = new JsonManipulator (file_get_contents ($ this ->rootDir .'/package.json ' ));
178+ $ content = json_decode ($ manipulator ->getContents (), true );
179+ $ devDependencies = $ content ['devDependencies ' ] ?? [];
180+
181+ foreach ($ peerDependencies as $ peerDependency => $ constraints ) {
182+ $ devDependencies [$ peerDependency ] = $ this ->compactConstraints ($ constraints );
183+ }
184+ uksort ($ devDependencies , 'strnatcmp ' );
185+ $ manipulator ->addMainKey ('devDependencies ' , $ devDependencies );
186+
187+ file_put_contents ($ this ->rootDir .'/package.json ' , $ manipulator ->getContents ());
188+ }
189+
153190 private function resolveAssetsDir (string $ phpPackage )
154191 {
155192 foreach (['/assets ' , '/Resources/assets ' ] as $ subdir ) {
@@ -160,4 +197,28 @@ private function resolveAssetsDir(string $phpPackage)
160197
161198 return null ;
162199 }
200+
201+ /**
202+ * @param ConstraintInterface[] $constraints
203+ */
204+ private function compactConstraints (array $ constraints ): string
205+ {
206+ if (method_exists (Intervals::class, 'isSubsetOf ' )) {
207+ foreach ($ constraints as $ k1 => $ constraint1 ) {
208+ foreach ($ constraints as $ k2 => $ constraint2 ) {
209+ if ($ k1 !== $ k2 && Intervals::isSubsetOf ($ constraint1 , $ constraint2 )) {
210+ unset($ constraints [$ k2 ]);
211+ }
212+ }
213+ }
214+ }
215+
216+ uksort ($ constraints , 'strnatcmp ' );
217+
218+ foreach ($ constraints as $ k => $ constraint ) {
219+ $ constraints [$ k ] = \count ($ constraints ) > 1 && false !== strpos ($ k , '| ' ) ? '( ' .$ k .') ' : $ k ;
220+ }
221+
222+ return implode (', ' , $ constraints );
223+ }
163224}
0 commit comments