1use clap::{CommandFactory, Parser, Subcommand, ValueEnum};
2use clap_complete::Shell;
3
4#[derive(Parser, Debug)]
8#[command(name = "idgen")]
9#[command(author = "Mohamed Aamir Maniar <aamir.maniar@maniartech.com>")]
10#[command(version)]
11#[command(about = "Generate and inspect unique identifiers", long_about = None)]
12#[command(after_help = "EXAMPLES:
13 idgen Generate a random UUID v4 (default)
14 idgen -t uuid1 Generate a time-based UUID v1
15 idgen -t uuid3 --namespace DNS --name example.com
16 idgen -t nanoid -l 10 Generate a NanoID of length 10
17 idgen -t ulid Generate a ULID
18 idgen -c 5 Generate 5 UUIDs
19 idgen -p 'test-' -s '.log' Add prefix and suffix
20 idgen --json Output as JSON
21 idgen inspect 550e8400-e29b-44d4-a716-446655440000
22 idgen completions bash Generate bash completions")]
23pub struct Cli {
24 #[arg(short = 't', long = "type", value_enum, default_value = "uuid4")]
26 pub id_type: IdType,
27
28 #[arg(short = 'f', long = "format", value_enum, default_value = "hyphenated")]
30 pub format: UuidFormat,
31
32 #[arg(short = 'c', long = "count", default_value = "1")]
34 pub count: u32,
35
36 #[arg(short = 'l', long = "length")]
38 pub length: Option<usize>,
39
40 #[arg(short = 'p', long = "prefix", default_value = "")]
42 pub prefix: String,
43
44 #[arg(short = 's', long = "suffix", default_value = "")]
46 pub suffix: String,
47
48 #[arg(long = "namespace")]
50 pub namespace: Option<String>,
51
52 #[arg(long = "name")]
54 pub name: Option<String>,
55
56 #[arg(long = "json")]
58 pub json: bool,
59
60 #[arg(short = 'b', long = "banner")]
62 pub banner: bool,
63
64 #[command(subcommand)]
65 pub command: Option<Commands>,
66}
67
68#[derive(Subcommand, Debug)]
69pub enum Commands {
70 Inspect {
72 id: String,
74
75 #[arg(long = "json")]
77 json: bool,
78 },
79
80 Completions {
82 #[arg(value_enum)]
84 shell: Shell,
85 },
86
87 #[command(name = "manpage", hide = true)]
89 ManPage,
90}
91
92#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
93pub enum IdType {
94 #[value(name = "uuid1", alias = "u1")]
96 Uuid1,
97
98 #[value(name = "uuid3", alias = "u3")]
100 Uuid3,
101
102 #[value(name = "uuid4", alias = "u4")]
104 Uuid4,
105
106 #[value(name = "uuid5", alias = "u5")]
108 Uuid5,
109
110 #[value(name = "nanoid", alias = "nano")]
112 NanoId,
113
114 #[value(name = "cuid1", alias = "c1")]
116 Cuid1,
117
118 #[value(name = "cuid2", alias = "c2")]
120 Cuid2,
121
122 #[value(name = "ulid")]
124 Ulid,
125
126 #[value(name = "objectid", alias = "oid")]
128 ObjectId,
129}
130
131#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
132pub enum UuidFormat {
133 #[value(name = "hyphenated", alias = "h")]
135 Hyphenated,
136
137 #[value(name = "simple", alias = "s")]
139 Simple,
140
141 #[value(name = "urn", alias = "u")]
143 Urn,
144}
145
146pub fn resolve_namespace(namespace: &str) -> Result<String, String> {
148 match namespace.to_uppercase().as_str() {
149 "DNS" => Ok("6ba7b810-9dad-11d1-80b4-00c04fd430c8".to_string()),
150 "URL" => Ok("6ba7b811-9dad-11d1-80b4-00c04fd430c8".to_string()),
151 "OID" => Ok("6ba7b812-9dad-11d1-80b4-00c04fd430c8".to_string()),
152 "X500" => Ok("6ba7b814-9dad-11d1-80b4-00c04fd430c8".to_string()),
153 _ => {
154 if namespace.len() >= 32 && (namespace.len() == 32 || namespace.len() == 36) {
156 Ok(namespace.to_string())
157 } else {
158 Err(format!(
159 "Invalid namespace '{}'. Use DNS, URL, OID, X500, or a valid UUID.",
160 namespace
161 ))
162 }
163 }
164 }
165}
166
167pub fn build_cli() -> clap::Command {
168 Cli::command()
169}