11#!/usr/bin/env node
22import chalk from "chalk"
33import merge from "lodash/merge"
4- import { clearLine } from "node:readline"
54import path from "path"
6- import { color , COLOR_CODE_LEN , wrap } from "./utils"
5+ import { ArrayOr , asArray , color , COLOR_CODE_LEN , wrap } from "./utils"
76
87export function massarg ( ) {
98 return new Massarg ( )
@@ -21,7 +20,7 @@ export interface OptionDef<Options, Value> {
2120 description ?: string
2221 defaultValue ?: Value
2322 boolean ?: boolean
24- command ?: string
23+ commands ?: ArrayOr < string >
2524 parse ?( value : string , options : Options ) : Value
2625}
2726
@@ -35,9 +34,10 @@ export interface CommandDef<T> {
3534export interface HelpDef {
3635 printWidth ?: number
3736 binName ?: string
38- normalColor ?: keyof typeof chalk
39- highlightColor ?: keyof typeof chalk
40- titleColor ?: keyof typeof chalk
37+ normalColors ?: ArrayOr < keyof typeof chalk >
38+ highlightColors ?: ArrayOr < keyof typeof chalk >
39+ titleColors ?: ArrayOr < keyof typeof chalk >
40+ subtitleColors ?: ArrayOr < keyof typeof chalk >
4141 header ?: string
4242 footer ?: string
4343 commandNameSeparator ?: string
@@ -55,9 +55,10 @@ export class Massarg<Options extends OptionsBase = OptionsBase> {
5555
5656 private _help : Required < HelpDef > = {
5757 binName : undefined as any ,
58- normalColor : "dim" ,
59- highlightColor : "yellow" ,
60- titleColor : "white" ,
58+ normalColors : "dim" ,
59+ highlightColors : "yellow" ,
60+ titleColors : "white" ,
61+ subtitleColors : "dim" ,
6162 printWidth : 80 ,
6263 header : "" ,
6364 footer : "" ,
@@ -99,33 +100,31 @@ export class Massarg<Options extends OptionsBase = OptionsBase> {
99100 public printHelp ( args ?: string [ ] ) : void {
100101 this . parseArgs ( args )
101102
102- const { highlightColor , normalColor , titleColor , binName } = this . _help
103+ const { highlightColors , normalColors , titleColors , binName } = this . _help
103104
104105 console . log (
105- color ( titleColor , chalk . bold `Usage:` ) ,
106- color ( highlightColor , binName ?? path . basename ( process . argv [ 1 ] ) ) ,
107- color ( normalColor , "[command] [options]" )
106+ color ( titleColors , chalk . bold `Usage:` ) ,
107+ color ( highlightColors , binName ?? path . basename ( process . argv [ 1 ] ) ) ,
108+ color ( normalColors , "[command] [options]" )
108109 )
109110
110111 if ( this . _help . header ) {
111112 console . log ( )
112- console . log ( color ( titleColor , this . _help . header ) )
113+ console . log ( color ( titleColors , this . _help . header ) )
113114 }
114115
115116 if ( this . _commands . length ) {
116117 console . log ( "" )
117- console . log ( color ( titleColor , chalk . bold `Commands:` ) )
118+ console . log ( color ( titleColors , chalk . bold `Commands:` ) )
118119 this . _printCommands ( )
119120 }
120121
121122 console . log ( )
122-
123- console . log ( color ( titleColor , chalk . bold `Options:` ) )
124123 this . _printOptions ( )
125124
126125 if ( this . _help . footer ) {
127126 console . log ( )
128- console . log ( color ( titleColor , this . _help . footer ) )
127+ console . log ( color ( titleColors , this . _help . footer ) )
129128 }
130129 }
131130
@@ -203,6 +202,7 @@ export class Massarg<Options extends OptionsBase = OptionsBase> {
203202 }
204203
205204 private _getWrappedLines ( list : Array < { name : string ; description ? : string } > ) : string [ ] {
205+ const { normalColors, highlightColors } = this . _help
206206 const lines : string [ ] = [ ]
207207
208208 let maxNameLen = this . _help . useGlobalColumns ? this . _maxNameLen ?? 0 : 0
@@ -221,8 +221,11 @@ export class Massarg<Options extends OptionsBase = OptionsBase> {
221221 const nameFullSize = maxNameLen + ARG_SPACE_LEN + INDENT_LEN
222222
223223 for ( const item of list ) {
224- const cmdName = chalk . yellow ( `${ item . name } ` ) . padEnd ( nameFullSize + ( COLOR_COUNT - 1 ) * COLOR_CODE_LEN , " " )
225- const cmdDescr = chalk . dim ( item . description ?? "" )
224+ const cmdName = color ( highlightColors , `${ item . name } ` ) . padEnd (
225+ nameFullSize + ( COLOR_COUNT - 1 ) * COLOR_CODE_LEN ,
226+ " "
227+ )
228+ const cmdDescr = color ( normalColors , item . description ?? "" )
226229
227230 for ( const line of wrap ( cmdName + cmdDescr , {
228231 indent : nameFullSize + INDENT_LEN ,
@@ -248,21 +251,69 @@ export class Massarg<Options extends OptionsBase = OptionsBase> {
248251 }
249252
250253 private _printOptions ( ) {
251- for ( const line of this . _getWrappedLines (
252- this . _options . map ( ( c ) => ( { name : this . _fullOptName ( c ) , description : c . description } ) )
253- ) ) {
254- if ( line . trim ( ) . length ) {
255- console . log ( line )
254+ let printedTitle = false
255+ const { titleColors , subtitleColors } = this . _help
256+
257+ const commandOpts : string [ ] = [ ]
258+
259+ for ( const cmd of this . _commands ) {
260+ const opts = this . _commandOptions ( cmd )
261+ if ( opts . length ) {
262+ commandOpts . push ( color ( subtitleColors , `${ cmd . name } :` ) )
263+ for ( const line of this . _getWrappedLines (
264+ opts . map ( ( c ) => ( { name : this . _fullOptName ( c ) , description : c . description } ) )
265+ ) ) {
266+ if ( line . trim ( ) . length ) {
267+ commandOpts . push ( line )
268+ }
269+ }
270+ }
271+ }
272+
273+ console . log ( color ( titleColors , chalk . bold `${ commandOpts . length ? "Command Options" : "Options" } :` ) )
274+ // if (commandOpts.length) {
275+ console . log ( )
276+ // }
277+
278+ for ( const line of commandOpts ) {
279+ console . log ( line )
280+ }
281+
282+ const globalOpts = this . _globalOptions ( )
283+ if ( globalOpts . length ) {
284+ if ( commandOpts . length ) {
285+ console . log ( chalk . bold `Global Options:` )
286+ console . log ( )
287+ }
288+ for ( const line of this . _getWrappedLines (
289+ globalOpts . map ( ( c ) => ( { name : this . _fullOptName ( c ) , description : c . description } ) )
290+ ) ) {
291+ if ( line . trim ( ) . length ) {
292+ console . log ( line )
293+ }
256294 }
257295 }
258296 }
259297
260298 private _fullCmdName ( cmd : CommandDef < Options > ) {
261299 return [ cmd . name , ...( cmd . aliases ?? [ ] ) ] . join ( this . _help . commandNameSeparator )
262300 }
301+
263302 private _fullOptName ( opt : OptionDef < Options , any > ) {
264303 return [ `--${ opt . name } ` , ...( opt . aliases ?? [ ] ) . map ( ( a ) => `-${ a } ` ) ] . join ( this . _help . optionNameSeparator )
265304 }
305+
306+ private _commandOptions ( cmd : CommandDef < Options > ) : OptionDef < Options , any > [ ] {
307+ return this . _options . filter (
308+ ( o ) =>
309+ ( asArray ( o . commands ) . length && asArray ( o . commands ) . includes ( cmd . name ) ) ||
310+ cmd . aliases ?. some ( ( a ) => asArray ( o . commands ) . includes ( a ) )
311+ )
312+ }
313+
314+ private _globalOptions ( ) : OptionDef < Options , any > [ ] {
315+ return this . _options . filter ( ( o ) => ! o . commands )
316+ }
266317}
267318
268319massarg ( )
@@ -285,6 +336,7 @@ massarg()
285336 aliases : [ "n" ] ,
286337 description : "This is a number arg, if you include this option, you must supply it with a value." ,
287338 defaultValue : 0 ,
339+ commands : [ "do" ] ,
288340 parse : ( v ) => parseInt ( v ) ,
289341 } )
290342 . command ( {
0 commit comments