1- const { spawn } = require ( 'child_process ' )
1+ const spawn = require ( '@npmcli/promise-spawn ' )
22const path = require ( 'path' )
33const openUrl = require ( '../utils/open-url.js' )
44const { promisify } = require ( 'util' )
@@ -14,19 +14,26 @@ const BaseCommand = require('../base-command.js')
1414const manNumberRegex = / \. ( \d + ) ( \. [ ^ / \\ ] * ) ? $ /
1515// Searches for the "npm-" prefix in page names, to prefer those.
1616const manNpmPrefixRegex = / \/ n p m - /
17+ // hardcoded names for mansections
18+ // XXX: these are used in the docs workspace and should be exported
19+ // from npm so section names can changed more easily
20+ const manSectionNames = {
21+ 1 : 'commands' ,
22+ 5 : 'configuring-npm' ,
23+ 7 : 'using-npm' ,
24+ }
1725
1826class Help extends BaseCommand {
1927 static description = 'Get help on npm'
2028 static name = 'help'
2129 static usage = [ '<term> [<terms..>]' ]
2230 static params = [ 'viewer' ]
23- static ignoreImplicitWorkspace = true
2431
2532 async completion ( opts ) {
2633 if ( opts . conf . argv . remain . length > 2 ) {
2734 return [ ]
2835 }
29- const g = path . resolve ( __dirname , '../../ man/man[0-9]/*.[0-9]' )
36+ const g = path . resolve ( this . npm . npmRoot , 'man/man[0-9]/*.[0-9]' )
3037 const files = await glob ( globify ( g ) )
3138
3239 return Object . keys ( files . reduce ( function ( acc , file ) {
@@ -40,10 +47,7 @@ class Help extends BaseCommand {
4047 async exec ( args ) {
4148 // By default we search all of our man subdirectories, but if the user has
4249 // asked for a specific one we limit the search to just there
43- let manSearch = 'man*'
44- if ( / ^ \d + $ / . test ( args [ 0 ] ) ) {
45- manSearch = `man${ args . shift ( ) } `
46- }
50+ const manSearch = / ^ \d + $ / . test ( args [ 0 ] ) ? `man${ args . shift ( ) } ` : 'man*'
4751
4852 if ( ! args . length ) {
4953 return this . npm . output ( await this . npm . usage )
@@ -54,20 +58,18 @@ class Help extends BaseCommand {
5458 return this . helpSearch ( args )
5559 }
5660
57- let section = this . npm . deref ( args [ 0 ] ) || args [ 0 ]
58-
59- // support `npm help package.json`
60- section = section . replace ( '.json' , '-json' )
61+ // `npm help package.json`
62+ const arg = ( this . npm . deref ( args [ 0 ] ) || args [ 0 ] ) . replace ( '.json' , '-json' )
6163
62- const manroot = path . resolve ( __dirname , '..' , '..' , 'man' )
6364 // find either section.n or npm-section.n
64- const f = ` ${ manroot } /${ manSearch } /?(npm-)${ section } .[0-9]*`
65- let mans = await glob ( globify ( f ) )
66- mans = mans . sort ( ( a , b ) => {
65+ const f = globify ( path . resolve ( this . npm . npmRoot , `man /${ manSearch } /?(npm-)${ arg } .[0-9]*`) )
66+
67+ const [ man ] = await glob ( f ) . then ( r => r . sort ( ( a , b ) => {
6768 // Prefer the page with an npm prefix, if there's only one.
6869 const aHasPrefix = manNpmPrefixRegex . test ( a )
6970 const bHasPrefix = manNpmPrefixRegex . test ( b )
7071 if ( aHasPrefix !== bHasPrefix ) {
72+ /* istanbul ignore next */
7173 return aHasPrefix ? - 1 : 1
7274 }
7375
@@ -76,6 +78,7 @@ class Help extends BaseCommand {
7678 const aManNumberMatch = a . match ( manNumberRegex )
7779 const bManNumberMatch = b . match ( manNumberRegex )
7880 if ( aManNumberMatch ) {
81+ /* istanbul ignore next */
7982 if ( ! bManNumberMatch ) {
8083 return - 1
8184 }
@@ -88,77 +91,41 @@ class Help extends BaseCommand {
8891 }
8992
9093 return localeCompare ( a , b )
91- } )
92- const man = mans [ 0 ]
94+ } ) )
9395
94- if ( man ) {
95- await this . viewMan ( man )
96- } else {
97- return this . helpSearch ( args )
98- }
96+ return man ? this . viewMan ( man ) : this . helpSearch ( args )
9997 }
10098
10199 helpSearch ( args ) {
102100 return this . npm . exec ( 'help-search' , args )
103101 }
104102
105103 async viewMan ( man ) {
106- const env = { }
107- Object . keys ( process . env ) . forEach ( function ( i ) {
108- env [ i ] = process . env [ i ]
109- } )
110104 const viewer = this . npm . config . get ( 'viewer' )
111105
112- const opts = {
113- env,
114- stdio : 'inherit' ,
106+ if ( viewer === 'browser' ) {
107+ return openUrl ( this . npm , this . htmlMan ( man ) , 'help available at the following URL' , true )
115108 }
116109
117- let bin = 'man'
118- const args = [ ]
119- switch ( viewer ) {
120- case 'woman' :
121- bin = 'emacsclient'
122- args . push ( '-e' , `(woman-find-file '${ man } ')` )
123- break
124-
125- case 'browser' :
126- await openUrl ( this . npm , this . htmlMan ( man ) , 'help available at the following URL' , true )
127- return
128-
129- default :
130- args . push ( man )
131- break
110+ let args = [ 'man' , [ man ] ]
111+ if ( viewer === 'woman' ) {
112+ args = [ 'emacsclient' , [ '-e' , `(woman-find-file '${ man } ')` ] ]
132113 }
133114
134- const proc = spawn ( bin , args , opts )
135- return new Promise ( ( resolve , reject ) => {
136- proc . on ( 'exit' , ( code ) => {
137- if ( code ) {
138- return reject ( new Error ( `help process exited with code: ${ code } ` ) )
139- }
140-
141- return resolve ( )
142- } )
115+ return spawn ( ...args , { stdio : 'inherit' } ) . catch ( err => {
116+ if ( err . code ) {
117+ throw new Error ( `help process exited with code: ${ err . code } ` )
118+ } else {
119+ throw err
120+ }
143121 } )
144122 }
145123
146124 // Returns the path to the html version of the man page
147125 htmlMan ( man ) {
148- let sect = man . match ( manNumberRegex ) [ 1 ]
126+ const sect = manSectionNames [ man . match ( manNumberRegex ) [ 1 ] ]
149127 const f = path . basename ( man ) . replace ( manNumberRegex , '' )
150- switch ( sect ) {
151- case '1' :
152- sect = 'commands'
153- break
154- case '5' :
155- sect = 'configuring-npm'
156- break
157- case '7' :
158- sect = 'using-npm'
159- break
160- }
161- return 'file:///' + path . resolve ( __dirname , '..' , '..' , 'docs' , 'output' , sect , f + '.html' )
128+ return 'file:///' + path . resolve ( this . npm . npmRoot , `docs/output/${ sect } /${ f } .html` )
162129 }
163130}
164131module . exports = Help
0 commit comments