2026-10-07 13:27:00 +00:00
package commandkit
import (
2026-10-26 02:55:08 +00:00
"fmt"
2026-10-07 13:27:00 +00:00
"sort"
2026-10-26 02:55:08 +00:00
"strconv"
2026-10-07 13:27:00 +00:00
2026-11-04 03:49:38 +00:00
internalcobra "go.maximumdirect.net/commandkit/internal/cobra"
commandmeta "go.maximumdirect.net/commandkit/internal/commandmeta"
"go.maximumdirect.net/commandkit/internal/commandpath"
2026-10-07 13:27:00 +00:00
)
2026-10-11 01:25:45 +00:00
func ( a * App ) parse ( args [ ] string , options commandmeta . ParseOptions ) commandmeta . Result {
2026-10-07 13:27:00 +00:00
if a == nil {
2026-10-11 01:25:45 +00:00
return commandmeta . Result { Failure : & commandmeta . Failure { Message : "cannot parse commands on a nil app" } }
2026-10-07 13:27:00 +00:00
}
2026-10-26 02:55:08 +00:00
result := internalcobra . Parse ( a . routeSnapshot ( ) . metadata , args , options )
return reduceReportingOccurrences ( result )
}
func reduceReportingOccurrences ( result commandmeta . Result ) commandmeta . Result {
selection := commandmeta . ReportingSelection { }
for index , occurrence := range result . FlagOccurrences {
if ! commandmeta . IsReportingFlag ( occurrence . Name ) {
continue
}
2026-11-07 03:45:12 +00:00
if occurrence . Name == "format" {
switch Format ( occurrence . RawValue ) {
case FormatText , FormatYAML , FormatJSON :
selection . Format = occurrence . RawValue
default :
result . FlagOccurrences = result . FlagOccurrences [ : index + 1 ]
result . Reporting = selection
result . Failure = & commandmeta . Failure { Message : fmt . Sprintf ( "invalid format %q for %s (expected text, yaml, or json)" , occurrence . RawValue , occurrence . Spelling ) , Usage : true }
return result
}
continue
}
2026-10-26 02:55:08 +00:00
enabled , err := strconv . ParseBool ( occurrence . RawValue )
if err != nil {
result . FlagOccurrences = result . FlagOccurrences [ : index + 1 ]
result . Reporting = selection
result . Failure = & commandmeta . Failure {
Message : fmt . Sprintf ( "invalid boolean value %q for %s" , occurrence . RawValue , occurrence . Spelling ) ,
Usage : true ,
}
return result
}
mode := commandmeta . ReportingModeNormal
switch occurrence . Name {
case "quiet" :
mode = commandmeta . ReportingModeQuiet
case "verbose" :
mode = commandmeta . ReportingModeVerbose
case "debug" :
mode = commandmeta . ReportingModeDebug
case "progress" :
selection . Progress = enabled
selection . ProgressSet = true
continue
}
if enabled {
selection . Mode = mode
} else if selection . Mode == mode {
selection . Mode = commandmeta . ReportingModeNormal
}
}
result . Reporting = selection
return result
2026-10-07 13:37:57 +00:00
}
2026-10-11 01:25:45 +00:00
func ( a * App ) routeSnapshot ( ) * routingSnapshot {
2026-10-07 13:37:57 +00:00
if a == nil {
return nil
}
2026-10-11 01:25:45 +00:00
if a . snapshot == nil {
a . snapshot = a . buildRoutingSnapshot ( )
2026-10-09 01:34:24 +00:00
}
2026-10-11 01:25:45 +00:00
return a . snapshot
2026-10-09 01:34:24 +00:00
}
2026-10-11 01:25:45 +00:00
func ( a * App ) buildRoutingSnapshot ( ) * routingSnapshot {
2026-10-26 02:50:54 +00:00
root := & commandmeta . Command { Name : a . identity . Name , CoreFlags : commandmeta . ReportingFlags ( ) }
2026-10-19 17:37:59 +00:00
snapshot := & routingSnapshot {
metadata : root ,
runners : make ( map [ commandmeta . Key ] commandPayload ) ,
aliases : a . aliases ,
canonical : buildCanonicalTree ( a . commands ) ,
flagAliases : a . flagAliases ,
discoveryFlags : a . discoveryFlags ,
}
2026-11-03 03:50:12 +00:00
if node := a . commands [ "completion" ] ; node != nil {
snapshot . completion = node . command . record . completion
}
2026-10-19 19:40:55 +00:00
for _ , rule := range a . routingRules {
if rule . record . kind != commandAliasRule {
continue
}
snapshot . commandAliases = append ( snapshot . commandAliases , commandmeta . CommandAlias {
Source : [ ] string ( rule . record . sourcePath . Clone ( ) ) ,
Target : [ ] string ( snapshot . aliases . Resolve ( rule . record . targetPath ) ) ,
} )
}
sort . Slice ( snapshot . commandAliases , func ( i , j int ) bool {
return commandpath . FromTokens ( snapshot . commandAliases [ i ] . Source ) . Key ( ) < commandpath . FromTokens ( snapshot . commandAliases [ j ] . Source ) . Key ( )
} )
2026-10-07 13:27:00 +00:00
names := make ( [ ] string , 0 , len ( a . commands ) )
2026-10-11 01:22:47 +00:00
for name := range a . commands {
names = append ( names , name )
2026-10-07 13:27:00 +00:00
}
sort . Strings ( names )
2026-10-11 01:25:45 +00:00
var key commandmeta . Key
2026-10-07 13:27:00 +00:00
for _ , name := range names {
2026-11-03 13:13:20 +00:00
root . Children = append ( root . Children , bridgeCommand ( snapshot . canonical [ name ] , snapshot , & key ) )
2026-10-07 13:27:00 +00:00
}
2026-10-11 01:25:45 +00:00
return snapshot
2026-10-07 13:27:00 +00:00
}
2026-11-03 13:13:20 +00:00
func bridgeCommand ( node * canonicalNode , snapshot * routingSnapshot , next * commandmeta . Key ) * commandmeta . Command {
record := node . command . record
2026-10-11 01:25:45 +00:00
* next = * next + 1
declaration := & commandmeta . Command {
Key : * next ,
2026-10-11 01:15:13 +00:00
Name : record . name ,
Summary : record . summary ,
Description : record . description ,
2026-10-26 02:50:54 +00:00
CoreFlags : commandmeta . ReportingFlags ( ) ,
2026-10-07 13:27:00 +00:00
}
2026-11-03 13:13:20 +00:00
node . metadata = declaration
2026-10-11 01:15:13 +00:00
if record . payload != nil {
2026-10-11 01:25:45 +00:00
snapshot . runners [ declaration . Key ] = record . payload
2026-10-11 01:15:13 +00:00
declaration . Runnable = record . payload . hasRun ( )
declaration . Flags = record . payload . bridgeFlags ( )
declaration . Arguments = record . payload . bridgeArguments ( )
2026-10-07 13:27:00 +00:00
}
2026-10-11 01:15:13 +00:00
children := append ( [ ] Command ( nil ) , record . children ... )
sort . Slice ( children , func ( i , j int ) bool { return children [ i ] . record . name < children [ j ] . record . name } )
2026-10-07 13:37:57 +00:00
for _ , child := range children {
2026-10-11 01:15:13 +00:00
if child . record == nil || child . record . absent {
continue
}
2026-11-03 13:13:20 +00:00
declaration . Children = append ( declaration . Children , bridgeCommand ( node . children [ child . record . name ] , snapshot , next ) )
2026-10-07 13:27:00 +00:00
}
return declaration
}