@@ -7,12 +7,13 @@ const fs = require('fs')
77const jsonParse = require ( 'json-parse-even-better-errors' )
88const log = require ( 'npmlog' )
99const npa = require ( 'npm-package-arg' )
10- const path = require ( 'path' )
10+ const { resolve } = require ( 'path' )
1111const relativeDate = require ( 'tiny-relative-date' )
1212const semver = require ( 'semver' )
1313const style = require ( 'ansistyles' )
1414const { inspect, promisify } = require ( 'util' )
1515const { packument } = require ( 'pacote' )
16+ const getWorkspaces = require ( './workspaces/get-workspaces.js' )
1617
1718const readFile = promisify ( fs . readFile )
1819const readJson = async file => jsonParse ( await readFile ( file , 'utf8' ) )
@@ -24,6 +25,15 @@ class View extends BaseCommand {
2425 return 'View registry info'
2526 }
2627
28+ /* istanbul ignore next - see test/lib/load-all-commands.js */
29+ static get params ( ) {
30+ return [
31+ 'json' ,
32+ 'workspace' ,
33+ 'workspaces' ,
34+ ]
35+ }
36+
2737 /* istanbul ignore next - see test/lib/load-all-commands.js */
2838 static get name ( ) {
2939 return 'view'
@@ -85,43 +95,116 @@ class View extends BaseCommand {
8595 this . view ( args ) . then ( ( ) => cb ( ) ) . catch ( cb )
8696 }
8797
98+ execWorkspaces ( args , filters , cb ) {
99+ this . viewWorkspaces ( args , filters ) . then ( ( ) => cb ( ) ) . catch ( cb )
100+ }
101+
88102 async view ( args ) {
89103 if ( ! args . length )
90104 args = [ '.' ]
105+ let pkg = args . shift ( )
106+ const local = / ^ \. @ / . test ( pkg ) || pkg === '.'
91107
92- const opts = {
93- ...this . npm . flatOptions ,
94- preferOnline : true ,
95- fullMetadata : true ,
108+ if ( local ) {
109+ if ( this . npm . config . get ( 'global' ) )
110+ throw new Error ( 'Cannot use view command in global mode.' )
111+ const dir = this . npm . prefix
112+ const manifest = await readJson ( resolve ( dir , 'package.json' ) )
113+ if ( ! manifest . name )
114+ throw new Error ( 'Invalid package.json, no "name" field' )
115+ // put the version back if it existed
116+ pkg = `${ manifest . name } ${ pkg . slice ( 1 ) } `
96117 }
118+ let wholePackument = false
119+ if ( ! args . length ) {
120+ args = [ '' ]
121+ wholePackument = true
122+ }
123+ const [ pckmnt , data ] = await this . getData ( pkg , args )
124+
125+ if ( ! this . npm . config . get ( 'json' ) && wholePackument ) {
126+ // pretty view (entire packument)
127+ data . map ( ( v ) => this . prettyView ( pckmnt , v [ Object . keys ( v ) [ 0 ] ] [ '' ] ) )
128+ } else {
129+ // JSON formatted output (JSON or specific attributes from packument)
130+ let reducedData = data . reduce ( reducer , { } )
131+ if ( wholePackument ) {
132+ // No attributes
133+ reducedData = cleanBlanks ( reducedData )
134+ log . silly ( 'view' , reducedData )
135+ }
136+ // disable the progress bar entirely, as we can't meaningfully update it
137+ // if we may have partial lines printed.
138+ log . disableProgress ( )
139+
140+ const msg = await this . jsonData ( reducedData , pckmnt . _id )
141+ if ( msg !== '' )
142+ console . log ( msg )
143+ }
144+ }
145+
146+ async viewWorkspaces ( args , filters ) {
147+ if ( ! args . length )
148+ args = [ '.' ]
149+
97150 const pkg = args . shift ( )
98- let nv
99- if ( / ^ [ . ] @ / . test ( pkg ) )
100- nv = npa . resolve ( null , pkg . slice ( 2 ) )
101- else
102- nv = npa ( pkg )
103151
104- const name = nv . name
105- const local = ( name === '.' || ! name )
152+ const local = / ^ \. @ / . test ( pkg ) || pkg === '.'
153+ if ( ! local ) {
154+ this . npm . log . warn ( 'Ignoring workspaces for remote package' )
155+ return this . view ( [ pkg , ...args ] )
156+ }
157+ let wholePackument = false
158+ if ( ! args . length ) {
159+ wholePackument = true
160+ args = [ '' ] // getData relies on this
161+ }
162+ const results = { }
163+ const workspaces =
164+ await getWorkspaces ( filters , { path : this . npm . localPrefix } )
165+ for ( const workspace of [ ...workspaces . entries ( ) ] ) {
166+ const wsPkg = `${ workspace [ 0 ] } ${ pkg . slice ( 1 ) } `
167+ const [ pckmnt , data ] = await this . getData ( wsPkg , args )
168+
169+ let reducedData = data . reduce ( reducer , { } )
170+ if ( wholePackument ) {
171+ // No attributes
172+ reducedData = cleanBlanks ( reducedData )
173+ log . silly ( 'view' , reducedData )
174+ }
106175
107- if ( this . npm . config . get ( 'global' ) && local )
108- throw new Error ( 'Cannot use view command in global mode.' )
176+ if ( ! this . npm . config . get ( 'json' ) ) {
177+ if ( wholePackument )
178+ data . map ( ( v ) => this . prettyView ( pckmnt , v [ Object . keys ( v ) [ 0 ] ] [ '' ] ) )
179+ else {
180+ console . log ( `${ workspace [ 0 ] } :` )
181+ const msg = await this . jsonData ( reducedData , pckmnt . _id )
182+ if ( msg !== '' )
183+ console . log ( msg )
184+ }
185+ } else {
186+ const msg = await this . jsonData ( reducedData , pckmnt . _id )
187+ if ( msg !== '' )
188+ results [ workspace [ 0 ] ] = JSON . parse ( msg )
189+ }
190+ }
191+ if ( Object . keys ( results ) . length > 0 )
192+ console . log ( JSON . stringify ( results , null , 2 ) )
193+ }
109194
110- if ( local ) {
111- const dir = this . npm . prefix
112- const manifest = await readJson ( path . resolve ( dir , 'package.json' ) )
113- if ( ! manifest . name )
114- throw new Error ( 'Invalid package.json, no "name" field' )
115- const p = manifest . name
116- nv = npa ( p )
117- if ( pkg && ~ pkg . indexOf ( '@' ) )
118- nv . rawSpec = pkg . split ( '@' ) [ pkg . indexOf ( '@' ) ]
195+ async getData ( pkg , args ) {
196+ const opts = {
197+ ...this . npm . flatOptions ,
198+ preferOnline : true ,
199+ fullMetadata : true ,
119200 }
120201
202+ const spec = npa ( pkg )
203+
121204 // get the data about this package
122- let version = nv . rawSpec || this . npm . config . get ( 'tag' )
205+ let version = spec . rawSpec || this . npm . config . get ( 'tag' )
123206
124- const pckmnt = await packument ( nv , opts )
207+ const pckmnt = await packument ( spec , opts )
125208
126209 if ( pckmnt [ 'dist-tags' ] && pckmnt [ 'dist-tags' ] [ version ] )
127210 version = pckmnt [ 'dist-tags' ] [ version ]
@@ -135,11 +218,9 @@ class View extends BaseCommand {
135218 throw er
136219 }
137220
138- const results = [ ]
221+ const data = [ ]
139222 const versions = pckmnt . versions || { }
140223 pckmnt . versions = Object . keys ( versions ) . sort ( semver . compareLoose )
141- if ( ! args . length )
142- args = [ '' ]
143224
144225 // remove readme unless we asked for it
145226 if ( args . indexOf ( 'readme' ) === - 1 )
@@ -152,36 +233,22 @@ class View extends BaseCommand {
152233 if ( args . indexOf ( 'readme' ) !== - 1 )
153234 delete versions [ v ] . readme
154235
155- results . push ( showFields ( pckmnt , versions [ v ] , arg ) )
236+ data . push ( showFields ( pckmnt , versions [ v ] , arg ) )
156237 } )
157238 }
158239 } )
159- let retval = results . reduce ( reducer , { } )
160-
161- if ( args . length === 1 && args [ 0 ] === '' ) {
162- retval = cleanBlanks ( retval )
163- log . silly ( 'view' , retval )
164- }
165240
166241 if (
167242 ! this . npm . config . get ( 'json' ) &&
168243 args . length === 1 &&
169244 args [ 0 ] === ''
170- ) {
171- // general view
245+ )
172246 pckmnt . version = version
173- await Promise . all (
174- results . map ( ( v ) => this . prettyView ( pckmnt , v [ Object . keys ( v ) [ 0 ] ] [ '' ] ) )
175- )
176- return retval
177- } else {
178- // view by field name
179- await this . printData ( retval , pckmnt . _id )
180- return retval
181- }
247+
248+ return [ pckmnt , data ]
182249 }
183250
184- async printData ( data , name ) {
251+ async jsonData ( data , name ) {
185252 const versions = Object . keys ( data )
186253 let msg = ''
187254 let msgJson = [ ]
@@ -233,16 +300,10 @@ class View extends BaseCommand {
233300 msg = JSON . stringify ( msgJson , null , 2 ) + '\n'
234301 }
235302
236- // disable the progress bar entirely, as we can't meaningfully update it if
237- // we may have partial lines printed.
238- log . disableProgress ( )
239-
240- // only log if there is something to log
241- if ( msg !== '' )
242- console . log ( msg . trim ( ) )
303+ return msg . trim ( )
243304 }
244305
245- async prettyView ( packument , manifest ) {
306+ prettyView ( packument , manifest ) {
246307 // More modern, pretty printing of default view
247308 const unicode = this . npm . config . get ( 'unicode' )
248309 const tags = [ ]
@@ -375,17 +436,18 @@ function cleanBlanks (obj) {
375436 return clean
376437}
377438
378- function reducer ( l , r ) {
379- if ( r ) {
380- Object . keys ( r ) . forEach ( ( v ) => {
381- l [ v ] = l [ v ] || { }
382- Object . keys ( r [ v ] ) . forEach ( ( t ) => {
383- l [ v ] [ t ] = r [ v ] [ t ]
439+ // takes an array of objects and merges them into one object
440+ function reducer ( acc , cur ) {
441+ if ( cur ) {
442+ Object . keys ( cur ) . forEach ( ( v ) => {
443+ acc [ v ] = acc [ v ] || { }
444+ Object . keys ( cur [ v ] ) . forEach ( ( t ) => {
445+ acc [ v ] [ t ] = cur [ v ] [ t ]
384446 } )
385447 } )
386448 }
387449
388- return l
450+ return acc
389451}
390452
391453// return whatever was printed
0 commit comments