Skip to main content

mrapids/cli/
mod.rs

1use clap::{Parser, Subcommand};
2use std::path::PathBuf;
3
4#[derive(Parser)]
5#[command(name = "mrapids")]
6#[command(about = "Your OpenAPI, but executable", long_about = None)]
7#[command(version)]
8#[command(before_help = crate::core::banner::get_help_header())]
9#[command(after_help = get_help_footer())]
10#[command(override_help = get_grouped_help())]
11pub struct Args {
12    #[command(subcommand)]
13    pub command: Commands,
14
15    /// Global: Environment name (dev, staging, prod)
16    #[arg(long, global = true, value_name = "ENV")]
17    pub env: Option<String>,
18
19    /// Global: Output format (json, yaml, table, pretty)
20    #[arg(long = "output-format", global = true, value_name = "FORMAT")]
21    pub output_format: Option<String>,
22
23    /// Global: Suppress all output except errors
24    #[arg(long, short = 'q', global = true)]
25    pub quiet: bool,
26
27    /// Global: Enable verbose output
28    #[arg(long, short = 'v', global = true)]
29    pub verbose: bool,
30
31    /// Global: Enable trace output (includes HTTP requests/responses)
32    #[arg(long, global = true)]
33    pub trace: bool,
34
35    /// Global: Disable colored output
36    #[arg(long, global = true)]
37    pub no_color: bool,
38}
39
40#[derive(Subcommand)]
41pub enum Commands {
42    // === GETTING STARTED ===
43    /// Initialize a new MicroRapid project from OpenAPI/GraphQL specs
44    #[command(display_order = 1)]
45    Init(InitCommand),
46
47    /// Discover what operations are available in your API
48    #[command(alias = "search", alias = "discover", display_order = 2)]
49    Explore(ExploreCommand),
50
51    /// Show detailed information about specific operations
52    #[command(display_order = 3)]
53    Show(ShowCommand),
54
55    /// Ensure your OpenAPI specification is correct
56    #[command(display_order = 4)]
57    Validate(ValidateCommand),
58
59    // === EXECUTION & TESTING ===
60    /// Execute API operations directly from specifications
61    #[command(display_order = 5)]
62    Run(RunCommand),
63
64    /// Run automated tests against your API
65    #[command(display_order = 6)]
66    Test(TestCommand),
67
68    /// List available operations, requests, or resources
69    #[command(display_order = 7)]
70    List(ListCommand),
71
72    // === CODE GENERATION ===
73    /// Generate SDKs, examples, test fixtures, and code
74    #[command(alias = "generate", display_order = 8)]
75    Gen(GenCommand),
76
77    /// Resolve all $ref references in your specification
78    #[command(display_order = 9)]
79    Flatten(FlattenCommand),
80
81    // === AUTOMATION & WORKFLOWS ===
82    /// Manage and run complex API request collections
83    #[command(display_order = 10)]
84    Collection(CollectionCommand),
85
86    /// Set up complete test environment automatically
87    #[command(alias = "tests-init", display_order = 11)]
88    SetupTests(SetupTestsCommand),
89
90    // === CONFIGURATION ===
91    /// Manage OAuth and API authentication
92    #[command(display_order = 12)]
93    Auth(AuthCommand),
94
95    /// Initialize environment configurations
96    #[command(alias = "config", display_order = 13)]
97    InitConfig(InitConfigCommand),
98
99    // === UTILITIES ===
100    /// Compare specifications for breaking changes
101    #[command(display_order = 14)]
102    Diff(DiffCommand),
103
104    /// Clean up test artifacts and temporary files
105    #[command(display_order = 15)]
106    Cleanup(CleanupCommand),
107}
108
109#[derive(Parser)]
110pub struct ValidateCommand {
111    /// Path to the OpenAPI/Swagger specification file
112    pub spec: PathBuf,
113
114    /// Strict mode - treat warnings as errors
115    #[arg(long)]
116    pub strict: bool,
117
118    /// Enable linting for best practices and style issues
119    #[arg(long)]
120    pub lint: bool,
121
122    /// Custom linting rules file
123    #[arg(long, requires = "lint")]
124    pub rules: Option<PathBuf>,
125
126    /// Output format (text or json)
127    #[arg(short, long, value_enum, default_value = "text")]
128    pub format: ValidateFormat,
129}
130
131#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
132pub enum ValidateFormat {
133    /// Human-readable text format
134    Text,
135    /// JSON format for tooling
136    Json,
137}
138
139#[derive(Parser)]
140pub struct InitCommand {
141    /// Project name (defaults to current directory name)
142    #[arg(default_value = "my-api-project")]
143    pub name: String,
144
145    /// Project template (minimal, rest, graphql)
146    #[arg(short, long, default_value = "rest")]
147    pub template: String,
148
149    /// Initialize from a URL (downloads OpenAPI/GraphQL schema)
150    #[arg(long, value_name = "URL", conflicts_with = "from_file")]
151    pub from_url: Option<String>,
152
153    /// Initialize from a local file (OpenAPI/GraphQL schema)
154    #[arg(long, value_name = "FILE", conflicts_with = "from_url")]
155    pub from_file: Option<String>,
156
157    /// Force overwrite if directory exists
158    #[arg(short, long)]
159    pub force: bool,
160
161    /// Allow insecure HTTP connections when downloading specs (not recommended)
162    #[arg(long)]
163    pub allow_insecure: bool,
164}
165
166#[derive(Parser)]
167#[command(
168    args_override_self = true,
169    after_help = "EXAMPLES:
170    # Execute an API operation
171    mrapids run users/get-by-username --param username=octocat
172    
173    # POST request with data
174    mrapids run repos/create --data '{\"name\": \"my-repo\"}'
175    
176    # Use authentication profile
177    mrapids run users/get-authenticated --profile github
178    
179    # Search with special characters (NO encoding needed - mrapids handles it)
180    mrapids run search/repos --param q=\"language:javascript stars:>1000\" --param sort=stars
181    
182    # Save response to file
183    mrapids run users/list --save users.json
184    
185    # Show as curl command
186    mrapids run repos/get --param owner=octocat --param repo=hello-world --as-curl
187
188IMPORTANT TIPS:
189    • Parameters are automatically URL-encoded - pass them as plain text
190    • Use quotes for values with spaces: --param q=\"user:octocat type:pr\"
191    • Data can be read from file: --data @request.json or --file request.json"
192)]
193pub struct RunCommand {
194    /// Operation ID (e.g., users/get, repos/create) or path to request config file
195    pub operation: String,
196
197    // === DATA INPUT ===
198    /// Request body as JSON string or @file.json
199    #[arg(short, long, conflicts_with = "file", help_heading = "Data Input")]
200    pub data: Option<String>,
201
202    /// Read request body from file
203    #[arg(short, long, conflicts_with = "data", help_heading = "Data Input")]
204    pub file: Option<PathBuf>,
205
206    // === COMMON PARAMETERS ===
207    /// Resource ID (auto-mapped to path/query parameters)
208    #[arg(long, help_heading = "Common Parameters")]
209    pub id: Option<String>,
210
211    /// Resource name
212    #[arg(long, help_heading = "Common Parameters")]
213    pub name: Option<String>,
214
215    /// Filter by status
216    #[arg(long, help_heading = "Common Parameters")]
217    pub status: Option<String>,
218
219    /// Limit number of results
220    #[arg(long, help_heading = "Common Parameters")]
221    pub limit: Option<u32>,
222
223    /// Offset for pagination
224    #[arg(long, help_heading = "Common Parameters")]
225    pub offset: Option<u32>,
226
227    /// Sort order
228    #[arg(long, help_heading = "Common Parameters")]
229    pub sort: Option<String>,
230
231    // === REQUEST PARAMETERS ===
232    /// Set any parameter: --param key=value (can be used multiple times)
233    #[arg(
234        long = "param",
235        value_name = "KEY=VALUE",
236        help_heading = "Request Parameters"
237    )]
238    pub params: Vec<String>,
239
240    /// Force query parameters: --query key=value (can be used multiple times)
241    #[arg(
242        long = "query",
243        value_name = "KEY=VALUE",
244        help_heading = "Request Parameters"
245    )]
246    pub query_params: Vec<String>,
247
248    /// Add HTTP headers: --header "Key: Value" (can be used multiple times)
249    #[arg(
250        short = 'H',
251        long = "header",
252        value_name = "KEY: VALUE",
253        help_heading = "Request Parameters"
254    )]
255    pub headers: Vec<String>,
256
257    // === AUTHENTICATION ===
258    /// Bearer token or Basic auth (e.g., "Bearer token123" or "Basic base64")
259    #[arg(long, conflicts_with = "auth_profile", help_heading = "Authentication")]
260    pub auth: Option<String>,
261
262    /// API key for X-API-Key header
263    #[arg(long, conflicts_with = "auth_profile", help_heading = "Authentication")]
264    pub api_key: Option<String>,
265
266    /// Use saved OAuth/auth profile
267    #[arg(long = "profile", value_name = "PROFILE", conflicts_with_all = &["auth", "api_key"], help_heading = "Authentication")]
268    pub auth_profile: Option<String>,
269
270    /// Environment to use (dev, staging, prod)
271    #[arg(short, long, default_value = "development")]
272    pub env: String,
273
274    /// Base URL to override default
275    #[arg(short, long)]
276    pub url: Option<String>,
277
278    /// Output format (json, yaml, table, pretty)
279    #[arg(short, long, default_value = "pretty")]
280    pub output: String,
281
282    /// Save response to file
283    #[arg(long)]
284    pub save: Option<PathBuf>,
285
286    /// Use template file
287    #[arg(long)]
288    pub template: Option<String>,
289
290    /// Set template variables: --set key=value (can be used multiple times)
291    #[arg(long = "set", value_name = "KEY=VALUE")]
292    pub template_vars: Vec<String>,
293
294    // === OUTPUT & DEBUGGING ===
295    /// Use only required fields in requests
296    #[arg(long, help_heading = "Testing & Debugging")]
297    pub required_only: bool,
298
299    /// Show detailed request/response info
300    #[arg(short, long, help_heading = "Testing & Debugging")]
301    pub verbose: bool,
302
303    /// Preview request without sending
304    #[arg(long, help_heading = "Testing & Debugging")]
305    pub dry_run: bool,
306
307    /// Show equivalent curl command
308    #[arg(long, help_heading = "Testing & Debugging")]
309    pub as_curl: bool,
310
311    /// Edit generated data before sending
312    #[arg(long, help_heading = "Data Input")]
313    pub edit: bool,
314
315    /// Read request body from stdin
316    #[arg(long, help_heading = "Data Input")]
317    pub stdin: bool,
318
319    // === REQUEST OPTIONS ===
320    /// Number of retries for failed requests
321    #[arg(long, default_value = "0", help_heading = "Request Options")]
322    pub retry: u32,
323
324    /// Request timeout in seconds
325    #[arg(long, default_value = "30", help_heading = "Request Options")]
326    pub timeout: u32,
327
328    /// Allow insecure HTTPS connections (skip certificate validation)
329    #[arg(long, help_heading = "Security")]
330    pub allow_insecure: bool,
331
332    /// Suppress warnings about sensitive data in requests
333    #[arg(long, help_heading = "Security")]
334    pub no_warnings: bool,
335}
336
337#[derive(Parser)]
338pub struct TestCommand {
339    /// Path to the OpenAPI specification file
340    pub spec: PathBuf,
341
342    /// Test all operations
343    #[arg(long)]
344    pub all: bool,
345
346    /// Specific operation to test
347    #[arg(short, long)]
348    pub operation: Option<String>,
349
350    /// Automatically clean up test artifacts after completion
351    #[arg(long, default_value = "true")]
352    pub cleanup: bool,
353
354    /// Keep test artifacts even after cleanup (for debugging)
355    #[arg(long)]
356    pub keep_artifacts: bool,
357
358    /// Allow insecure HTTP connections (not recommended)
359    #[arg(long)]
360    pub allow_insecure: bool,
361
362    /// Suppress security warnings about request content
363    #[arg(long)]
364    pub no_warnings: bool,
365}
366
367// Still used internally by gen snippets
368#[derive(Parser)]
369pub struct AnalyzeCommand {
370    /// Path to the OpenAPI/Swagger specification file
371    pub spec: Option<PathBuf>,
372
373    /// Analyze specific operation only
374    #[arg(short, long)]
375    pub operation: Option<String>,
376
377    /// Output directory for generated examples (defaults to current directory)
378    #[arg(short = 'd', long, default_value = ".")]
379    pub output: PathBuf,
380
381    /// Generate examples for all operations
382    #[arg(long)]
383    pub all: bool,
384
385    /// Skip generating data files for request bodies
386    #[arg(long)]
387    pub skip_data: bool,
388
389    /// Skip OpenAPI validation
390    #[arg(long)]
391    pub skip_validate: bool,
392
393    /// Overwrite existing files
394    #[arg(short, long)]
395    pub force: bool,
396
397    /// Clean up old backup directories after analysis
398    #[arg(long, default_value = "true")]
399    pub cleanup_backups: bool,
400}
401
402#[derive(Parser)]
403pub struct ListCommand {
404    /// What to list: operations, requests, or all
405    #[arg(value_enum, default_value = "operations")]
406    pub resource: ListResource,
407
408    /// Path to OpenAPI specification file (optional)
409    pub spec: Option<PathBuf>,
410
411    /// Filter results by text
412    #[arg(short, long)]
413    pub filter: Option<String>,
414
415    /// Filter by HTTP method
416    #[arg(short, long)]
417    pub method: Option<String>,
418
419    /// Filter by tag (for operations)
420    #[arg(short, long)]
421    pub tag: Option<String>,
422
423    /// Output format
424    #[arg(long, value_enum, default_value = "table")]
425    pub format: ListFormat,
426}
427
428#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
429pub enum ListResource {
430    /// List operations from API spec
431    Operations,
432    /// List saved request configurations
433    Requests,
434    /// List all resources
435    All,
436}
437
438#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
439pub enum ListFormat {
440    /// Table format with borders
441    Table,
442    /// Simple list format
443    Simple,
444    /// JSON output
445    Json,
446    /// YAML output
447    Yaml,
448}
449
450#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
451pub enum GenerateTarget {
452    /// TypeScript/JavaScript with Fetch API
453    Typescript,
454    /// Python with Requests
455    Python,
456    /// Go with net/http
457    Go,
458    /// Rust with reqwest
459    Rust,
460    /// Java with OkHttp
461    Java,
462    /// C# with HttpClient
463    Csharp,
464    /// Ruby with Net::HTTP
465    Ruby,
466    /// PHP with Guzzle
467    Php,
468    /// Swift with URLSession
469    Swift,
470    /// Kotlin with Ktor
471    Kotlin,
472    /// cURL commands
473    Curl,
474    /// Postman collection
475    Postman,
476}
477
478#[derive(Parser)]
479pub struct SetupTestsCommand {
480    /// Path to the OpenAPI/Swagger specification file
481    pub spec: PathBuf,
482
483    /// Output format for test setup
484    #[arg(short, long, value_enum, default_value = "npm")]
485    pub format: TestSetupFormat,
486
487    /// Output directory or file
488    #[arg(short, long, default_value = ".")]
489    pub output: PathBuf,
490
491    /// Overwrite existing files
492    #[arg(long)]
493    pub force: bool,
494
495    /// Show what would be generated without creating files
496    #[arg(long)]
497    pub dry_run: bool,
498
499    /// Include example usage in generated files
500    #[arg(long)]
501    pub with_examples: bool,
502
503    /// Generate .env.example file
504    #[arg(long)]
505    pub with_env: bool,
506}
507
508#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
509pub enum TestSetupFormat {
510    /// NPM package.json with scripts (cross-platform)
511    Npm,
512    /// Makefile for Unix/Mac
513    Make,
514    /// Shell script for automation
515    Shell,
516    /// Docker Compose for containers
517    Compose,
518    /// Direct cURL commands (no mrapids needed)
519    Curl,
520    /// Generate all formats
521    All,
522}
523
524#[derive(Parser)]
525pub struct CleanupCommand {
526    /// Clean all test artifacts in current directory
527    #[arg(long, default_value = "true")]
528    pub test_artifacts: bool,
529
530    /// Clean empty directories
531    #[arg(long, default_value = "true")]
532    pub empty_dirs: bool,
533
534    /// Clean backup directories (.backup, .old, etc)
535    #[arg(long, default_value = "true")]
536    pub backups: bool,
537
538    /// Preserve directories containing spec files
539    #[arg(long, default_value = "true")]
540    pub preserve_specs: bool,
541
542    /// Target directory to clean (defaults to current directory)
543    #[arg(short, long, default_value = ".")]
544    pub path: PathBuf,
545
546    /// Dry run - show what would be deleted without actually deleting
547    #[arg(long)]
548    pub dry_run: bool,
549}
550
551#[derive(Parser)]
552pub struct ShowCommand {
553    /// Operation to show details for (e.g., create-customer, list-users)
554    pub operation: String,
555
556    /// Path to the API specification file
557    pub spec: Option<PathBuf>,
558
559    /// Show examples for the operation
560    #[arg(long)]
561    pub examples: bool,
562
563    /// Output format
564    #[arg(short, long, value_enum, default_value = "pretty")]
565    pub format: ShowFormat,
566}
567
568#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
569pub enum ShowFormat {
570    /// Human-readable format with colors
571    Pretty,
572    /// JSON output
573    Json,
574    /// YAML output
575    Yaml,
576}
577
578#[derive(Parser)]
579pub struct InitConfigCommand {
580    /// Environment name (e.g., development, staging, production)
581    #[arg(short, long, default_value = "development")]
582    pub env: String,
583
584    /// API to configure (e.g., stripe, github, openai)
585    #[arg(short, long)]
586    pub api: Option<String>,
587
588    /// Output path for the config file
589    #[arg(short, long)]
590    pub output: Option<PathBuf>,
591
592    /// Force overwrite if config already exists
593    #[arg(short, long)]
594    pub force: bool,
595}
596
597#[derive(Parser)]
598pub struct ExploreCommand {
599    /// Keyword to search for in operations, paths, and descriptions
600    pub keyword: String,
601
602    /// Path to the API specification file (defaults to specs/api.yaml)
603    #[arg(short, long)]
604    pub spec: Option<PathBuf>,
605
606    /// Maximum number of results to show per category
607    #[arg(short, long, default_value = "5")]
608    pub limit: usize,
609
610    /// Show detailed results including descriptions
611    #[arg(long)]
612    pub detailed: bool,
613
614    /// Output format
615    #[arg(short, long, value_enum, default_value = "pretty")]
616    pub format: ExploreFormat,
617}
618
619#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
620pub enum ExploreFormat {
621    /// Human-readable format with colors and grouping
622    Pretty,
623    /// Simple list format
624    Simple,
625    /// JSON output for machine processing
626    Json,
627}
628
629#[derive(Parser)]
630pub struct AuthCommand {
631    #[command(subcommand)]
632    pub command: AuthCommands,
633}
634
635#[derive(Subcommand)]
636pub enum AuthCommands {
637    /// Login to an OAuth provider
638    Login {
639        /// Provider name (github, google, microsoft, etc.) or 'custom' for custom provider
640        provider: String,
641
642        /// Client ID (required for custom providers)
643        #[arg(long)]
644        client_id: Option<String>,
645
646        /// Client Secret (for custom providers)
647        #[arg(long)]
648        client_secret: Option<String>,
649
650        /// Authorization URL (required for custom providers)
651        #[arg(long)]
652        auth_url: Option<String>,
653
654        /// Token URL (required for custom providers)
655        #[arg(long)]
656        token_url: Option<String>,
657
658        /// OAuth scopes to request (space-separated)
659        #[arg(long, value_delimiter = ' ')]
660        scopes: Vec<String>,
661
662        /// Profile name (defaults to provider name)
663        #[arg(long)]
664        profile: Option<String>,
665
666        /// Show provider-specific setup instructions
667        #[arg(long)]
668        setup_help: bool,
669    },
670
671    /// List stored auth profiles
672    List {
673        /// Show detailed information
674        #[arg(long)]
675        detailed: bool,
676    },
677
678    /// Show auth profile details
679    Show {
680        /// Profile name to show
681        profile: String,
682
683        /// Show decrypted tokens (security warning)
684        #[arg(long)]
685        show_tokens: bool,
686    },
687
688    /// Refresh tokens for a profile
689    Refresh {
690        /// Profile name to refresh
691        profile: String,
692    },
693
694    /// Remove auth profile
695    Logout {
696        /// Profile name to remove
697        profile: String,
698
699        /// Skip confirmation prompt
700        #[arg(long)]
701        force: bool,
702    },
703
704    /// Test authentication by making a simple API call
705    Test {
706        /// Profile name to test
707        profile: String,
708    },
709
710    /// Show setup instructions for a provider
711    Setup {
712        /// Provider name (github, google, microsoft, etc.)
713        provider: String,
714    },
715}
716
717#[derive(Parser)]
718pub struct FlattenCommand {
719    /// Path to the OpenAPI/Swagger specification file
720    pub spec: PathBuf,
721
722    /// Output file path (defaults to stdout if not specified)
723    #[arg(short, long)]
724    pub output: Option<PathBuf>,
725
726    /// Output format (json or yaml)
727    #[arg(short, long, value_enum, default_value = "yaml")]
728    pub format: FlattenFormat,
729
730    /// Include schemas that are not referenced
731    #[arg(long)]
732    pub include_unused: bool,
733
734    /// Resolve external references (http:// or file paths)
735    #[arg(long)]
736    pub resolve_external: bool,
737
738    /// Allow insecure HTTP connections when resolving external references (not recommended)
739    #[arg(long)]
740    pub allow_insecure: bool,
741}
742
743#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
744pub enum FlattenFormat {
745    /// YAML format
746    Yaml,
747    /// JSON format  
748    Json,
749}
750
751#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
752pub enum SdkLanguage {
753    /// TypeScript (fetch-based)
754    Typescript,
755    /// Python (httpx-based)
756    Python,
757    /// Go (net/http-based)
758    Go,
759    /// Rust (reqwest-based)
760    Rust,
761}
762
763#[derive(Parser)]
764pub struct DiffCommand {
765    /// Path to the old OpenAPI/Swagger specification file
766    pub old_spec: PathBuf,
767
768    /// Path to the new OpenAPI/Swagger specification file  
769    pub new_spec: PathBuf,
770
771    /// Only show breaking changes
772    #[arg(long, alias = "breaking")]
773    pub breaking_only: bool,
774
775    /// Output format (text, json, markdown)
776    #[arg(short, long, value_enum, default_value = "text")]
777    pub format: DiffFormat,
778
779    /// Exit with non-zero code if breaking changes found
780    #[arg(long)]
781    pub fail_on_breaking: bool,
782}
783
784#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
785pub enum DiffFormat {
786    /// Human-readable text format
787    Text,
788    /// JSON format for tooling
789    Json,
790    /// Markdown format for PRs
791    Markdown,
792}
793
794#[derive(Parser)]
795pub struct GenCommand {
796    #[command(subcommand)]
797    pub target: GenTarget,
798}
799
800#[derive(Subcommand)]
801pub enum GenTarget {
802    /// Generate example requests and responses (replaces 'analyze')
803    Snippets(GenSnippetsCommand),
804
805    /// Generate SDK client library (replaces 'sdk')
806    Sdk(GenSdkCommand),
807
808    /// Generate server stubs (replaces 'generate')
809    Stubs(GenStubsCommand),
810
811    /// Generate test fixtures and sample data
812    Fixtures(GenFixturesCommand),
813}
814
815#[derive(Parser)]
816pub struct GenSnippetsCommand {
817    /// Path to the OpenAPI specification
818    pub spec: Option<PathBuf>,
819
820    /// Output directory for examples
821    #[arg(short, long, default_value = "./examples")]
822    pub output: PathBuf,
823
824    /// Operation ID to generate examples for (all if not specified)
825    #[arg(long)]
826    pub operation: Option<String>,
827
828    /// Example format
829    #[arg(long, value_enum, default_value = "json")]
830    pub format: SnippetFormat,
831
832    /// Include curl examples
833    #[arg(long)]
834    pub curl: bool,
835
836    /// Include HTTPie examples
837    #[arg(long)]
838    pub httpie: bool,
839}
840
841#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
842pub enum SnippetFormat {
843    Json,
844    Yaml,
845    Curl,
846    Httpie,
847    All,
848}
849
850#[derive(Parser)]
851pub struct GenSdkCommand {
852    /// Path to the OpenAPI specification
853    pub spec: Option<PathBuf>,
854
855    /// Target language
856    #[arg(short, long, value_enum)]
857    pub language: SdkLanguage,
858
859    /// Output directory
860    #[arg(short, long)]
861    pub output: Option<PathBuf>,
862
863    /// Package name
864    #[arg(long)]
865    pub package: Option<String>,
866
867    /// Include documentation
868    #[arg(long, default_value = "true")]
869    pub docs: bool,
870
871    /// Include examples
872    #[arg(long, default_value = "true")]
873    pub examples: bool,
874}
875
876#[derive(Parser)]
877pub struct GenStubsCommand {
878    /// Path to the OpenAPI specification
879    pub spec: Option<PathBuf>,
880
881    /// Target framework
882    #[arg(short, long)]
883    pub framework: String,
884
885    /// Output directory
886    #[arg(short, long)]
887    pub output: Option<PathBuf>,
888
889    /// Include tests
890    #[arg(long)]
891    pub with_tests: bool,
892
893    /// Include validation
894    #[arg(long)]
895    pub with_validation: bool,
896}
897
898#[derive(Parser)]
899pub struct GenFixturesCommand {
900    /// Path to the OpenAPI specification
901    pub spec: Option<PathBuf>,
902
903    /// Output directory
904    #[arg(short, long, default_value = "./fixtures")]
905    pub output: PathBuf,
906
907    /// Number of samples per schema
908    #[arg(long, default_value = "10")]
909    pub count: u32,
910
911    /// Specific schemas to generate (all if not specified)
912    #[arg(long)]
913    pub schema: Vec<String>,
914
915    /// Random seed for deterministic output
916    #[arg(long)]
917    pub seed: Option<u64>,
918
919    /// Output format
920    #[arg(long, value_enum, default_value = "json")]
921    pub format: FixtureFormat,
922}
923
924#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
925pub enum FixtureFormat {
926    Json,
927    Yaml,
928    Csv,
929}
930
931#[derive(Parser)]
932pub struct CollectionCommand {
933    #[command(subcommand)]
934    pub command: CollectionSubcommand,
935}
936
937#[derive(Subcommand)]
938pub enum CollectionSubcommand {
939    /// List available collections
940    List {
941        /// Directory containing collections
942        #[arg(long, default_value = ".mrapids/collections")]
943        dir: PathBuf,
944    },
945
946    /// Show details of a collection
947    Show {
948        /// Collection name
949        name: String,
950
951        /// Directory containing collections
952        #[arg(long, default_value = ".mrapids/collections")]
953        dir: PathBuf,
954    },
955
956    /// Validate collection syntax and operations
957    Validate {
958        /// Collection name
959        name: String,
960
961        /// Directory containing collections
962        #[arg(long, default_value = ".mrapids/collections")]
963        dir: PathBuf,
964
965        /// Path to API specification
966        #[arg(long)]
967        spec: Option<PathBuf>,
968    },
969
970    /// Run a collection
971    Run {
972        /// Collection name
973        name: String,
974
975        /// Directory containing collections
976        #[arg(long, default_value = ".mrapids/collections")]
977        dir: PathBuf,
978
979        /// Output format (json, yaml, pretty)
980        #[arg(long, default_value = "pretty")]
981        output: String,
982
983        /// Save all responses to directory
984        #[arg(long)]
985        save_all: Option<PathBuf>,
986
987        /// Save execution summary
988        #[arg(long)]
989        save_summary: Option<PathBuf>,
990
991        /// Override variables (key=value)
992        #[arg(long = "var", value_parser = parse_key_val::<String, String>)]
993        variables: Vec<(String, String)>,
994
995        /// Authentication profile to use
996        #[arg(long = "profile", value_name = "PROFILE")]
997        auth_profile: Option<String>,
998
999        /// Continue execution on errors
1000        #[arg(long)]
1001        continue_on_error: bool,
1002
1003        /// Run specific request(s)
1004        #[arg(long = "request")]
1005        requests: Vec<String>,
1006
1007        /// Skip specific request(s)
1008        #[arg(long = "skip")]
1009        skip_requests: Vec<String>,
1010
1011        /// Use environment variables
1012        #[arg(long)]
1013        use_env: bool,
1014
1015        /// Path to .env file
1016        #[arg(long)]
1017        env_file: Option<PathBuf>,
1018
1019        /// Path to API specification
1020        #[arg(long)]
1021        spec: Option<PathBuf>,
1022
1023        /// Environment name
1024        #[arg(long)]
1025        env: Option<String>,
1026    },
1027
1028    /// Run collection as tests
1029    Test {
1030        /// Collection name
1031        name: String,
1032
1033        /// Directory containing collections
1034        #[arg(long, default_value = ".mrapids/collections")]
1035        dir: PathBuf,
1036
1037        /// Path to API specification
1038        #[arg(long)]
1039        spec: Option<PathBuf>,
1040
1041        /// Authentication profile to use
1042        #[arg(long = "profile", value_name = "PROFILE")]
1043        auth_profile: Option<String>,
1044
1045        /// Output format (pretty, json, junit)
1046        #[arg(long, default_value = "pretty")]
1047        output: String,
1048
1049        /// Continue on test failures
1050        #[arg(long)]
1051        continue_on_error: bool,
1052    },
1053}
1054
1055/// Parse key=value pairs
1056fn parse_key_val<T, U>(
1057    s: &str,
1058) -> Result<(T, U), Box<dyn std::error::Error + Send + Sync + 'static>>
1059where
1060    T: std::str::FromStr,
1061    T::Err: std::error::Error + Send + Sync + 'static,
1062    U: std::str::FromStr,
1063    U::Err: std::error::Error + Send + Sync + 'static,
1064{
1065    let pos = s
1066        .find('=')
1067        .ok_or_else(|| format!("invalid KEY=value: no `=` found in `{}`", s))?;
1068    Ok((s[..pos].parse()?, s[pos + 1..].parse()?))
1069}
1070
1071/// Get the grouped help display with section headers
1072fn get_grouped_help() -> &'static str {
1073    r#"      ╭──────────────────────────────────────────╮
1074      │   ○ ○     M I C R O   R A P I D     ○ ○  │
1075      │    ╲ ╱                               ╲ ╱   │
1076      │     ═       🤖 agent automation 🤖    ═    │
1077      │    ╱ ╲        your api, automated    ╱ ╲   │
1078      │   ○ ○                               ○ ○  │
1079      ╰──────────────────────────────────────────╯
1080      
1081         >> mrapids.exe --mode agent
1082         >> status: [READY] ████████████ 100%
1083
1084Your OpenAPI, but executable
1085
1086The blazing fast API automation toolkit
1087
1088Usage: mrapids [OPTIONS] <COMMAND>
1089
1090GETTING STARTED
1091  init          Initialize a new MicroRapid project
1092  explore       Discover what operations are available in your API
1093  show          Show detailed information about specific operations
1094  validate      Ensure your OpenAPI specification is correct
1095
1096EXECUTION & TESTING  
1097  run           Execute API operations directly
1098  test          Run automated tests against your API
1099  list          List available operations, requests, or resources
1100
1101CODE GENERATION
1102  gen           Generate SDKs, examples, test fixtures, and code
1103  flatten       Resolve all $ref references in your specification
1104
1105AUTOMATION & WORKFLOWS
1106  collection    Manage and run complex API request collections
1107  setup-tests   Set up complete test environment automatically
1108
1109CONFIGURATION
1110  auth          Manage OAuth and API authentication
1111  init-config   Initialize environment configurations
1112  
1113UTILITIES
1114  diff          Compare specifications for breaking changes
1115  cleanup       Clean up test artifacts and temporary files
1116  help          Print this message or the help of the given subcommand(s)
1117
1118Options:
1119      --env <ENV>               Environment name (dev, staging, prod)
1120      --output-format <FORMAT>  Output format (json, yaml, table, pretty)
1121  -q, --quiet                   Suppress all output except errors
1122  -v, --verbose                 Enable verbose output
1123      --trace                   Enable trace output (includes HTTP requests/responses)
1124      --no-color                Disable colored output
1125  -h, --help                    Print help
1126  -V, --version                 Print version
1127
1128EXAMPLES:
1129    # Start with a new project
1130    mrapids init my-api --from-url https://api.example.com/openapi.json
1131    
1132    # Explore available operations
1133    mrapids explore user
1134    
1135    # Execute an operation
1136    mrapids run GetUser --id 123
1137    
1138    # Generate an SDK
1139    mrapids gen sdk --language typescript --output ./sdk
1140    
1141    # Run a test collection
1142    mrapids collection run smoke-tests
1143
1144For detailed help on any command:
1145    mrapids <command> --help
1146
1147For more information, visit: https://microrapid.io/"#
1148}
1149
1150/// Get the help footer with examples and additional information
1151fn get_help_footer() -> &'static str {
1152    r#"
1153EXAMPLES:
1154    # Start with a new project
1155    mrapids init my-api --from-url https://api.example.com/openapi.json
1156    
1157    # Explore available operations
1158    mrapids explore user
1159    
1160    # Execute an operation
1161    mrapids run GetUser --id 123
1162    
1163    # Generate an SDK
1164    mrapids gen sdk --language typescript --output ./sdk
1165    
1166    # Run a test collection
1167    mrapids collection run smoke-tests
1168
1169For detailed help on any command:
1170    mrapids <command> --help
1171
1172For more information, visit: https://microrapid.io/"#
1173}