1
1
import path from 'path' ;
2
2
import fs from 'fs-extra' ;
3
- import { logger } from '@react-native-community/cli-tools' ;
3
+ import { getLoader , logger } from '@react-native-community/cli-tools' ;
4
4
import chalk from 'chalk' ;
5
5
import { prompt } from 'prompts' ;
6
+ import execa from 'execa' ;
7
+ import semver from 'semver' ;
6
8
7
9
interface DependencyInfo {
8
10
path : string ;
9
11
peerDependencies : { [ key : string ] : string } ;
10
12
}
11
13
14
+ function isUsingYarn ( root : string ) {
15
+ return fs . existsSync ( path . join ( root , 'yarn.lock' ) ) ;
16
+ }
17
+
12
18
function getPeerDependencies ( root : string ) : Map < string , DependencyInfo > {
13
19
const packageJsonPath = path . join ( root , 'package.json' ) ;
14
20
const packageJson = require ( packageJsonPath ) ;
15
21
16
22
const dependenciesAndPeerDependencies = new Map < string , DependencyInfo > ( ) ;
17
23
18
- for ( const dependency in { ... packageJson . dependencies } ) {
24
+ for ( const dependency in packageJson . dependencies ) {
19
25
const dependencyPath = path . join ( root , 'node_modules' , dependency ) ;
20
26
21
27
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
+ }
24
41
25
42
if (
26
- packageJson . peerDependencies &&
43
+ dependencyPackageJson . peerDependencies &&
27
44
! dependenciesAndPeerDependencies . has ( dependency )
28
45
) {
29
46
dependenciesAndPeerDependencies . set ( dependency , {
30
47
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
+ } , { } ) ,
32
54
} ) ;
33
55
}
34
56
}
@@ -63,6 +85,22 @@ function excludeInstalledPeerDependencies(
63
85
return missingPeerDependencies ;
64
86
}
65
87
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
+
66
104
export default async function installTransitiveDeps ( ) {
67
105
const root = process . cwd ( ) ;
68
106
@@ -85,8 +123,31 @@ export default async function installTransitiveDeps() {
85
123
const { install} = await prompt ( {
86
124
type : 'confirm' ,
87
125
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.' ,
89
128
} ) ;
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
+ }
91
152
}
92
153
}
0 commit comments