Skip to main content

numi_cli/
cli.rs

1use std::path::PathBuf;
2
3use clap::{ArgAction, Args, Parser, Subcommand};
4
5#[derive(Debug, Parser)]
6#[command(
7    name = "numi",
8    version,
9    about = "Generate Swift code from Apple project resources",
10    long_about = "Generate Swift code from asset catalogs, localization files, and other project resources.",
11    before_help = "Generate Swift code from Apple project resources",
12    after_help = "Examples:\n  numi init\n  numi generate\n  numi check\n  numi generate --workspace\n  numi dump-context --job l10n",
13    propagate_version = true,
14    subcommand_required = true
15)]
16pub struct Cli {
17    #[command(subcommand)]
18    pub command: Option<Command>,
19}
20
21#[derive(Debug, Subcommand)]
22pub enum Command {
23    #[command(
24        about = "Generate outputs for one config or workspace",
25        after_help = "Examples:\n  numi generate\n  numi generate --job assets --job l10n\n  numi generate --workspace"
26    )]
27    Generate(GenerateArgs),
28    #[command(
29        about = "Check whether generated outputs are up to date",
30        after_help = "Examples:\n  numi check\n  numi check --job l10n\n  numi check --workspace"
31    )]
32    Check(CheckArgs),
33    #[command(about = "Write a starter numi.toml in the current directory")]
34    Init(InitArgs),
35    #[command(about = "Inspect resolved config paths and values")]
36    Config(ConfigCommand),
37    #[command(
38        name = "dump-context",
39        about = "Print the template context for a single job",
40        after_help = "Examples:\n  numi dump-context --job l10n\n  numi dump-context --config AppUI/numi.toml --job assets"
41    )]
42    DumpContext(DumpContextArgs),
43}
44
45#[derive(Debug, Args)]
46#[command(about = "Inspect resolved config paths and values")]
47pub struct ConfigCommand {
48    #[command(subcommand)]
49    pub command: ConfigSubcommand,
50}
51
52#[derive(Debug, Subcommand)]
53pub enum ConfigSubcommand {
54    #[command(about = "Print the resolved config path")]
55    Locate(LocateArgs),
56    #[command(about = "Print the resolved config with defaults applied")]
57    Print(PrintArgs),
58}
59
60#[derive(Debug, Args)]
61pub struct LocateArgs {
62    #[arg(
63        long = "config",
64        help = "Use a specific numi.toml instead of auto-discovery"
65    )]
66    pub config: Option<PathBuf>,
67}
68
69#[derive(Debug, Args)]
70pub struct GenerateArgs {
71    #[arg(
72        long = "config",
73        help = "Use a specific numi.toml instead of auto-discovery"
74    )]
75    pub config: Option<PathBuf>,
76    #[arg(
77        long = "workspace",
78        action = ArgAction::SetTrue,
79        help = "Use the ancestor workspace manifest instead of the nearest member manifest"
80    )]
81    pub workspace: bool,
82    #[arg(long = "job", help = "Limit generation to the selected job name")]
83    pub jobs: Vec<String>,
84    #[command(flatten)]
85    pub incremental_override: IncrementalOverrideArgs,
86}
87
88#[derive(Debug, Args)]
89pub struct CheckArgs {
90    #[arg(
91        long = "config",
92        help = "Use a specific numi.toml instead of auto-discovery"
93    )]
94    pub config: Option<PathBuf>,
95    #[arg(
96        long = "workspace",
97        action = ArgAction::SetTrue,
98        help = "Use the ancestor workspace manifest instead of the nearest member manifest"
99    )]
100    pub workspace: bool,
101    #[arg(long = "job", help = "Limit checking to the selected job name")]
102    pub jobs: Vec<String>,
103}
104
105#[derive(Debug, Args)]
106pub struct InitArgs {
107    #[arg(
108        long,
109        help = "Overwrite an existing numi.toml in the current directory"
110    )]
111    pub force: bool,
112}
113
114#[derive(Debug, Args)]
115pub struct PrintArgs {
116    #[arg(
117        long = "config",
118        help = "Use a specific numi.toml instead of auto-discovery"
119    )]
120    pub config: Option<PathBuf>,
121}
122
123#[derive(Debug, Args)]
124pub struct DumpContextArgs {
125    #[arg(
126        long = "config",
127        help = "Use a specific numi.toml instead of auto-discovery"
128    )]
129    pub config: Option<PathBuf>,
130    #[arg(long = "job", help = "Job name to render as JSON context")]
131    pub job: String,
132}
133
134#[derive(Debug, Args, Default, Clone, PartialEq, Eq)]
135pub struct IncrementalOverrideArgs {
136    #[arg(
137        long = "incremental",
138        action = ArgAction::SetTrue,
139        help = "Force incremental parsing when supported",
140        conflicts_with = "no_incremental"
141    )]
142    pub incremental: bool,
143    #[arg(
144        long = "no-incremental",
145        action = ArgAction::SetTrue,
146        help = "Disable incremental parsing even when the config enables it"
147    )]
148    pub no_incremental: bool,
149}
150
151impl IncrementalOverrideArgs {
152    pub fn resolve(&self) -> Option<bool> {
153        if self.incremental {
154            Some(true)
155        } else if self.no_incremental {
156            Some(false)
157        } else {
158            None
159        }
160    }
161}