1
- import type { Clerc , Command , HandlerContext , RootType , TranslateFn } from "@clerc/core" ;
1
+ import type { HandlerContext , RootType } from "@clerc/core" ;
2
2
import { NoSuchCommandError , Root , definePlugin , formatCommandName , resolveCommandStrict , withBrackets } from "@clerc/core" ;
3
-
4
- import { gracefulFlagName , toArray } from "@clerc/utils" ;
3
+ import { toArray } from "@clerc/utils" ;
5
4
import pc from "picocolors" ;
6
5
7
6
import type { Render , Renderers , Section } from "./renderer" ;
8
7
import { defaultRenderers , render } from "./renderer" ;
9
- import { splitTable } from "./utils" ;
8
+ import { DELIMITER , formatFlags , generateCliDetail , generateExamples , print , sortName , splitTable } from "./utils" ;
10
9
import { locales } from "./locales" ;
11
10
12
11
declare module "@clerc/core" {
@@ -15,46 +14,6 @@ declare module "@clerc/core" {
15
14
}
16
15
}
17
16
18
- const DELIMITER = pc . yellow ( "-" ) ;
19
-
20
- const print = ( s : string ) => { process . stdout . write ( s ) ; } ;
21
-
22
- const generateCliDetail = ( sections : Section [ ] , cli : Clerc , subcommand ?: Command < string | RootType > ) => {
23
- const { t } = cli . i18n ;
24
- const items = [
25
- {
26
- title : t ( "help.name" ) ! ,
27
- body : pc . red ( cli . _name ) ,
28
- } ,
29
- {
30
- title : t ( "help.version" ) ! ,
31
- body : pc . yellow ( cli . _version ) ,
32
- } ,
33
- ] ;
34
- if ( subcommand ) {
35
- items . push ( {
36
- title : t ( "help.subcommand" ) ! ,
37
- body : pc . green ( `${ cli . _name } ${ formatCommandName ( subcommand . name ) } ` ) ,
38
- } ) ;
39
- }
40
- sections . push ( {
41
- type : "inline" ,
42
- items,
43
- } ) ;
44
- sections . push ( {
45
- title : t ( "help.description" ) ! ,
46
- body : [ subcommand ?. description || cli . _description ] ,
47
- } ) ;
48
- } ;
49
-
50
- const generateExamples = ( sections : Section [ ] , examples : [ string , string ] [ ] , t : TranslateFn ) => {
51
- const examplesFormatted = examples . map ( ( [ command , description ] ) => [ command , DELIMITER , description ] ) ;
52
- sections . push ( {
53
- title : t ( "help.examples" ) ! ,
54
- body : splitTable ( examplesFormatted ) ,
55
- } ) ;
56
- } ;
57
-
58
17
const generateHelp = ( render : Render , ctx : HandlerContext , notes : string [ ] | undefined , examples : [ string , string ] [ ] | undefined ) => {
59
18
const { cli } = ctx ;
60
19
const { t } = cli . i18n ;
@@ -64,23 +23,31 @@ const generateHelp = (render: Render, ctx: HandlerContext, notes: string[] | und
64
23
title : t ( "help.usage" ) ! ,
65
24
body : [ pc . magenta ( `$ ${ cli . _name } ${ withBrackets ( "command" , ctx . hasRootOrAlias ) } [flags]` ) ] ,
66
25
} ) ;
67
- const commands = [ ...( ctx . hasRoot ? [ cli . _commands [ Root ] ! ] : [ ] ) , ...Object . values ( cli . _commands ) ] . map ( ( command ) => {
26
+ const commands = [
27
+ ...( ctx . hasRoot ? [ cli . _commands [ Root ] ! ] : [ ] ) ,
28
+ ...Object . values ( cli . _commands ) ,
29
+ ] . map ( ( command ) => {
68
30
const commandNameWithAlias = [ typeof command . name === "symbol" ? "" : command . name , ...toArray ( command . alias || [ ] ) ]
69
- . sort ( ( a , b ) => {
70
- if ( a === Root ) { return - 1 ; }
71
- if ( b === Root ) { return 1 ; }
72
- return a . length - b . length ;
73
- } )
31
+ . sort ( sortName )
74
32
. map ( ( n ) => {
75
33
return ( n === "" || typeof n === "symbol" ) ? `${ cli . _name } ` : `${ cli . _name } ${ n } ` ;
76
34
} )
77
35
. join ( ", " ) ;
78
36
return [ pc . cyan ( commandNameWithAlias ) , DELIMITER , command . description ] ;
79
37
} ) ;
80
- sections . push ( {
81
- title : t ( "help.commands" ) ! ,
82
- body : splitTable ( commands ) ,
83
- } ) ;
38
+ if ( commands . length ) {
39
+ sections . push ( {
40
+ title : t ( "help.commands" ) ! ,
41
+ body : splitTable ( commands ) ,
42
+ } ) ;
43
+ }
44
+ const globalFlags = formatFlags ( cli . _flags ) ;
45
+ if ( globalFlags . length ) {
46
+ sections . push ( {
47
+ title : t ( "help.globalFlags" ) ! ,
48
+ body : splitTable ( globalFlags ) ,
49
+ } ) ;
50
+ }
84
51
if ( notes ) {
85
52
sections . push ( {
86
53
title : t ( "help.notes" ) ! ,
@@ -118,25 +85,17 @@ const generateSubcommandHelp = (render: Render, ctx: HandlerContext, command: st
118
85
title : t ( "help.usage" ) ! ,
119
86
body : [ pc . magenta ( `$ ${ cli . _name } ${ commandName } ${ parametersString } ${ flagsString } ` ) ] ,
120
87
} ) ;
88
+ const globalFlags = formatFlags ( cli . _flags ) ;
89
+ if ( globalFlags . length ) {
90
+ sections . push ( {
91
+ title : t ( "help.globalFlags" ) ! ,
92
+ body : splitTable ( globalFlags ) ,
93
+ } ) ;
94
+ }
121
95
if ( subcommand . flags ) {
122
96
sections . push ( {
123
97
title : t ( "help.flags" ) ! ,
124
- body : splitTable (
125
- Object . entries ( subcommand . flags ) . map ( ( [ name , flag ] ) => {
126
- const hasDefault = flag . default !== undefined ;
127
- let flagNameWithAlias : string [ ] = [ gracefulFlagName ( name ) ] ;
128
- if ( flag . alias ) {
129
- flagNameWithAlias . push ( gracefulFlagName ( flag . alias ) ) ;
130
- }
131
- flagNameWithAlias = flagNameWithAlias . map ( renderers . renderFlagName ) ;
132
- const items = [ pc . blue ( flagNameWithAlias . join ( ", " ) ) , renderers . renderType ( flag . type , hasDefault ) ] ;
133
- items . push ( DELIMITER , flag . description || t ( "help.noDescription" ) ! ) ;
134
- if ( hasDefault ) {
135
- items . push ( `(${ t ( "help.default" , renderers . renderDefault ( flag . default ) ) } )` ) ;
136
- }
137
- return items ;
138
- } ) ,
139
- ) ,
98
+ body : splitTable ( formatFlags ( subcommand . flags ) ) ,
140
99
} ) ;
141
100
}
142
101
if ( subcommand . notes ) {
@@ -154,10 +113,15 @@ const generateSubcommandHelp = (render: Render, ctx: HandlerContext, command: st
154
113
155
114
export interface HelpPluginOptions {
156
115
/**
157
- * Whether to registr the help command.
116
+ * Whether to register the help command.
158
117
* @default true
159
118
*/
160
119
command ?: boolean
120
+ /**
121
+ * Whether to register the global help flag.
122
+ * @default true
123
+ */
124
+ flag ?: boolean
161
125
/**
162
126
* Whether to show help when no command is specified.
163
127
* @default true
@@ -172,12 +136,13 @@ export interface HelpPluginOptions {
172
136
*/
173
137
examples ?: [ string , string ] [ ]
174
138
/**
175
- * Banner
139
+ * Banner.
176
140
*/
177
141
banner ?: string
178
142
}
179
143
export const helpPlugin = ( {
180
144
command = true ,
145
+ flag = true ,
181
146
showHelpWhenNoCommand = true ,
182
147
notes,
183
148
examples,
@@ -192,7 +157,7 @@ export const helpPlugin = ({
192
157
} ;
193
158
194
159
if ( command ) {
195
- cli = cli . command ( "help" , t ( "help.commandDescription " ) ! , {
160
+ cli = cli . command ( "help" , t ( "help.helpDdescription " ) ! , {
196
161
parameters : [
197
162
"[command...]" ,
198
163
] ,
@@ -216,15 +181,23 @@ export const helpPlugin = ({
216
181
} ) ;
217
182
}
218
183
184
+ if ( flag ) {
185
+ cli = cli . flag ( "help" , t ( "help.helpDdescription" ) ! , {
186
+ alias : "h" ,
187
+ type : Boolean ,
188
+ default : false ,
189
+ } ) ;
190
+ }
191
+
219
192
cli . inspector ( ( ctx , next ) => {
220
- const helpFlag = ctx . raw . mergedFlags . h || ctx . raw . mergedFlags . help ;
221
- if ( ! ctx . hasRootOrAlias && ! ctx . raw . _ . length && showHelpWhenNoCommand && ! helpFlag ) {
193
+ const shouldShowHelp = ctx . flags . help ;
194
+ if ( ! ctx . hasRootOrAlias && ! ctx . raw . _ . length && showHelpWhenNoCommand && ! shouldShowHelp ) {
222
195
let str = `${ t ( "core.noCommandGiven" ) } \n\n` ;
223
196
str += generateHelp ( render , ctx , notes , examples ) ;
224
197
str += "\n" ;
225
198
printHelp ( str ) ;
226
199
process . exit ( 1 ) ;
227
- } else if ( helpFlag ) {
200
+ } else if ( shouldShowHelp ) {
228
201
if ( ctx . raw . _ . length ) {
229
202
if ( ctx . called !== Root ) {
230
203
if ( ctx . name === Root ) {
0 commit comments