1+ using OpenCli ;
2+
3+ namespace Spectre . Console . Cli ;
4+
5+ internal sealed class OpenCliGeneratorCommand : Command , IBuiltInCommand
6+ {
7+ private readonly IConfiguration _configuration ;
8+ private readonly CommandModel _model ;
9+
10+ public OpenCliGeneratorCommand ( IConfiguration configuration , CommandModel model )
11+ {
12+ _configuration = configuration ;
13+ _model = model ?? throw new ArgumentNullException ( nameof ( model ) ) ;
14+ }
15+
16+ public override int Execute ( CommandContext context )
17+ {
18+ var document = new OpenCliDocument
19+ {
20+ OpenCli = "0.1-draft" ,
21+ Info = new OpenCliInfo
22+ {
23+ Title = ( ( ICommandModel ) _model ) . ApplicationName , Version = _model . ApplicationVersion ?? "1.0" ,
24+ } ,
25+ Commands = CreateCommands ( _model . Commands ) ,
26+ Arguments = CreateArguments ( _model . DefaultCommand ? . GetArguments ( ) ) ,
27+ Options = CreateOptions ( _model . DefaultCommand ? . GetOptions ( ) ) ,
28+ } ;
29+
30+ var writer = _configuration . Settings . Console . GetConsole ( ) ;
31+ writer . WriteLine ( document . Write ( ) ) ;
32+
33+ return 0 ;
34+ }
35+
36+ private List < OpenCliCommand > CreateCommands ( IList < CommandInfo > commands )
37+ {
38+ var result = new List < OpenCliCommand > ( ) ;
39+
40+ foreach ( var command in commands . OrderBy ( o => o . Name , StringComparer . OrdinalIgnoreCase ) )
41+ {
42+ if ( typeof ( IBuiltInCommand ) . IsAssignableFrom ( command . CommandType ) )
43+ {
44+ continue ;
45+ }
46+
47+ var openCliCommand = new OpenCliCommand
48+ {
49+ Name = command . Name ,
50+ Aliases =
51+ [
52+ ..command . Aliases . OrderBy ( str => str )
53+ ] ,
54+ Commands = CreateCommands ( command . Children ) ,
55+ Arguments = CreateArguments ( command . GetArguments ( ) ) ,
56+ Options = CreateOptions ( command . GetOptions ( ) ) ,
57+ Description = command . Description ,
58+ Hidden = command . IsHidden ,
59+ Examples = [ ..command . Examples . Select ( example => string . Join ( " " , example ) ) ] ,
60+ } ;
61+
62+ // Skip branches without commands
63+ if ( command . IsBranch && openCliCommand . Commands . Count == 0 )
64+ {
65+ continue ;
66+ }
67+
68+ result . Add ( openCliCommand ) ;
69+ }
70+
71+ return result ;
72+ }
73+
74+ private List < OpenCliArgument > CreateArguments ( IEnumerable < CommandArgument > ? arguments )
75+ {
76+ var result = new List < OpenCliArgument > ( ) ;
77+
78+ if ( arguments == null )
79+ {
80+ return result ;
81+ }
82+
83+ foreach ( var argument in arguments . OrderBy ( x => x . Position ) )
84+ {
85+ var metadata = default ( List < OpenCliMetadata > ) ;
86+ if ( argument . ParameterType != typeof ( void ) &&
87+ argument . ParameterType != typeof ( bool ) )
88+ {
89+ metadata =
90+ [
91+ new OpenCliMetadata { Name = "ClrType" , Value = argument . ParameterType . ToCliTypeString ( ) , } ,
92+ ] ;
93+ }
94+
95+ result . Add ( new OpenCliArgument
96+ {
97+ Name = argument . Value ,
98+ Required = argument . IsRequired ,
99+ Arity = new OpenCliArity
100+ {
101+ // TODO: Look into this
102+ Minimum = 1 ,
103+ Maximum = 1 ,
104+ } ,
105+ Description = argument . Description ,
106+ Hidden = argument . IsHidden ,
107+ Metadata = metadata ,
108+ AcceptedValues = null ,
109+ Group = null ,
110+ } ) ;
111+ }
112+
113+ return result ;
114+ }
115+
116+ private List < OpenCliOption > CreateOptions ( IEnumerable < CommandOption > ? options )
117+ {
118+ var result = new List < OpenCliOption > ( ) ;
119+
120+ if ( options == null )
121+ {
122+ return result ;
123+ }
124+
125+ foreach ( var option in options . OrderBy ( o => o . GetOptionName ( ) , StringComparer . OrdinalIgnoreCase ) )
126+ {
127+ var arguments = new List < OpenCliArgument > ( ) ;
128+ if ( option . ParameterType != typeof ( void ) &&
129+ option . ParameterType != typeof ( bool ) )
130+ {
131+ arguments . Add ( new OpenCliArgument
132+ {
133+ Name = option . ValueName ?? "VALUE" ,
134+ Required = ! option . ValueIsOptional ,
135+ Arity = new OpenCliArity
136+ {
137+ // TODO: Look into this
138+ Minimum = option . ValueIsOptional
139+ ? 0
140+ : 1 ,
141+ Maximum = 1 ,
142+ } ,
143+ AcceptedValues = null ,
144+ Group = null ,
145+ Hidden = null ,
146+ Metadata =
147+ [
148+ new OpenCliMetadata
149+ {
150+ Name = "ClrType" ,
151+ Value = option . ParameterType . ToCliTypeString ( ) ,
152+ } ,
153+ ] ,
154+ } ) ;
155+ }
156+
157+ var optionMetadata = default ( List < OpenCliMetadata > ) ;
158+ if ( arguments . Count == 0 && option . ParameterType != typeof ( void ) &&
159+ option . ParameterType != typeof ( bool ) )
160+ {
161+ optionMetadata =
162+ [
163+ new OpenCliMetadata { Name = "ClrType" , Value = option . ParameterType . ToCliTypeString ( ) , } ,
164+ ] ;
165+ }
166+
167+ var ( optionName , optionAliases ) = GetOptionNames ( option ) ;
168+ result . Add ( new OpenCliOption
169+ {
170+ Name = optionName ,
171+ Required = option . IsRequired ,
172+ Aliases = [ ..optionAliases . OrderBy ( str => str ) ] ,
173+ Arguments = arguments ,
174+ Description = option . Description ,
175+ Group = null ,
176+ Hidden = option . IsHidden ,
177+ Recursive = option . IsShadowed , // TODO: Is this correct?
178+ Metadata = optionMetadata ,
179+ } ) ;
180+ }
181+
182+ return result ;
183+ }
184+
185+ private static ( string Name , HashSet < string > Aliases ) GetOptionNames ( CommandOption option )
186+ {
187+ var name = GetOptionName ( option ) ;
188+ var aliases = new HashSet < string > ( ) ;
189+
190+ if ( option . LongNames . Count > 0 )
191+ {
192+ foreach ( var alias in option . LongNames . Skip ( 1 ) )
193+ {
194+ aliases . Add ( "--" + alias ) ;
195+ }
196+
197+ foreach ( var alias in option . ShortNames )
198+ {
199+ aliases . Add ( "-" + alias ) ;
200+ }
201+ }
202+ else
203+ {
204+ foreach ( var alias in option . LongNames )
205+ {
206+ aliases . Add ( "--" + alias ) ;
207+ }
208+
209+ foreach ( var alias in option . ShortNames . Skip ( 1 ) )
210+ {
211+ aliases . Add ( "-" + alias ) ;
212+ }
213+ }
214+
215+ return ( name , aliases ) ;
216+ }
217+
218+ private static string GetOptionName ( CommandOption option )
219+ {
220+ return option . LongNames . Count > 0
221+ ? "--" + option . LongNames [ 0 ]
222+ : "-" + option . ShortNames [ 0 ] ;
223+ }
224+ }
0 commit comments