@@ -4,6 +4,7 @@ const fs = require('fs-extra');
44const opta = require ( 'opta' ) ;
55const parseList = require ( 'safe-parse-list' ) ;
66const { create, load } = require ( '@npmcli/package-json' ) ;
7+ const mapWorkspaces = require ( '@npmcli/map-workspaces' ) ;
78const { Loggerr } = require ( 'loggerr' ) ;
89const packageName = require ( './lib/package-name' ) ;
910const git = require ( './lib/git' ) ;
@@ -123,6 +124,22 @@ function initOpts () {
123124 }
124125 } ,
125126
127+ workspaceRoot : {
128+ type : 'string' ,
129+ flag : {
130+ key : 'workspace-root'
131+ } ,
132+ prompt : {
133+ message : 'Workspace Root:' ,
134+ when : ( promptInput , defaultWhen , allInput ) => {
135+ if ( allInput . workspaceRoot !== allInput . cwd ) {
136+ return true ;
137+ }
138+ return defaultWhen ;
139+ }
140+ }
141+ } ,
142+
126143 type : {
127144 type : 'string' ,
128145 prompt : {
@@ -255,6 +272,50 @@ async function readPackageJson (options, { log } = {}) {
255272 log . error ( e ) ;
256273 }
257274
275+ // Check to see if we are in a monorepo context
276+ if ( ! pkg . workspaces ) {
277+ let rootPkg ;
278+ let rootDir = opts . workspaceRoot ;
279+ if ( ! rootDir ) {
280+ // Limit to git root if in a checked out repo
281+ const gitRoot = await git . repositoryRoot ( opts . cwd ) ;
282+
283+ const [ _rootPkg , _rootDir ] = await npm . findWorkspaceRoot ( opts . cwd , gitRoot ) ;
284+ rootPkg = _rootPkg ;
285+ rootDir = _rootDir ;
286+ } else {
287+ try {
288+ rootPkg = await npm . readPkg ( rootDir ) ;
289+ } catch ( e ) {
290+ if ( e . code !== 'ENOENT' ) {
291+ throw e ;
292+ }
293+ // ignore
294+ }
295+ }
296+
297+ // If we are *not* inside what looks like an existing monorepo setup,
298+ // check what packages may show up and suggest them as defaults
299+ // for the `workspaces` key
300+ if ( rootDir === opts . cwd ) {
301+ const maybeWorkspaces = await npm . searchForWorkspaces ( opts . cwd , pkg ) ;
302+ if ( maybeWorkspaces . size ) {
303+ pkg . workspaces = [ ] ;
304+ for ( const wsDir of maybeWorkspaces . values ( ) ) {
305+ pkg . workspaces . push ( path . relative ( opts . cwd , wsDir ) ) ;
306+ }
307+ }
308+ } else {
309+ // We are in a workspace context, don't ask about
310+ // workspaces and set the workspaceRoot
311+ options . overrides ( {
312+ workspaces : null ,
313+ workspaceRoot : rootDir ,
314+ workspaceRootPkg : rootPkg
315+ } ) ;
316+ }
317+ }
318+
258319 let author ;
259320 if ( ! pkg || ! pkg . author ) {
260321 const gitAuthor = await git . author ( { cwd : opts . cwd } ) ;
@@ -285,7 +346,8 @@ async function readPackageJson (options, { log } = {}) {
285346 repository : repo ,
286347 keywords : pkg . keywords ,
287348 scripts : pkg . scripts ,
288- license : pkg . license
349+ license : pkg . license ,
350+ workspaces : pkg . workspaces
289351 } ) ;
290352
291353 return packageInstance . update ( pkg ) ;
@@ -364,26 +426,86 @@ module.exports.write = write;
364426// TODO: look at https://npm.im/json-file-plus for writing
365427async function write ( opts , pkg , { log } = { } ) {
366428 const pkgPath = path . resolve ( opts . cwd , 'package.json' ) ;
429+
430+ // Ensure directory exists
431+ await fs . mkdirp ( path . dirname ( pkgPath ) ) ;
432+
367433 // Write package json
368434 log . info ( `Writing package.json\n${ pkgPath } ` ) ;
369435 await pkg . save ( ) ;
370436
437+ // If we dont have workspaceRootPkg then we are
438+ // already working on the root workspace package.json
439+ // which means we don't need to do anything with updating
440+ // the monorepo
441+ let workspaceRelativePath = null ;
442+ if ( opts . workspaceRoot && opts . workspaceRootPkg ) {
443+ workspaceRelativePath = path . relative ( opts . workspaceRoot , opts . cwd ) ;
444+
445+ // Check if this wis already part of the workspace
446+ const ws = await mapWorkspaces ( {
447+ pkg : opts . workspaceRootPkg ,
448+ cwd : opts . workspaceRoot
449+ } ) ;
450+ if ( Array . from ( ws . values ( ) ) . includes ( opts . cwd ) ) {
451+ log . debug ( 'Workspaces globs already match the new package path, no update necessary' ) ;
452+ } else {
453+ log . info ( 'Adding new package to workspace root package.json' ) ;
454+ const rootPkg = await load ( opts . workspaceRoot ) ;
455+ rootPkg . update ( {
456+ workspaces : [ ...( opts . workspaceRootPkg . workspaces || [ ] ) , workspaceRelativePath ]
457+ } ) ;
458+ await rootPkg . save ( ) ;
459+ }
460+
461+ log . info ( 'Running install' , {
462+ directory : opts . workspaceRoot || opts . cwd
463+ } ) ;
464+ const out = await npm . install ( null , {
465+ directory : opts . workspaceRoot || opts . cwd
466+ } ) ;
467+ if ( out . stderr ) {
468+ log . error ( out . stderr ) ;
469+ }
470+ log . debug ( out . stdout ) ;
471+ }
472+
371473 // Run installs
372474 if ( opts . dependencies && opts . dependencies . length ) {
373- log . info ( 'Installing dependencies' , opts . dependencies ) ;
374- await npm . install ( opts . dependencies , {
475+ log . info ( 'Installing dependencies' , {
476+ save : 'prod' ,
477+ directory : opts . workspaceRoot || opts . cwd ,
478+ exact : ! ! opts . saveExact ,
479+ workspace : workspaceRelativePath
480+ } ) ;
481+ const out = await npm . install ( opts . dependencies , {
375482 save : 'prod' ,
376- directory : opts . cwd ,
377- exact : ! ! opts . saveExact
483+ directory : opts . workspaceRoot || opts . cwd ,
484+ exact : ! ! opts . saveExact ,
485+ workspace : workspaceRelativePath
378486 } ) ;
487+ if ( out . stderr ) {
488+ log . error ( out . stderr ) ;
489+ }
490+ log . debug ( out . stdout ) ;
379491 }
380492 if ( opts . devDependencies && opts . devDependencies . length ) {
381- log . info ( 'Installing dev dependencies' , opts . devDependencies ) ;
382- await npm . install ( opts . devDependencies , {
493+ log . info ( 'Installing dev dependencies' , {
494+ save : 'dev' ,
495+ directory : opts . workspaceRoot || opts . cwd ,
496+ exact : ! ! opts . saveExact ,
497+ workspace : workspaceRelativePath
498+ } ) ;
499+ const out = await npm . install ( opts . devDependencies , {
383500 save : 'dev' ,
384- directory : opts . cwd ,
385- exact : ! ! opts . saveExact
501+ directory : opts . workspaceRoot || opts . cwd ,
502+ exact : ! ! opts . saveExact ,
503+ workspace : workspaceRelativePath
386504 } ) ;
505+ if ( out . stderr ) {
506+ log . error ( out . stderr ) ;
507+ }
508+ log . debug ( out . stdout ) ;
387509 }
388510
389511 // Read full package back to return
0 commit comments