@@ -23,10 +23,13 @@ import {
2323const OPTIONS_SECTION_RE = / ^ \s * O p t i o n s : / i;
2424const LEVEL_MATCH_RE = / (?: l e v e l s ? | o p t i o n s ? | v a l u e s ? ) [ ^ : ] * : \s * ( [ ^ . ] + ) / i;
2525const LINE_SPLIT_RE = / \r ? \n / ;
26- const REPORTER_LINE_RE = / ^ \s * - - r e p o r t e r \s + \w / ;
27- const REPORTER_MATCH_RE = / ^ \s * - - r e p o r t e r \s + ( \w + (?: - \w + ) * ) \s + ( .+ ) $ / ;
28- const SILENT_REPORTER_RE = / - s , \s * - - s i l e n t , \s * - - r e p o r t e r \s + s i l e n t \s + ( .+ ) / ;
2926const COMMA_SPACE_SPLIT_RE = / [ , \s ] + / ;
27+ const OPTION_WITH_VALUE_RE =
28+ / ^ \s * (?: - \w , ? \s * ) ? - - ( \w + (?: - \w + ) * ) \s + ( \w + (?: - \w + ) * ) \s + ( .+ ) $ / ;
29+ const OPTION_ALIAS_RE =
30+ / ^ \s * - \w , ? \s * - - \w + (?: , \s * - - ( \w + (?: - \w + ) * ) \s + ( \w + (?: - \w + ) * ) ) ? \s + ( .+ ) $ / ;
31+ const CONTINUATION_LINE_RE = / ^ \s { 20 , } / ;
32+ const SECTION_HEADER_RE = / ^ \s * [ A - Z ] [ ^ : ] * : \s * $ / ;
3033
3134function toLines ( text : string ) : string [ ] {
3235 return stripAnsiEscapes ( text ) . split ( LINE_SPLIT_RE ) ;
@@ -60,29 +63,74 @@ function extractValidValuesFromHelp(
6063 optionName : string
6164) : Array < { value : string ; desc : string } > {
6265 const lines = toLines ( helpText ) ;
66+ const results : Array < { value : string ; desc : string } > = [ ] ;
6367
64- // edge case: reporter often appears as multiple lines
65- if ( optionName === 'reporter' ) {
66- const out : Array < { value : string ; desc : string } > = [ ] ;
67-
68- for ( const line of lines ) {
69- if ( line . includes ( '--reporter' ) && REPORTER_LINE_RE . test ( line ) ) {
70- const match = line . match ( REPORTER_MATCH_RE ) ;
71- if ( match ) {
72- const [ , value , desc ] = match ;
73- out . push ( { value, desc : desc . trim ( ) } ) ;
68+ for ( let i = 0 ; i < lines . length ; i ++ ) {
69+ const line = lines [ i ] ;
70+
71+ // Look for options with values in any section
72+ const optionMatch = line . match ( OPTION_WITH_VALUE_RE ) ;
73+ if ( optionMatch ) {
74+ const [ , option , value , initialDesc ] = optionMatch ;
75+ if ( option === optionName ) {
76+ // capture continuation lines for complete description
77+ let fullDesc = initialDesc . trim ( ) ;
78+ let j = i + 1 ;
79+
80+ // Look ahead for continuation lines (indented lines that don't start new options)
81+ while ( j < lines . length ) {
82+ const nextLine = lines [ j ] ;
83+ const isIndented = CONTINUATION_LINE_RE . test ( nextLine ) ;
84+ const isNewOption =
85+ OPTION_WITH_VALUE_RE . test ( nextLine ) ||
86+ OPTION_ALIAS_RE . test ( nextLine ) ;
87+ const isEmptyOrSection =
88+ ! nextLine . trim ( ) || SECTION_HEADER_RE . test ( nextLine ) ;
89+
90+ if ( isIndented && ! isNewOption && ! isEmptyOrSection ) {
91+ fullDesc += ' ' + nextLine . trim ( ) ;
92+ j ++ ;
93+ } else {
94+ break ;
95+ }
7496 }
75- }
7697
77- const silent = line . match ( SILENT_REPORTER_RE ) ;
78- if ( silent && ! out . some ( ( r ) => r . value === 'silent' ) ) {
79- out . push ( { value : 'silent' , desc : silent [ 1 ] . trim ( ) } ) ;
98+ results . push ( { value, desc : fullDesc } ) ;
8099 }
81100 }
82101
83- if ( out . length ) return out ;
102+ const aliasMatch = line . match ( OPTION_ALIAS_RE ) ;
103+ if ( aliasMatch ) {
104+ const [ , option , value , initialDesc ] = aliasMatch ;
105+ if ( option === optionName && value ) {
106+ // capture continuation lines for alias descriptions too
107+ let fullDesc = initialDesc . trim ( ) ;
108+ let j = i + 1 ;
109+
110+ while ( j < lines . length ) {
111+ const nextLine = lines [ j ] ;
112+ const isIndented = CONTINUATION_LINE_RE . test ( nextLine ) ;
113+ const isNewOption =
114+ OPTION_WITH_VALUE_RE . test ( nextLine ) ||
115+ OPTION_ALIAS_RE . test ( nextLine ) ;
116+ const isEmptyOrSection =
117+ ! nextLine . trim ( ) || SECTION_HEADER_RE . test ( nextLine ) ;
118+
119+ if ( isIndented && ! isNewOption && ! isEmptyOrSection ) {
120+ fullDesc += ' ' + nextLine . trim ( ) ;
121+ j ++ ;
122+ } else {
123+ break ;
124+ }
125+ }
126+
127+ results . push ( { value, desc : fullDesc } ) ;
128+ }
129+ }
84130 }
85131
132+ if ( results . length ) return results ;
133+
86134 for ( let i = 0 ; i < lines . length ; i ++ ) {
87135 const ln = lines [ i ] ;
88136 if ( ln . includes ( `--${ optionName } ` ) || ln . includes ( `${ optionName } :` ) ) {
@@ -259,11 +307,14 @@ function loadPnpmOptionsSync(cmd: LazyCommand, command: string): void {
259307 else cmd . option ( long , desc , short ) ;
260308 }
261309
262- // edge case: reporter sometimes doesn’t match standard row pattern
263- if ( output . includes ( '--reporter' ) && ! cmd . optionsRaw ?. get ?.( 'reporter' ) ) {
264- const handler = pnpmOptionHandlers [ 'reporter' ] ;
265- if ( handler )
266- cmd . option ( 'reporter' , 'Output reporter for pnpm commands' , handler ) ;
310+ // Register options found by general algorithm but not in standard parsing
311+ for ( const [ optionName , handler ] of Object . entries ( pnpmOptionHandlers ) ) {
312+ if ( ! cmd . optionsRaw ?. get ?.( optionName ) ) {
313+ const values = extractValidValuesFromHelp ( output , optionName ) ;
314+ if ( values . length > 0 ) {
315+ cmd . option ( optionName , ' ' , handler ) ;
316+ }
317+ }
267318 }
268319}
269320
0 commit comments