@@ -4,6 +4,7 @@ import path from 'path'
4
4
import { fileURLToPath } from 'url'
5
5
import { execa } from 'execa'
6
6
import fs from 'fs-extra'
7
+ import latestVersion from 'latest-version'
7
8
import Listr from 'listr'
8
9
import prompt from 'prompt'
9
10
import semver from 'semver'
@@ -161,38 +162,33 @@ async function processMonorepo (projectDir, manifest, branchName, repoUrl, ciFil
161
162
* @param {string[] } projectDirs
162
163
*/
163
164
async function alignMonorepoProjectDependencies ( projectDirs ) {
164
- console . info ( 'Align monorepo project dependencies' )
165
-
166
165
/** @type {Record<string, string> } */
167
166
const siblingVersions = { }
168
167
/** @type {Record<string, string> } */
169
168
const deps = { }
170
- /** @type {Record<string, string> } */
171
- const devDeps = { }
172
- /** @type {Record<string, string> } */
173
- const optionalDeps = { }
174
- /** @type {Record<string, string> } */
175
- const peerDeps = { }
176
169
177
170
// first loop over every project and choose the most recent version of a given dep
178
171
for ( const projectDir of projectDirs ) {
179
172
const pkg = fs . readJSONSync ( path . join ( projectDir , 'package.json' ) )
180
173
siblingVersions [ pkg . name ] = calculateSiblingVersion ( pkg . version )
181
174
182
- chooseVersions ( pkg . dependencies || { } , deps )
183
- chooseVersions ( pkg . devDependencies || { } , devDeps )
184
- chooseVersions ( pkg . optionalDependencies || { } , optionalDeps )
185
- chooseVersions ( pkg . peerDependencies || { } , peerDeps )
175
+ chooseVersions ( pkg . dependencies ?? { } , deps )
176
+ chooseVersions ( pkg . devDependencies ?? { } , deps )
177
+ chooseVersions ( pkg . optionalDependencies ?? { } , deps )
178
+ chooseVersions ( pkg . peerDependencies ?? { } , deps )
186
179
}
187
180
181
+ // get the latest patch release of every dep from npm
182
+ await findLatestVersions ( deps )
183
+
188
184
// now propose the most recent version of a dep for all projects
189
185
for ( const projectDir of projectDirs ) {
190
186
const pkg = fs . readJSONSync ( path . join ( projectDir , 'package.json' ) )
191
187
192
- selectVersions ( pkg . dependencies || { } , deps , siblingVersions )
193
- selectVersions ( pkg . devDependencies || { } , devDeps , siblingVersions )
194
- selectVersions ( pkg . optionalDependencies || { } , optionalDeps , siblingVersions )
195
- selectVersions ( pkg . peerDependencies || { } , peerDeps , siblingVersions )
188
+ selectVersions ( pkg . dependencies ?? { } , deps , siblingVersions )
189
+ selectVersions ( pkg . devDependencies ?? { } , deps , siblingVersions )
190
+ selectVersions ( pkg . optionalDependencies ?? { } , deps , siblingVersions )
191
+ selectVersions ( pkg . peerDependencies ?? { } , deps , siblingVersions )
196
192
197
193
await ensureFileHasContents ( projectDir , 'package.json' , JSON . stringify ( pkg , null , 2 ) )
198
194
}
@@ -203,37 +199,50 @@ async function alignMonorepoProjectDependencies (projectDirs) {
203
199
* @param {Record<string, string> } list
204
200
*/
205
201
function chooseVersions ( deps , list ) {
206
- Object . entries ( deps ) . forEach ( ( [ key , value ] ) => {
202
+ for ( const [ dep , version ] of Object . entries ( deps ) ) {
207
203
// not seen this dep before
208
- if ( ! list [ key ] ) {
209
- list [ key ] = value
210
- return
204
+ if ( list [ dep ] == null ) {
205
+ list [ dep ] = version
206
+ continue
207
+ }
208
+
209
+ // test for later version
210
+ if ( semver . gt ( version . replace ( / \^ | ~ / , '' ) , list [ dep ] . replace ( / \^ | ~ / , '' ) ) ) {
211
+ list [ dep ] = version
211
212
}
213
+ }
214
+ }
212
215
213
- const existingVersion = semver . minVersion ( list [ key ] )
214
- const moduleVersion = semver . minVersion ( value )
216
+ /**
217
+ * @param {Record<string, string> } deps
218
+ */
219
+ async function findLatestVersions ( deps ) {
220
+ // find the latest semver-compatible release from npm
221
+ for ( const [ key , value ] of Object . entries ( deps ) ) {
222
+ try {
223
+ const npmVersion = `^${ await latestVersion ( key , { version : value } ) } `
215
224
216
- // take the most recent range or version
217
- const res = semver . compare ( existingVersion ?? '0.0.0' , moduleVersion ?? '0.0.0' )
225
+ console . info ( key , 'local version:' , value , 'npm version:' , npmVersion )
218
226
219
- if ( res === - 1 ) {
220
- list [ key ] = value
227
+ deps [ key ] = npmVersion
228
+ } catch ( err ) {
229
+ console . error ( `Could not load latest npm version of "${ key } "` , err )
221
230
}
222
- } )
231
+ }
223
232
}
224
233
225
234
/**
226
235
* @param {Record<string, string> } deps
227
236
* @param {Record<string, string> } list
228
237
* @param {Record<string, string> } siblingVersions
229
238
*/
230
- function selectVersions ( deps , list , siblingVersions ) {
239
+ async function selectVersions ( deps , list , siblingVersions ) {
231
240
// release-please updates sibling versions to the latest patch releases but
232
241
// we try to update to the latest minor so skip that if release please is
233
242
// in use
234
243
const ignoreSiblingDeps = usesReleasePlease ( )
235
244
236
- Object . entries ( list ) . forEach ( ( [ key , value ] ) => {
245
+ for ( const [ key , value ] of Object . entries ( list ) ) {
237
246
if ( deps [ key ] != null ) {
238
247
if ( siblingVersions [ key ] != null && ! ignoreSiblingDeps ) {
239
248
// take sibling version if available
@@ -243,7 +252,7 @@ function selectVersions (deps, list, siblingVersions) {
243
252
deps [ key ] = value
244
253
}
245
254
}
246
- } )
255
+ }
247
256
}
248
257
249
258
/**
0 commit comments