@@ -71,6 +71,10 @@ export async function setupPnpmCompletions(
7171 if ( command === 'run' ) {
7272 cmd . argument ( 'script' , scriptCompletion , true ) ;
7373 }
74+
75+ // TODO: AMIR: MANUAL OPTIONS ?
76+
77+ setupLazyOptionLoading ( cmd , command ) ;
7478 }
7579 } catch ( error ) {
7680 if ( error instanceof Error ) {
@@ -168,3 +172,102 @@ export async function setupYarnCompletions(
168172export async function setupBunCompletions (
169173 completion : PackageManagerCompletion
170174) { }
175+
176+ function setupLazyOptionLoading ( cmd : any , command : string ) {
177+ cmd . _lazyCommand = command ;
178+ cmd . _optionsLoaded = false ;
179+
180+ const originalOptions = cmd . options ;
181+ Object . defineProperty ( cmd , 'options' , {
182+ get ( ) {
183+ if ( ! this . _optionsLoaded ) {
184+ this . _optionsLoaded = true ;
185+ loadDynamicOptionsSync ( this , this . _lazyCommand ) ;
186+ }
187+ return originalOptions ;
188+ } ,
189+ configurable : true ,
190+ } ) ;
191+ }
192+
193+ function loadDynamicOptionsSync ( cmd : any , command : string ) {
194+ try {
195+ const output = execSync ( `pnpm ${ command } --help` , {
196+ encoding : 'utf8' ,
197+ timeout : 3000 ,
198+ } ) ;
199+ const lines = output . split ( '\n' ) ;
200+ let inOptionsSection = false ;
201+ let currentOption = '' ;
202+ let currentDescription = '' ;
203+ let currentShortFlag : string | undefined ;
204+
205+ for ( let i = 0 ; i < lines . length ; i ++ ) {
206+ const line = lines [ i ] ;
207+
208+ if ( line . match ( / ^ O p t i o n s : / ) ) {
209+ inOptionsSection = true ;
210+ continue ;
211+ }
212+
213+ if ( inOptionsSection && line . match ( / ^ [ A - Z ] [ a - z ] .* : / ) ) {
214+ break ;
215+ }
216+
217+ if ( inOptionsSection && line . trim ( ) ) {
218+ const optionMatch = line . match (
219+ / ^ \s * (?: - ( [ A - Z a - z ] ) , \s * ) ? - - ( [ a - z - ] + ) (? ! \s + < | \s + \[ ) \s + ( .* ) /
220+ ) ;
221+ if ( optionMatch ) {
222+ if ( currentOption && currentDescription ) {
223+ const existingOption = cmd . options . get ( currentOption ) ;
224+ if ( ! existingOption ) {
225+ cmd . option (
226+ currentOption ,
227+ currentDescription . trim ( ) ,
228+ currentShortFlag
229+ ) ;
230+ }
231+ }
232+
233+ const [ , shortFlag , optionName , description ] = optionMatch ;
234+
235+ // TODO: AMIR: lets only proccess options that don't have <value> ?
236+ if ( ! line . includes ( '<' ) && ! line . includes ( '[' ) ) {
237+ currentOption = optionName ;
238+ currentShortFlag = shortFlag || undefined ;
239+ currentDescription = description ;
240+
241+ let j = i + 1 ;
242+ while (
243+ j < lines . length &&
244+ lines [ j ] . match ( / ^ \s { 25 , } / ) &&
245+ ! lines [ j ] . match ( / ^ \s * (?: - [ A - Z a - z ] , \s * ) ? - - [ a - z - ] / )
246+ ) {
247+ currentDescription += ' ' + lines [ j ] . trim ( ) ;
248+ j ++ ;
249+ }
250+ i = j - 1 ;
251+ } else {
252+ currentOption = '' ;
253+ currentDescription = '' ;
254+ currentShortFlag = undefined ;
255+ }
256+ }
257+ }
258+ }
259+
260+ if ( currentOption && currentDescription ) {
261+ const existingOption = cmd . options . get ( currentOption ) ;
262+ if ( ! existingOption ) {
263+ cmd . option ( currentOption , currentDescription . trim ( ) , currentShortFlag ) ;
264+ }
265+ }
266+ } catch ( error ) {
267+ if ( error instanceof Error ) {
268+ console . error ( `Failed to load options for ${ command } :` , error . message ) ;
269+ } else {
270+ console . error ( `Failed to load options for ${ command } :` , error ) ;
271+ }
272+ }
273+ }
0 commit comments