@@ -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,120 @@ 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 === '.'
107+
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 ) } `
117+ }
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+ await Promise . all (
128+ data . map ( ( v ) => this . prettyView ( pckmnt , v [ Object . keys ( v ) [ 0 ] ] [ '' ] ) )
129+ )
130+ } else {
131+ // JSON formatted output (JSON or specific attributes from packument)
132+ let reducedData = data . reduce ( reducer , { } )
133+ if ( wholePackument ) {
134+ // No attributes
135+ reducedData = cleanBlanks ( reducedData )
136+ log . silly ( 'view' , reducedData )
137+ }
138+ // disable the progress bar entirely, as we can't meaningfully update it if
139+ // we may have partial lines printed.
140+ log . disableProgress ( )
141+
142+ const msg = await this . jsonData ( reducedData , pckmnt . _id )
143+ if ( msg !== '' )
144+ console . log ( msg )
145+ }
146+ }
147+
148+ async viewWorkspaces ( args , filters ) {
149+ if ( ! args . length ) {
150+ args = [ '.' ]
151+ }
152+
153+ let pkg = args . shift ( )
91154
155+ const local = / ^ \. @ / . test ( pkg ) || pkg === '.'
156+ if ( ! local ) {
157+ this . npm . log . warn ( 'Ignoring workspaces for remote package' )
158+ return this . view ( [ pkg , ...args ] )
159+ }
160+
161+ let wholePackument = false
162+ if ( ! args . length ) {
163+ wholePackument = true
164+ args = [ '' ] //getData relies on this
165+ }
166+ const results = { }
167+ const workspaces = await getWorkspaces ( filters , { path : this . npm . localPrefix } )
168+ for ( const workspace of [ ...workspaces . entries ( ) ] ) {
169+ const wsPkg = `${ workspace [ 0 ] } ${ pkg . slice ( 1 ) } `
170+ const [ pckmnt , data ] = await this . getData ( wsPkg , args )
171+
172+ let reducedData = data . reduce ( reducer , { } )
173+ if ( wholePackument ) {
174+ // No attributes
175+ reducedData = cleanBlanks ( reducedData )
176+ log . silly ( 'view' , reducedData )
177+ }
178+
179+ if ( ! this . npm . config . get ( 'json' ) ) {
180+ if ( wholePackument ) {
181+ data . map ( ( v ) => this . prettyView ( pckmnt , v [ Object . keys ( v ) [ 0 ] ] [ '' ] ) )
182+ } else {
183+ console . log ( workspace [ 0 ] )
184+ const msg = await this . jsonData ( reducedData , pckmnt . _id )
185+ if ( msg !== '' )
186+ console . log ( msg )
187+ }
188+ } else {
189+ const msg = await this . jsonData ( reducedData , pckmnt . _id )
190+ if ( msg !== '' )
191+ results [ workspace [ 0 ] ] = JSON . parse ( msg )
192+ }
193+ }
194+ if ( Object . keys ( results ) . length > 0 ) {
195+ console . log ( results )
196+ }
197+ }
198+
199+ async getData ( pkg , args ) {
92200 const opts = {
93201 ...this . npm . flatOptions ,
94202 preferOnline : true ,
95203 fullMetadata : true ,
96204 }
97- 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 )
103205
104- const name = nv . name
105- const local = ( name === '.' || ! name )
106-
107- if ( this . npm . config . get ( 'global' ) && local )
108- throw new Error ( 'Cannot use view command in global mode.' )
109-
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 ( '@' ) ]
119- }
206+ const spec = npa ( pkg )
120207
121208 // get the data about this package
122- let version = nv . rawSpec || this . npm . config . get ( 'tag' )
209+ let version = spec . rawSpec || this . npm . config . get ( 'tag' )
123210
124- const pckmnt = await packument ( nv , opts )
211+ const pckmnt = await packument ( spec , opts )
125212
126213 if ( pckmnt [ 'dist-tags' ] && pckmnt [ 'dist-tags' ] [ version ] )
127214 version = pckmnt [ 'dist-tags' ] [ version ]
@@ -135,11 +222,9 @@ class View extends BaseCommand {
135222 throw er
136223 }
137224
138- const results = [ ]
225+ const data = [ ]
139226 const versions = pckmnt . versions || { }
140227 pckmnt . versions = Object . keys ( versions ) . sort ( semver . compareLoose )
141- if ( ! args . length )
142- args = [ '' ]
143228
144229 // remove readme unless we asked for it
145230 if ( args . indexOf ( 'readme' ) === - 1 )
@@ -152,36 +237,22 @@ class View extends BaseCommand {
152237 if ( args . indexOf ( 'readme' ) !== - 1 )
153238 delete versions [ v ] . readme
154239
155- results . push ( showFields ( pckmnt , versions [ v ] , arg ) )
240+ data . push ( showFields ( pckmnt , versions [ v ] , arg ) )
156241 } )
157242 }
158243 } )
159- let retval = results . reduce ( reducer , { } )
160-
161- if ( args . length === 1 && args [ 0 ] === '' ) {
162- retval = cleanBlanks ( retval )
163- log . silly ( 'view' , retval )
164- }
165244
166245 if (
167246 ! this . npm . config . get ( 'json' ) &&
168247 args . length === 1 &&
169248 args [ 0 ] === ''
170- ) {
171- // general view
249+ )
172250 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- }
251+
252+ return [ pckmnt , data ]
182253 }
183254
184- async printData ( data , name ) {
255+ async jsonData ( data , name ) {
185256 const versions = Object . keys ( data )
186257 let msg = ''
187258 let msgJson = [ ]
@@ -233,13 +304,7 @@ class View extends BaseCommand {
233304 msg = JSON . stringify ( msgJson , null , 2 ) + '\n'
234305 }
235306
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 ( ) )
307+ return msg . trim ( )
243308 }
244309
245310 async prettyView ( packument , manifest ) {
@@ -375,17 +440,18 @@ function cleanBlanks (obj) {
375440 return clean
376441}
377442
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 ]
443+ // takes an array of objects and merges them into one object
444+ function reducer ( acc , cur ) {
445+ if ( cur ) {
446+ Object . keys ( cur ) . forEach ( ( v ) => {
447+ acc [ v ] = acc [ v ] || { }
448+ Object . keys ( cur [ v ] ) . forEach ( ( t ) => {
449+ acc [ v ] [ t ] = cur [ v ] [ t ]
384450 } )
385451 } )
386452 }
387453
388- return l
454+ return acc
389455}
390456
391457// return whatever was printed
0 commit comments