11import path from 'path' ;
22import fs from 'fs-extra' ;
3- import { logger } from '@react-native-community/cli-tools' ;
3+ import { getLoader , logger } from '@react-native-community/cli-tools' ;
44import chalk from 'chalk' ;
55import { prompt } from 'prompts' ;
6+ import execa from 'execa' ;
7+ import semver from 'semver' ;
68
79interface DependencyInfo {
810 path : string ;
911 peerDependencies : { [ key : string ] : string } ;
1012}
1113
14+ function isUsingYarn ( root : string ) {
15+ return fs . existsSync ( path . join ( root , 'yarn.lock' ) ) ;
16+ }
17+
1218function getPeerDependencies ( root : string ) : Map < string , DependencyInfo > {
1319 const packageJsonPath = path . join ( root , 'package.json' ) ;
1420 const packageJson = require ( packageJsonPath ) ;
1521
1622 const dependenciesAndPeerDependencies = new Map < string , DependencyInfo > ( ) ;
1723
18- for ( const dependency in { ... packageJson . dependencies } ) {
24+ for ( const dependency in packageJson . dependencies ) {
1925 const dependencyPath = path . join ( root , 'node_modules' , dependency ) ;
2026
2127 if ( fs . existsSync ( dependencyPath ) ) {
22- const packageJsonPath = path . join ( dependencyPath , 'package.json' ) ;
23- const packageJson = require ( packageJsonPath ) ;
28+ const dependencyPackageJson = require ( path . join (
29+ dependencyPath ,
30+ 'package.json' ,
31+ ) ) ;
32+ const peerDependenciesMeta = dependencyPackageJson . peerDependenciesMeta ;
33+
34+ let optionalDeps : string [ ] = [ ] ;
35+ if ( peerDependenciesMeta ) {
36+ const peers = Object . keys ( peerDependenciesMeta ) ;
37+ optionalDeps = peers . filter (
38+ ( p ) => peerDependenciesMeta [ p ] . optional === true ,
39+ ) ;
40+ }
2441
2542 if (
26- packageJson . peerDependencies &&
43+ dependencyPackageJson . peerDependencies &&
2744 ! dependenciesAndPeerDependencies . has ( dependency )
2845 ) {
2946 dependenciesAndPeerDependencies . set ( dependency , {
3047 path : dependencyPath ,
31- peerDependencies : packageJson . peerDependencies ,
48+ peerDependencies : Object . keys ( dependencyPackageJson . peerDependencies )
49+ . filter ( ( key ) => ! optionalDeps . includes ( key ) )
50+ . reduce < Record < string , string > > ( ( result , key ) => {
51+ result [ key ] = dependencyPackageJson . peerDependencies [ key ] ;
52+ return result ;
53+ } , { } ) ,
3254 } ) ;
3355 }
3456 }
@@ -63,6 +85,22 @@ function excludeInstalledPeerDependencies(
6385 return missingPeerDependencies ;
6486}
6587
88+ function getMatchingPackageVersion ( packageName : string , range : string ) {
89+ const { stdout} = execa . sync ( 'yarn' , [
90+ 'info' ,
91+ packageName ,
92+ 'versions' ,
93+ '--json' ,
94+ ] ) ;
95+ const versions = JSON . parse ( stdout ) . data as string [ ] ;
96+ const satisfying = versions . filter ( ( version ) =>
97+ semver . satisfies ( version , range ) ,
98+ ) ;
99+ const maxSatisfying = semver . maxSatisfying ( satisfying , range ) ;
100+
101+ return maxSatisfying ;
102+ }
103+
66104export default async function installTransitiveDeps ( ) {
67105 const root = process . cwd ( ) ;
68106
@@ -85,8 +123,31 @@ export default async function installTransitiveDeps() {
85123 const { install} = await prompt ( {
86124 type : 'confirm' ,
87125 name : 'install' ,
88- message : 'Do you want to install them now?' ,
126+ message :
127+ 'Do you want to install them now? The matching versions will be added as project dependencies.' ,
89128 } ) ;
90- console . log ( { install} ) ;
129+ const loader = getLoader ( { text : 'Installing peer dependencies...' } ) ;
130+
131+ if ( install ) {
132+ if ( isUsingYarn ( root ) ) {
133+ let deps = { } as Record < string , string > ;
134+ dependenciesWithMissingDeps . map ( ( dep ) => {
135+ const missingDeps = depsToInstall [ dep ] ;
136+
137+ Object . entries ( missingDeps ) . map ( ( [ name , range ] ) => {
138+ const version = getMatchingPackageVersion ( name , range ) ;
139+ if ( version ) {
140+ deps [ name ] = version ;
141+ }
142+ } ) ;
143+ } ) ;
144+ loader . start ( ) ;
145+ execa . sync ( 'yarn' , [
146+ 'add' ,
147+ ...Object . entries ( deps ) . map ( ( [ k , v ] ) => `${ k } @^${ v } ` ) ,
148+ ] ) ;
149+ loader . succeed ( ) ;
150+ }
151+ }
91152 }
92153}
0 commit comments