config_definition.rs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. #![allow(clippy::field_reassign_with_default)]
  2. use schemars::JsonSchema;
  3. use serde::{Deserialize, Serialize};
  4. use serde_json::Value as JsonValue;
  5. use serde_with::skip_serializing_none;
  6. use std::{collections::HashMap, path::PathBuf};
  7. #[derive(Debug, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  8. #[serde(untagged)]
  9. pub enum BundleTarget {
  10. All(Vec<String>),
  11. One(String),
  12. }
  13. #[skip_serializing_none]
  14. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  15. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  16. pub struct DebConfig {
  17. pub depends: Option<Vec<String>>,
  18. #[serde(default)]
  19. pub use_bootstrapper: bool,
  20. }
  21. #[skip_serializing_none]
  22. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  23. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  24. pub struct OsxConfig {
  25. pub frameworks: Option<Vec<String>>,
  26. pub minimum_system_version: Option<String>,
  27. pub exception_domain: Option<String>,
  28. pub license: Option<String>,
  29. #[serde(default)]
  30. pub use_bootstrapper: bool,
  31. }
  32. #[skip_serializing_none]
  33. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  34. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  35. pub struct BundleConfig {
  36. /// Whether we should build your app with tauri-bundler or plain `cargo build`
  37. pub active: bool,
  38. /// The bundle targets, currently supports ["deb", "osx", "msi", "appimage", "dmg"] or "all"
  39. pub targets: Option<BundleTarget>,
  40. pub name: Option<String>,
  41. /// The app's identifier
  42. pub identifier: Option<String>,
  43. /// The app's icons
  44. pub icon: Option<Vec<String>>,
  45. pub version: Option<String>,
  46. /// App resources to bundle.
  47. /// Each resource is a path to a file or directory.
  48. /// Glob patterns are supported.
  49. pub resources: Option<Vec<String>>,
  50. pub copyright: Option<String>,
  51. pub category: Option<String>,
  52. pub short_description: Option<String>,
  53. pub long_description: Option<String>,
  54. pub script: Option<PathBuf>,
  55. #[serde(default)]
  56. pub deb: DebConfig,
  57. #[serde(default)]
  58. pub osx: OsxConfig,
  59. pub external_bin: Option<Vec<String>>,
  60. }
  61. /// A CLI argument definition
  62. #[skip_serializing_none]
  63. #[derive(Debug, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  64. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  65. pub struct CliArg {
  66. /// The short version of the argument, without the preceding -.
  67. ///
  68. /// NOTE: Any leading - characters will be stripped, and only the first non - character will be used as the short version.
  69. pub short: Option<char>,
  70. /// The unique argument name
  71. pub name: String,
  72. /// The argument description which will be shown on the help information.
  73. /// Typically, this is a short (one line) description of the arg.
  74. pub description: Option<String>,
  75. /// The argument long description which will be shown on the help information.
  76. /// Typically this a more detailed (multi-line) message that describes the argument.
  77. pub long_description: Option<String>,
  78. /// Specifies that the argument takes a value at run time.
  79. ///
  80. /// NOTE: values for arguments may be specified in any of the following methods
  81. /// - Using a space such as -o value or --option value
  82. /// - Using an equals and no space such as -o=value or --option=value
  83. /// - Use a short and no space such as -ovalue
  84. pub takes_value: Option<bool>,
  85. /// Specifies that the argument may appear more than once.
  86. ///
  87. /// - For flags, this results in the number of occurrences of the flag being recorded.
  88. /// For example -ddd or -d -d -d would count as three occurrences.
  89. /// - For options there is a distinct difference in multiple occurrences vs multiple values.
  90. /// For example, --opt val1 val2 is one occurrence, but two values. Whereas --opt val1 --opt val2 is two occurrences.
  91. pub multiple: Option<bool>,
  92. /// specifies that the argument may appear more than once.
  93. pub multiple_occurrences: Option<bool>,
  94. ///
  95. pub number_of_values: Option<u64>,
  96. /// Specifies a list of possible values for this argument.
  97. /// At runtime, the CLI verifies that only one of the specified values was used, or fails with an error message.
  98. pub possible_values: Option<Vec<String>>,
  99. /// Specifies the minimum number of values for this argument.
  100. /// For example, if you had a -f <file> argument where you wanted at least 2 'files',
  101. /// you would set `minValues: 2`, and this argument would be satisfied if the user provided, 2 or more values.
  102. pub min_values: Option<u64>,
  103. /// Specifies the maximum number of values are for this argument.
  104. /// For example, if you had a -f <file> argument where you wanted up to 3 'files',
  105. /// you would set .max_values(3), and this argument would be satisfied if the user provided, 1, 2, or 3 values.
  106. pub max_values: Option<u64>,
  107. /// Sets whether or not the argument is required by default.
  108. ///
  109. /// - Required by default means it is required, when no other conflicting rules have been evaluated
  110. /// - Conflicting rules take precedence over being required.
  111. pub required: Option<bool>,
  112. /// Sets an arg that override this arg's required setting
  113. /// i.e. this arg will be required unless this other argument is present.
  114. pub required_unless_present: Option<String>,
  115. /// Sets args that override this arg's required setting
  116. /// i.e. this arg will be required unless all these other arguments are present.
  117. pub required_unless_present_all: Option<Vec<String>>,
  118. /// Sets args that override this arg's required setting
  119. /// i.e. this arg will be required unless at least one of these other arguments are present.
  120. pub required_unless_present_any: Option<Vec<String>>,
  121. /// Sets a conflicting argument by name
  122. /// i.e. when using this argument, the following argument can't be present and vice versa.
  123. pub conflicts_with: Option<String>,
  124. /// The same as conflictsWith but allows specifying multiple two-way conflicts per argument.
  125. pub conflicts_with_all: Option<Vec<String>>,
  126. /// Tets an argument by name that is required when this one is present
  127. /// i.e. when using this argument, the following argument must be present.
  128. pub requires: Option<String>,
  129. /// Sts multiple arguments by names that are required when this one is present
  130. /// i.e. when using this argument, the following arguments must be present.
  131. pub requires_all: Option<Vec<String>>,
  132. /// Allows a conditional requirement with the signature [arg, value]
  133. /// the requirement will only become valid if `arg`'s value equals `${value}`.
  134. pub requires_if: Option<Vec<String>>,
  135. /// Allows specifying that an argument is required conditionally with the signature [arg, value]
  136. /// the requirement will only become valid if the `arg`'s value equals `${value}`.
  137. pub required_if_eq: Option<Vec<String>>,
  138. /// Requires that options use the --option=val syntax
  139. /// i.e. an equals between the option and associated value.
  140. pub require_equals: Option<bool>,
  141. /// The positional argument index, starting at 1.
  142. ///
  143. /// The index refers to position according to other positional argument.
  144. /// It does not define position in the argument list as a whole. When utilized with multiple=true,
  145. /// only the last positional argument may be defined as multiple (i.e. the one with the highest index).
  146. pub index: Option<u64>,
  147. }
  148. /// describes a CLI configuration
  149. #[skip_serializing_none]
  150. #[derive(Debug, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  151. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  152. pub struct CliConfig {
  153. /// command description which will be shown on the help information
  154. description: Option<String>,
  155. /// command long description which will be shown on the help information
  156. long_description: Option<String>,
  157. /// adds additional help information to be displayed in addition to auto-generated help
  158. /// this information is displayed before the auto-generated help information.
  159. /// this is often used for header information
  160. before_help: Option<String>,
  161. /// adds additional help information to be displayed in addition to auto-generated help
  162. /// this information is displayed after the auto-generated help information
  163. /// this is often used to describe how to use the arguments, or caveats to be noted.
  164. after_help: Option<String>,
  165. /// list of args for the command
  166. args: Option<Vec<CliArg>>,
  167. /// list of subcommands of this command.
  168. ///
  169. /// subcommands are effectively sub-apps, because they can contain their own arguments, subcommands, usage, etc.
  170. /// they also function just like the app command, in that they get their own auto generated help and usage
  171. subcommands: Option<HashMap<String, CliConfig>>,
  172. }
  173. #[derive(Debug, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  174. #[serde(untagged)]
  175. pub enum Port {
  176. /// Port with a numeric value.
  177. Value(u16),
  178. /// Random port.
  179. Random,
  180. }
  181. /// The embeddedServer configuration object.
  182. #[skip_serializing_none]
  183. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  184. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  185. pub struct EmbeddedServerConfig {
  186. /// The embedded server host.
  187. pub host: Option<String>,
  188. /// The embedded server port.
  189. /// If it's `random`, we'll generate one at runtime.
  190. pub port: Option<Port>,
  191. /// The base path of the embedded server.
  192. /// The path should always start and end in a forward slash, which the deserializer will ensure
  193. pub public_path: Option<String>,
  194. }
  195. /// The window configuration object.
  196. #[skip_serializing_none]
  197. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  198. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  199. pub struct WindowConfig {
  200. /// The window identifier.
  201. pub label: Option<String>,
  202. /// The window webview URL.
  203. pub url: Option<String>,
  204. /// The horizontal position of the window's top left corner
  205. pub x: Option<f64>,
  206. /// The vertical position of the window's top left corner
  207. pub y: Option<f64>,
  208. /// The window width.
  209. pub width: Option<f64>,
  210. /// The window height.
  211. pub height: Option<f64>,
  212. /// The min window width.
  213. pub min_width: Option<f64>,
  214. /// The min window height.
  215. pub min_height: Option<f64>,
  216. /// The max window width.
  217. pub max_width: Option<f64>,
  218. /// The max window height.
  219. pub max_height: Option<f64>,
  220. /// Whether the window is resizable or not.
  221. #[serde(default)]
  222. pub resizable: bool,
  223. /// The window title.
  224. pub title: Option<String>,
  225. /// Whether the window starts as fullscreen or not.
  226. #[serde(default)]
  227. pub fullscreen: bool,
  228. /// Whether the window is transparent or not.
  229. #[serde(default)]
  230. pub transparent: bool,
  231. /// Whether the window is maximized or not.
  232. #[serde(default)]
  233. pub maximized: bool,
  234. /// Whether the window is visible or not.
  235. #[serde(default)]
  236. pub visible: bool,
  237. /// Whether the window should have borders and bars.
  238. #[serde(default)]
  239. pub decorations: bool,
  240. /// Whether the window should always be on top of other windows.
  241. #[serde(default)]
  242. pub always_on_top: bool,
  243. }
  244. #[skip_serializing_none]
  245. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  246. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  247. pub struct SecurityConfig {
  248. csp: Option<String>,
  249. }
  250. trait Allowlist {
  251. fn to_features(&self) -> Vec<&str>;
  252. }
  253. macro_rules! check_feature {
  254. ($self:ident, $features:ident, $flag:ident, $feature_name: expr) => {
  255. if $self.$flag {
  256. $features.push($feature_name)
  257. }
  258. };
  259. }
  260. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  261. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  262. struct FsAllowlistConfig {
  263. #[serde(default)]
  264. all: bool,
  265. #[serde(default)]
  266. read_text_file: bool,
  267. #[serde(default)]
  268. read_binary_file: bool,
  269. #[serde(default)]
  270. write_file: bool,
  271. #[serde(default)]
  272. write_binary_file: bool,
  273. #[serde(default)]
  274. read_dir: bool,
  275. #[serde(default)]
  276. copy_file: bool,
  277. #[serde(default)]
  278. create_dir: bool,
  279. #[serde(default)]
  280. remove_dir: bool,
  281. #[serde(default)]
  282. remove_file: bool,
  283. #[serde(default)]
  284. rename_file: bool,
  285. #[serde(default)]
  286. path: bool,
  287. }
  288. impl Allowlist for FsAllowlistConfig {
  289. fn to_features(&self) -> Vec<&str> {
  290. if self.all {
  291. vec!["fs-all"]
  292. } else {
  293. let mut features = Vec::new();
  294. check_feature!(self, features, read_text_file, "fs-read-text-file");
  295. check_feature!(self, features, read_binary_file, "fs-read-binary-file");
  296. check_feature!(self, features, write_file, "fs-write-file");
  297. check_feature!(self, features, write_binary_file, "fs-write-binary-file");
  298. check_feature!(self, features, read_dir, "fs-read-dir");
  299. check_feature!(self, features, copy_file, "fs-copy-file");
  300. check_feature!(self, features, create_dir, "fs-create-dir");
  301. check_feature!(self, features, remove_dir, "fs-remove-dir");
  302. check_feature!(self, features, remove_file, "fs-remove-file");
  303. check_feature!(self, features, rename_file, "fs-rename-file");
  304. check_feature!(self, features, path, "fs-path");
  305. features
  306. }
  307. }
  308. }
  309. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  310. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  311. struct WindowAllowlistConfig {
  312. #[serde(default)]
  313. all: bool,
  314. #[serde(default)]
  315. create: bool,
  316. }
  317. impl Allowlist for WindowAllowlistConfig {
  318. fn to_features(&self) -> Vec<&str> {
  319. if self.all {
  320. vec!["window-all"]
  321. } else {
  322. let mut features = Vec::new();
  323. check_feature!(self, features, create, "window-create");
  324. features
  325. }
  326. }
  327. }
  328. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  329. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  330. struct ShellAllowlistConfig {
  331. #[serde(default)]
  332. all: bool,
  333. #[serde(default)]
  334. execute: bool,
  335. #[serde(default)]
  336. open: bool,
  337. }
  338. impl Allowlist for ShellAllowlistConfig {
  339. fn to_features(&self) -> Vec<&str> {
  340. if self.all {
  341. vec!["shell-all"]
  342. } else {
  343. let mut features = Vec::new();
  344. check_feature!(self, features, execute, "shell-execute");
  345. check_feature!(self, features, open, "shell-open");
  346. features
  347. }
  348. }
  349. }
  350. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  351. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  352. struct DialogAllowlistConfig {
  353. #[serde(default)]
  354. all: bool,
  355. #[serde(default)]
  356. open: bool,
  357. #[serde(default)]
  358. save: bool,
  359. }
  360. impl Allowlist for DialogAllowlistConfig {
  361. fn to_features(&self) -> Vec<&str> {
  362. if self.all {
  363. vec!["dialog-all"]
  364. } else {
  365. let mut features = Vec::new();
  366. check_feature!(self, features, open, "dialog-open");
  367. check_feature!(self, features, save, "dialog-save");
  368. features
  369. }
  370. }
  371. }
  372. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  373. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  374. struct HttpAllowlistConfig {
  375. #[serde(default)]
  376. all: bool,
  377. #[serde(default)]
  378. request: bool,
  379. }
  380. impl Allowlist for HttpAllowlistConfig {
  381. fn to_features(&self) -> Vec<&str> {
  382. if self.all {
  383. vec!["http-all"]
  384. } else {
  385. let mut features = Vec::new();
  386. check_feature!(self, features, request, "http-request");
  387. features
  388. }
  389. }
  390. }
  391. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  392. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  393. struct NotificationAllowlistConfig {
  394. #[serde(default)]
  395. all: bool,
  396. }
  397. impl Allowlist for NotificationAllowlistConfig {
  398. fn to_features(&self) -> Vec<&str> {
  399. if self.all {
  400. vec!["notification-all"]
  401. } else {
  402. vec![]
  403. }
  404. }
  405. }
  406. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  407. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  408. struct GlobalShortcutAllowlistConfig {
  409. #[serde(default)]
  410. all: bool,
  411. }
  412. impl Allowlist for GlobalShortcutAllowlistConfig {
  413. fn to_features(&self) -> Vec<&str> {
  414. if self.all {
  415. vec!["global-shortcut-all"]
  416. } else {
  417. vec![]
  418. }
  419. }
  420. }
  421. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  422. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  423. struct AllowlistConfig {
  424. #[serde(default)]
  425. all: bool,
  426. #[serde(default)]
  427. fs: FsAllowlistConfig,
  428. #[serde(default)]
  429. window: WindowAllowlistConfig,
  430. #[serde(default)]
  431. shell: ShellAllowlistConfig,
  432. #[serde(default)]
  433. dialog: DialogAllowlistConfig,
  434. #[serde(default)]
  435. http: HttpAllowlistConfig,
  436. #[serde(default)]
  437. notification: NotificationAllowlistConfig,
  438. #[serde(default)]
  439. global_shortcut: GlobalShortcutAllowlistConfig,
  440. }
  441. impl Allowlist for AllowlistConfig {
  442. fn to_features(&self) -> Vec<&str> {
  443. if self.all {
  444. vec!["api-all"]
  445. } else {
  446. let mut features = Vec::new();
  447. features.extend(self.fs.to_features());
  448. features.extend(self.window.to_features());
  449. features.extend(self.shell.to_features());
  450. features.extend(self.dialog.to_features());
  451. features.extend(self.http.to_features());
  452. features.extend(self.notification.to_features());
  453. features.extend(self.global_shortcut.to_features());
  454. features
  455. }
  456. }
  457. }
  458. /// The Tauri configuration object.
  459. #[skip_serializing_none]
  460. #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  461. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  462. pub struct TauriConfig {
  463. /// The windows configuration.
  464. #[serde(default)]
  465. pub windows: Vec<WindowConfig>,
  466. /// The CLI configuration.
  467. pub cli: Option<CliConfig>,
  468. #[serde(default)]
  469. pub embedded_server: EmbeddedServerConfig,
  470. /// The bundler configuration.
  471. #[serde(default)]
  472. pub bundle: BundleConfig,
  473. #[serde(default)]
  474. allowlist: AllowlistConfig,
  475. pub security: Option<SecurityConfig>,
  476. }
  477. impl TauriConfig {
  478. #[allow(dead_code)]
  479. pub fn features(&self) -> Vec<&str> {
  480. self.allowlist.to_features()
  481. }
  482. }
  483. /// The Build configuration object.
  484. #[skip_serializing_none]
  485. #[derive(Debug, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  486. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  487. pub struct BuildConfig {
  488. /// the app's dev server URL, or the path to the directory containing an index.html file
  489. #[serde(default = "default_dev_path")]
  490. pub dev_path: String,
  491. /// the path to the app's dist dir. This path must contain your index.html file.
  492. #[serde(default = "default_dist_dir")]
  493. pub dist_dir: String,
  494. /// a shell command to run before `tauri dev` kicks in
  495. pub before_dev_command: Option<String>,
  496. /// a shell command to run before `tauri build` kicks in
  497. pub before_build_command: Option<String>,
  498. /// Whether we should inject the Tauri API on `window.__TAURI__` or not.
  499. #[serde(default)]
  500. pub with_global_tauri: bool,
  501. }
  502. fn default_dev_path() -> String {
  503. "".to_string()
  504. }
  505. fn default_dist_dir() -> String {
  506. "../dist".to_string()
  507. }
  508. type JsonObject = HashMap<String, JsonValue>;
  509. /// The tauri.conf.json mapper.
  510. #[skip_serializing_none]
  511. #[derive(Debug, PartialEq, Clone, Deserialize, Serialize, JsonSchema)]
  512. #[serde(rename_all = "camelCase", deny_unknown_fields)]
  513. pub struct Config {
  514. /// The Tauri configuration.
  515. #[serde(default)]
  516. pub tauri: TauriConfig,
  517. /// The build configuration.
  518. #[serde(default = "default_build")]
  519. pub build: BuildConfig,
  520. /// The plugins config.
  521. #[serde(default)]
  522. pub plugins: HashMap<String, JsonObject>,
  523. }
  524. fn default_build() -> BuildConfig {
  525. BuildConfig {
  526. dev_path: default_dev_path(),
  527. dist_dir: default_dist_dir(),
  528. before_dev_command: None,
  529. before_build_command: None,
  530. with_global_tauri: false,
  531. }
  532. }