Skip to main content

turbopack_cli/
arguments.rs

1use std::{
2    net::IpAddr,
3    path::{Path, PathBuf},
4    str::FromStr,
5};
6
7use anyhow::anyhow;
8use bincode::{Decode, Encode};
9use clap::{Args, Parser, ValueEnum};
10use turbo_tasks::{NonLocalValue, TaskInput, trace::TraceRawVcs};
11use turbopack_core::issue::IssueSeverity;
12
13#[derive(Debug, Parser)]
14#[clap(author, version, about, long_about = None)]
15pub enum Arguments {
16    Build(BuildArguments),
17    Dev(DevArguments),
18}
19
20impl Arguments {
21    /// The directory of the application. see [CommonArguments]::dir
22    pub fn dir(&self) -> Option<&Path> {
23        match self {
24            Arguments::Build(args) => args.common.dir.as_deref(),
25            Arguments::Dev(args) => args.common.dir.as_deref(),
26        }
27    }
28
29    /// The number of worker threads to use. see [CommonArguments]::worker_threads
30    pub fn worker_threads(&self) -> Option<usize> {
31        match self {
32            Arguments::Build(args) => args.common.worker_threads,
33            Arguments::Dev(args) => args.common.worker_threads,
34        }
35    }
36}
37
38#[derive(
39    Copy,
40    Clone,
41    Debug,
42    ValueEnum,
43    PartialEq,
44    Eq,
45    Hash,
46    TaskInput,
47    NonLocalValue,
48    TraceRawVcs,
49    Encode,
50    Decode,
51)]
52pub enum Target {
53    Browser,
54    Node,
55}
56
57#[derive(Debug, Args, Clone)]
58pub struct CommonArguments {
59    /// The entrypoints of the project. Resolved relative to the project's
60    /// directory (`--dir`).
61    #[clap(value_parser)]
62    pub entries: Option<Vec<String>>,
63
64    /// The directory of the application.
65    /// If no directory is provided, the current directory will be used.
66    #[clap(short, long, value_parser)]
67    pub dir: Option<PathBuf>,
68
69    /// The root directory of the project. Nothing outside of this directory can
70    /// be accessed. e. g. the monorepo root.
71    /// If no directory is provided, `dir` will be used.
72    #[clap(long, value_parser)]
73    pub root: Option<PathBuf>,
74
75    /// Filter by issue severity.
76    #[clap(short, long)]
77    pub log_level: Option<IssueSeverityCliOption>,
78
79    /// Show all log messages without limit.
80    #[clap(long)]
81    pub show_all: bool,
82
83    /// Expand the log details.
84    #[clap(long)]
85    pub log_detail: bool,
86
87    /// Whether to enable full task stats recording in Turbo Engine.
88    #[clap(long)]
89    pub full_stats: bool,
90
91    /// Whether to build for the `browser` or `node`
92    #[clap(long)]
93    pub target: Option<Target>,
94
95    /// Number of worker threads to use for parallel processing
96    #[clap(long)]
97    pub worker_threads: Option<usize>,
98
99    /// Enable filesystem-backed persistent caching.
100    /// Cache is stored at `<cache-dir>/<git-version>`.
101    #[clap(long)]
102    pub persistent_caching: bool,
103
104    /// Directory to store the persistent cache.
105    /// Defaults to `.turbopack/cache` relative to the project directory.
106    #[clap(long)]
107    pub cache_dir: Option<PathBuf>,
108    // Enable experimental garbage collection with the provided memory limit in
109    // MB.
110    // #[clap(long)]
111    // pub memory_limit: Option<usize>,
112}
113
114#[derive(Debug, Args)]
115#[clap(author, version, about, long_about = None)]
116pub struct DevArguments {
117    #[clap(flatten)]
118    pub common: CommonArguments,
119
120    /// The port number on which to start the application
121    /// Note: setting env PORT allows to configure port without explicit cli
122    /// args. However, this is temporary measure to conform with existing
123    /// next.js devserver and can be removed in the future.
124    #[clap(short, long, value_parser, default_value_t = 3000, env = "PORT")]
125    pub port: u16,
126
127    /// Hostname on which to start the application
128    #[clap(short = 'H', long, value_parser, default_value = "0.0.0.0")]
129    pub hostname: IpAddr,
130
131    /// Compile all, instead of only compiling referenced assets when their
132    /// parent asset is requested
133    #[clap(long)]
134    pub eager_compile: bool,
135
136    /// Don't open the browser automatically when the dev server has started.
137    #[clap(long)]
138    pub no_open: bool,
139
140    // ==
141    // = Inherited options from next-dev, need revisit later.
142    // ==
143    /// If port is not explicitly specified, use different port if it's already
144    /// in use.
145    #[clap(long)]
146    pub allow_retry: bool,
147}
148
149#[derive(Debug, Args)]
150#[clap(author, version, about, long_about = None)]
151pub struct BuildArguments {
152    #[clap(flatten)]
153    pub common: CommonArguments,
154
155    /// Don't generate sourcemaps.
156    #[clap(long)]
157    pub no_sourcemap: bool,
158
159    /// Don't minify build output.
160    #[clap(long)]
161    pub no_minify: bool,
162
163    /// Don't perform scope hoisting.
164    #[clap(long)]
165    pub no_scope_hoist: bool,
166
167    /// Drop the `TurboTasks` object upon exit. By default we intentionally leak this memory, as
168    /// we're about to exit the process anyways, but that can cause issues with valgrind or other
169    /// leak detectors.
170    #[clap(long, hide = true)]
171    pub force_memory_cleanup: bool,
172}
173
174#[derive(Clone, Copy, PartialEq, Eq, Debug)]
175pub struct IssueSeverityCliOption(pub IssueSeverity);
176
177impl ValueEnum for IssueSeverityCliOption {
178    fn value_variants<'a>() -> &'a [Self] {
179        const VARIANTS: [IssueSeverityCliOption; 8] = [
180            IssueSeverityCliOption(IssueSeverity::Bug),
181            IssueSeverityCliOption(IssueSeverity::Fatal),
182            IssueSeverityCliOption(IssueSeverity::Error),
183            IssueSeverityCliOption(IssueSeverity::Warning),
184            IssueSeverityCliOption(IssueSeverity::Hint),
185            IssueSeverityCliOption(IssueSeverity::Note),
186            IssueSeverityCliOption(IssueSeverity::Suggestion),
187            IssueSeverityCliOption(IssueSeverity::Info),
188        ];
189        &VARIANTS
190    }
191
192    fn to_possible_value<'a>(&self) -> Option<clap::builder::PossibleValue> {
193        Some(clap::builder::PossibleValue::new(self.0.as_str()).help(self.0.as_help_str()))
194    }
195}
196
197impl FromStr for IssueSeverityCliOption {
198    type Err = anyhow::Error;
199
200    fn from_str(s: &str) -> Result<Self, Self::Err> {
201        <IssueSeverityCliOption as clap::ValueEnum>::from_str(s, true).map_err(|s| anyhow!("{}", s))
202    }
203}