config.rs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032
  1. // Copyright 2019-2021 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. //! The Tauri configuration used at runtime.
  5. //!
  6. //! It is pulled from a `tauri.conf.json` file and the [`Config`] struct is generated at compile time.
  7. //!
  8. //! # Stability
  9. //! This is a core functionality that is not considered part of the stable API.
  10. //! If you use it, note that it may include breaking changes in the future.
  11. use std::{collections::HashMap, path::PathBuf};
  12. use serde::Deserialize;
  13. use serde_json::Value as JsonValue;
  14. use url::Url;
  15. /// The window webview URL options.
  16. #[derive(PartialEq, Debug, Clone, Deserialize)]
  17. #[serde(untagged)]
  18. #[non_exhaustive]
  19. pub enum WindowUrl {
  20. /// An external URL.
  21. External(Url),
  22. /// An app URL.
  23. App(PathBuf),
  24. }
  25. impl Default for WindowUrl {
  26. fn default() -> Self {
  27. Self::App("index.html".into())
  28. }
  29. }
  30. /// The window configuration object.
  31. #[derive(PartialEq, Deserialize, Debug, Clone)]
  32. #[serde(rename_all = "camelCase")]
  33. pub struct WindowConfig {
  34. #[serde(default = "default_window_label")]
  35. /// The window identifier.
  36. pub label: String,
  37. /// The window webview URL.
  38. #[serde(default)]
  39. pub url: WindowUrl,
  40. /// Whether the file drop is enabled or not on the webview. By default it is enabled.
  41. ///
  42. /// Disabling it is required to use drag and drop on the frontend on Windows.
  43. #[serde(default = "default_file_drop_enabled")]
  44. pub file_drop_enabled: bool,
  45. /// Center the window.
  46. #[serde(default)]
  47. pub center: bool,
  48. /// The horizontal position of the window's top left corner
  49. pub x: Option<f64>,
  50. /// The vertical position of the window's top left corner
  51. pub y: Option<f64>,
  52. /// The window width.
  53. #[serde(default = "default_width")]
  54. pub width: f64,
  55. /// The window height.
  56. #[serde(default = "default_height")]
  57. pub height: f64,
  58. /// The min window width.
  59. pub min_width: Option<f64>,
  60. /// The min window height.
  61. pub min_height: Option<f64>,
  62. /// The max window width.
  63. pub max_width: Option<f64>,
  64. /// The max window height.
  65. pub max_height: Option<f64>,
  66. /// Whether the window is resizable or not.
  67. #[serde(default = "default_resizable")]
  68. pub resizable: bool,
  69. /// The window title.
  70. #[serde(default = "default_title")]
  71. pub title: String,
  72. /// Whether the window starts as fullscreen or not.
  73. #[serde(default)]
  74. pub fullscreen: bool,
  75. /// Whether the window will be initially hidden or focused.
  76. #[serde(default)]
  77. pub focus: bool,
  78. /// Whether the window is transparent or not.
  79. #[serde(default)]
  80. pub transparent: bool,
  81. /// Whether the window is maximized or not.
  82. #[serde(default)]
  83. pub maximized: bool,
  84. /// Whether the window is visible or not.
  85. #[serde(default = "default_visible")]
  86. pub visible: bool,
  87. /// Whether the window should have borders and bars.
  88. #[serde(default = "default_decorations")]
  89. pub decorations: bool,
  90. /// Whether the window should always be on top of other windows.
  91. #[serde(default)]
  92. pub always_on_top: bool,
  93. /// Whether or not the window icon should be added to the taskbar.
  94. #[serde(default)]
  95. pub skip_taskbar: bool,
  96. }
  97. fn default_window_label() -> String {
  98. "main".to_string()
  99. }
  100. fn default_width() -> f64 {
  101. 800f64
  102. }
  103. fn default_height() -> f64 {
  104. 600f64
  105. }
  106. fn default_resizable() -> bool {
  107. true
  108. }
  109. fn default_visible() -> bool {
  110. true
  111. }
  112. fn default_decorations() -> bool {
  113. true
  114. }
  115. fn default_title() -> String {
  116. "Tauri App".to_string()
  117. }
  118. fn default_file_drop_enabled() -> bool {
  119. true
  120. }
  121. impl Default for WindowConfig {
  122. fn default() -> Self {
  123. Self {
  124. label: default_window_label(),
  125. url: WindowUrl::default(),
  126. file_drop_enabled: default_file_drop_enabled(),
  127. center: false,
  128. x: None,
  129. y: None,
  130. width: default_width(),
  131. height: default_height(),
  132. min_width: None,
  133. min_height: None,
  134. max_width: None,
  135. max_height: None,
  136. resizable: default_resizable(),
  137. title: default_title(),
  138. fullscreen: false,
  139. focus: false,
  140. transparent: false,
  141. maximized: false,
  142. visible: default_visible(),
  143. decorations: default_decorations(),
  144. always_on_top: false,
  145. skip_taskbar: false,
  146. }
  147. }
  148. }
  149. /// The Updater configuration object.
  150. #[derive(PartialEq, Deserialize, Debug, Clone)]
  151. #[serde(rename_all = "camelCase")]
  152. pub struct UpdaterConfig {
  153. /// Whether the updater is active or not.
  154. #[serde(default)]
  155. pub active: bool,
  156. /// Display built-in dialog or use event system if disabled.
  157. #[serde(default = "default_updater_dialog")]
  158. pub dialog: bool,
  159. /// The updater endpoints.
  160. #[serde(default)]
  161. pub endpoints: Option<Vec<String>>,
  162. /// Optional pubkey.
  163. #[serde(default)]
  164. pub pubkey: Option<String>,
  165. }
  166. fn default_updater_dialog() -> bool {
  167. true
  168. }
  169. impl Default for UpdaterConfig {
  170. fn default() -> Self {
  171. Self {
  172. active: false,
  173. dialog: true,
  174. endpoints: None,
  175. pubkey: None,
  176. }
  177. }
  178. }
  179. /// Security configuration.
  180. #[derive(PartialEq, Deserialize, Debug, Clone, Default)]
  181. #[serde(rename_all = "camelCase")]
  182. pub struct SecurityConfig {
  183. /// Content security policy to inject to HTML files with `tauri://` and other user-defined custom protocols.
  184. pub csp: Option<String>,
  185. }
  186. /// Configuration for application system tray icon.
  187. #[derive(PartialEq, Deserialize, Debug, Clone, Default)]
  188. #[serde(rename_all = "camelCase")]
  189. pub struct SystemTrayConfig {
  190. /// Path to the icon to use on the system tray.
  191. /// Automatically set to be an `.png` on macOS and Linux, and `.ico` on Windows.
  192. pub icon_path: PathBuf,
  193. /// A Boolean value that determines whether the image represents a [template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc) image on macOS.
  194. #[serde(default)]
  195. pub icon_as_template: bool,
  196. }
  197. /// A CLI argument definition
  198. #[derive(PartialEq, Deserialize, Debug, Default, Clone)]
  199. #[serde(rename_all = "camelCase")]
  200. pub struct CliArg {
  201. /// The short version of the argument, without the preceding -.
  202. ///
  203. /// NOTE: Any leading - characters will be stripped, and only the first non - character will be used as the short version.
  204. pub short: Option<char>,
  205. /// The unique argument name
  206. pub name: String,
  207. /// The argument description which will be shown on the help information.
  208. /// Typically, this is a short (one line) description of the arg.
  209. pub description: Option<String>,
  210. /// The argument long description which will be shown on the help information.
  211. /// Typically this a more detailed (multi-line) message that describes the argument.
  212. pub long_description: Option<String>,
  213. /// Specifies that the argument takes a value at run time.
  214. ///
  215. /// NOTE: values for arguments may be specified in any of the following methods
  216. /// - Using a space such as -o value or --option value
  217. /// - Using an equals and no space such as -o=value or --option=value
  218. /// - Use a short and no space such as -ovalue
  219. pub takes_value: Option<bool>,
  220. /// Specifies that the argument may appear more than once.
  221. ///
  222. /// - For flags, this results in the number of occurrences of the flag being recorded.
  223. /// For example -ddd or -d -d -d would count as three occurrences.
  224. /// - For options there is a distinct difference in multiple occurrences vs multiple values.
  225. /// For example, --opt val1 val2 is one occurrence, but two values. Whereas --opt val1 --opt val2 is two occurrences.
  226. pub multiple: Option<bool>,
  227. ///
  228. pub multiple_occurrences: Option<bool>,
  229. ///
  230. pub number_of_values: Option<u64>,
  231. /// Specifies a list of possible values for this argument.
  232. /// At runtime, the CLI verifies that only one of the specified values was used, or fails with an error message.
  233. pub possible_values: Option<Vec<String>>,
  234. /// Specifies the minimum number of values for this argument.
  235. /// For example, if you had a -f <file> argument where you wanted at least 2 'files',
  236. /// you would set `minValues: 2`, and this argument would be satisfied if the user provided, 2 or more values.
  237. pub min_values: Option<u64>,
  238. /// Specifies the maximum number of values are for this argument.
  239. /// For example, if you had a -f <file> argument where you wanted up to 3 'files',
  240. /// you would set .max_values(3), and this argument would be satisfied if the user provided, 1, 2, or 3 values.
  241. pub max_values: Option<u64>,
  242. /// Sets whether or not the argument is required by default.
  243. ///
  244. /// - Required by default means it is required, when no other conflicting rules have been evaluated
  245. /// - Conflicting rules take precedence over being required.
  246. pub required: Option<bool>,
  247. /// Sets an arg that override this arg's required setting
  248. /// i.e. this arg will be required unless this other argument is present.
  249. pub required_unless_present: Option<String>,
  250. /// Sets args that override this arg's required setting
  251. /// i.e. this arg will be required unless all these other arguments are present.
  252. pub required_unless_present_all: Option<Vec<String>>,
  253. /// Sets args that override this arg's required setting
  254. /// i.e. this arg will be required unless at least one of these other arguments are present.
  255. pub required_unless_present_any: Option<Vec<String>>,
  256. /// Sets a conflicting argument by name
  257. /// i.e. when using this argument, the following argument can't be present and vice versa.
  258. pub conflicts_with: Option<String>,
  259. /// The same as conflictsWith but allows specifying multiple two-way conflicts per argument.
  260. pub conflicts_with_all: Option<Vec<String>>,
  261. /// Tets an argument by name that is required when this one is present
  262. /// i.e. when using this argument, the following argument must be present.
  263. pub requires: Option<String>,
  264. /// Sts multiple arguments by names that are required when this one is present
  265. /// i.e. when using this argument, the following arguments must be present.
  266. pub requires_all: Option<Vec<String>>,
  267. /// Allows a conditional requirement with the signature [arg, value]
  268. /// the requirement will only become valid if `arg`'s value equals `${value}`.
  269. pub requires_if: Option<Vec<String>>,
  270. /// Allows specifying that an argument is required conditionally with the signature [arg, value]
  271. /// the requirement will only become valid if the `arg`'s value equals `${value}`.
  272. pub required_if_eq: Option<Vec<String>>,
  273. /// Requires that options use the --option=val syntax
  274. /// i.e. an equals between the option and associated value.
  275. pub require_equals: Option<bool>,
  276. /// The positional argument index, starting at 1.
  277. ///
  278. /// The index refers to position according to other positional argument.
  279. /// It does not define position in the argument list as a whole. When utilized with multiple=true,
  280. /// only the last positional argument may be defined as multiple (i.e. the one with the highest index).
  281. pub index: Option<u64>,
  282. }
  283. /// The CLI command definition.
  284. #[derive(PartialEq, Deserialize, Debug, Clone)]
  285. #[serde(rename_all = "camelCase")]
  286. pub struct CliConfig {
  287. /// Command description which will be shown on the help information.
  288. pub description: Option<String>,
  289. /// Command long description which will be shown on the help information.
  290. pub long_description: Option<String>,
  291. /// Adds additional help information to be displayed in addition to auto-generated help.
  292. /// This information is displayed before the auto-generated help information.
  293. /// This is often used for header information.
  294. pub before_help: Option<String>,
  295. /// Adds additional help information to be displayed in addition to auto-generated help.
  296. /// This information is displayed after the auto-generated help information.
  297. /// This is often used to describe how to use the arguments, or caveats to be noted.
  298. pub after_help: Option<String>,
  299. /// List of arguments for the command
  300. pub args: Option<Vec<CliArg>>,
  301. /// List of subcommands of this command
  302. pub subcommands: Option<HashMap<String, CliConfig>>,
  303. }
  304. impl CliConfig {
  305. /// List of arguments for the command
  306. pub fn args(&self) -> Option<&Vec<CliArg>> {
  307. self.args.as_ref()
  308. }
  309. /// List of subcommands of this command
  310. pub fn subcommands(&self) -> Option<&HashMap<String, CliConfig>> {
  311. self.subcommands.as_ref()
  312. }
  313. /// Command description which will be shown on the help information.
  314. pub fn description(&self) -> Option<&String> {
  315. self.description.as_ref()
  316. }
  317. /// Command long description which will be shown on the help information.
  318. pub fn long_description(&self) -> Option<&String> {
  319. self.description.as_ref()
  320. }
  321. /// Adds additional help information to be displayed in addition to auto-generated help.
  322. /// This information is displayed before the auto-generated help information.
  323. /// This is often used for header information.
  324. pub fn before_help(&self) -> Option<&String> {
  325. self.before_help.as_ref()
  326. }
  327. /// Adds additional help information to be displayed in addition to auto-generated help.
  328. /// This information is displayed after the auto-generated help information.
  329. /// This is often used to describe how to use the arguments, or caveats to be noted.
  330. pub fn after_help(&self) -> Option<&String> {
  331. self.after_help.as_ref()
  332. }
  333. }
  334. /// The bundler configuration object.
  335. #[derive(PartialEq, Deserialize, Debug)]
  336. #[serde(rename_all = "camelCase")]
  337. pub struct BundleConfig {
  338. /// The bundle identifier.
  339. pub identifier: String,
  340. /// The bundle icons.
  341. #[serde(default)]
  342. pub icon: Vec<String>,
  343. }
  344. impl Default for BundleConfig {
  345. fn default() -> Self {
  346. Self {
  347. identifier: String::from(""),
  348. icon: Vec::default(),
  349. }
  350. }
  351. }
  352. fn default_window_config() -> Vec<WindowConfig> {
  353. vec![Default::default()]
  354. }
  355. /// The Tauri configuration object.
  356. #[derive(PartialEq, Deserialize, Debug)]
  357. #[serde(rename_all = "camelCase")]
  358. pub struct TauriConfig {
  359. /// The window configuration.
  360. #[serde(default = "default_window_config")]
  361. pub windows: Vec<WindowConfig>,
  362. /// The CLI configuration.
  363. #[serde(default)]
  364. pub cli: Option<CliConfig>,
  365. /// The bundler configuration.
  366. #[serde(default)]
  367. pub bundle: BundleConfig,
  368. /// The updater configuration.
  369. #[serde(default)]
  370. pub updater: UpdaterConfig,
  371. /// The security configuration.
  372. #[serde(default)]
  373. pub security: SecurityConfig,
  374. /// System tray configuration.
  375. #[serde(default)]
  376. pub system_tray: Option<SystemTrayConfig>,
  377. }
  378. impl Default for TauriConfig {
  379. fn default() -> Self {
  380. Self {
  381. windows: default_window_config(),
  382. cli: None,
  383. bundle: BundleConfig::default(),
  384. updater: UpdaterConfig::default(),
  385. security: SecurityConfig::default(),
  386. system_tray: None,
  387. }
  388. }
  389. }
  390. /// The `dev_path` and `dist_dir` options.
  391. #[derive(PartialEq, Debug, Clone, Deserialize)]
  392. #[serde(untagged)]
  393. #[non_exhaustive]
  394. pub enum AppUrl {
  395. /// A url or file path.
  396. Url(WindowUrl),
  397. /// An array of files.
  398. Files(Vec<PathBuf>),
  399. }
  400. /// The Build configuration object.
  401. #[derive(PartialEq, Deserialize, Debug)]
  402. #[serde(rename_all = "camelCase")]
  403. pub struct BuildConfig {
  404. /// Directory path or URL to use on development. Default to `http://localhost:8080`.
  405. #[serde(default = "default_dev_path")]
  406. pub dev_path: AppUrl,
  407. /// Distribution directory to use in release build. Default to `../dist`.
  408. #[serde(default = "default_dist_path")]
  409. pub dist_dir: AppUrl,
  410. /// Whether we should inject the Tauri API on `window.__TAURI__` or not.
  411. #[serde(default)]
  412. pub with_global_tauri: bool,
  413. }
  414. fn default_dev_path() -> AppUrl {
  415. AppUrl::Url(WindowUrl::External(
  416. Url::parse("http://localhost:8080").unwrap(),
  417. ))
  418. }
  419. fn default_dist_path() -> AppUrl {
  420. AppUrl::Url(WindowUrl::App("../dist".into()))
  421. }
  422. impl Default for BuildConfig {
  423. fn default() -> Self {
  424. Self {
  425. dev_path: default_dev_path(),
  426. dist_dir: default_dist_path(),
  427. with_global_tauri: false,
  428. }
  429. }
  430. }
  431. /// The package configuration.
  432. #[derive(Debug, Default, PartialEq, Deserialize)]
  433. #[serde(rename_all = "camelCase")]
  434. pub struct PackageConfig {
  435. /// App name.
  436. pub product_name: Option<String>,
  437. /// App version.
  438. pub version: Option<String>,
  439. }
  440. /// The config type mapped to `tauri.conf.json`.
  441. #[derive(Debug, Default, PartialEq, Deserialize)]
  442. #[serde(rename_all = "camelCase")]
  443. pub struct Config {
  444. /// Package settings.
  445. #[serde(default)]
  446. pub package: PackageConfig,
  447. /// The Tauri configuration.
  448. #[serde(default)]
  449. pub tauri: TauriConfig,
  450. /// The build configuration.
  451. #[serde(default)]
  452. pub build: BuildConfig,
  453. /// The plugins config.
  454. #[serde(default)]
  455. pub plugins: PluginConfig,
  456. }
  457. /// The plugin configs holds a HashMap mapping a plugin name to its configuration object.
  458. #[derive(Debug, Clone, Default, PartialEq, Deserialize)]
  459. pub struct PluginConfig(pub HashMap<String, JsonValue>);
  460. /// Implement `ToTokens` for all config structs, allowing a literal `Config` to be built.
  461. ///
  462. /// This allows for a build script to output the values in a `Config` to a `TokenStream`, which can
  463. /// then be consumed by another crate. Useful for passing a config to both the build script and the
  464. /// application using tauri while only parsing it once (in the build script).
  465. #[cfg(feature = "build")]
  466. mod build {
  467. use std::{convert::identity, path::Path};
  468. use proc_macro2::TokenStream;
  469. use quote::{quote, ToTokens, TokenStreamExt};
  470. use super::*;
  471. /// Create a `String` constructor `TokenStream`.
  472. ///
  473. /// e.g. `"Hello World" -> String::from("Hello World").
  474. /// This takes a `&String` to reduce casting all the `&String` -> `&str` manually.
  475. fn str_lit(s: impl AsRef<str>) -> TokenStream {
  476. let s = s.as_ref();
  477. quote! { #s.into() }
  478. }
  479. /// Create an `Option` constructor `TokenStream`.
  480. fn opt_lit(item: Option<&impl ToTokens>) -> TokenStream {
  481. match item {
  482. None => quote! { ::core::option::Option::None },
  483. Some(item) => quote! { ::core::option::Option::Some(#item) },
  484. }
  485. }
  486. /// Helper function to combine an `opt_lit` with `str_lit`.
  487. fn opt_str_lit(item: Option<impl AsRef<str>>) -> TokenStream {
  488. opt_lit(item.map(str_lit).as_ref())
  489. }
  490. /// Helper function to combine an `opt_lit` with a list of `str_lit`
  491. fn opt_vec_str_lit(item: Option<impl IntoIterator<Item = impl AsRef<str>>>) -> TokenStream {
  492. opt_lit(item.map(|list| vec_lit(list, str_lit)).as_ref())
  493. }
  494. /// Create a `Vec` constructor, mapping items with a function that spits out `TokenStream`s.
  495. fn vec_lit<Raw, Tokens>(
  496. list: impl IntoIterator<Item = Raw>,
  497. map: impl Fn(Raw) -> Tokens,
  498. ) -> TokenStream
  499. where
  500. Tokens: ToTokens,
  501. {
  502. let items = list.into_iter().map(map);
  503. quote! { vec![#(#items),*] }
  504. }
  505. /// Create a `PathBuf` constructor `TokenStream`.
  506. ///
  507. /// e.g. `"Hello World" -> String::from("Hello World").
  508. /// This takes a `&String` to reduce casting all the `&String` -> `&str` manually.
  509. fn path_buf_lit(s: impl AsRef<Path>) -> TokenStream {
  510. let s = s.as_ref().to_string_lossy().into_owned();
  511. quote! { ::std::path::PathBuf::from(#s) }
  512. }
  513. /// Create a map constructor, mapping keys and values with other `TokenStream`s.
  514. ///
  515. /// This function is pretty generic because the types of keys AND values get transformed.
  516. fn map_lit<Map, Key, Value, TokenStreamKey, TokenStreamValue, FuncKey, FuncValue>(
  517. map_type: TokenStream,
  518. map: Map,
  519. map_key: FuncKey,
  520. map_value: FuncValue,
  521. ) -> TokenStream
  522. where
  523. <Map as IntoIterator>::IntoIter: ExactSizeIterator,
  524. Map: IntoIterator<Item = (Key, Value)>,
  525. TokenStreamKey: ToTokens,
  526. TokenStreamValue: ToTokens,
  527. FuncKey: Fn(Key) -> TokenStreamKey,
  528. FuncValue: Fn(Value) -> TokenStreamValue,
  529. {
  530. let ident = quote::format_ident!("map");
  531. let map = map.into_iter();
  532. if map.len() > 0 {
  533. let items = map.map(|(key, value)| {
  534. let key = map_key(key);
  535. let value = map_value(value);
  536. quote! { #ident.insert(#key, #value); }
  537. });
  538. quote! {{
  539. let mut #ident = #map_type::new();
  540. #(#items)*
  541. #ident
  542. }}
  543. } else {
  544. quote! { #map_type::new() }
  545. }
  546. }
  547. /// Create a `serde_json::Value` variant `TokenStream` for a number
  548. fn json_value_number_lit(num: &serde_json::Number) -> TokenStream {
  549. // See https://docs.rs/serde_json/1/serde_json/struct.Number.html for guarantees
  550. let prefix = quote! { ::serde_json::Value };
  551. if num.is_u64() {
  552. // guaranteed u64
  553. let num = num.as_u64().unwrap();
  554. quote! { #prefix::Number(#num.into()) }
  555. } else if num.is_i64() {
  556. // guaranteed i64
  557. let num = num.as_i64().unwrap();
  558. quote! { #prefix::Number(#num.into()) }
  559. } else if num.is_f64() {
  560. // guaranteed f64
  561. let num = num.as_f64().unwrap();
  562. quote! { #prefix::Number(#num.into()) }
  563. } else {
  564. // invalid number
  565. quote! { #prefix::Null }
  566. }
  567. }
  568. /// Create a `serde_json::Value` constructor `TokenStream`
  569. fn json_value_lit(jv: &JsonValue) -> TokenStream {
  570. let prefix = quote! { ::serde_json::Value };
  571. match jv {
  572. JsonValue::Null => quote! { #prefix::Null },
  573. JsonValue::Bool(bool) => quote! { #prefix::Bool(#bool) },
  574. JsonValue::Number(number) => json_value_number_lit(number),
  575. JsonValue::String(str) => {
  576. let s = str_lit(str);
  577. quote! { #prefix::String(#s) }
  578. }
  579. JsonValue::Array(vec) => {
  580. let items = vec.iter().map(json_value_lit);
  581. quote! { #prefix::Array(vec![#(#items),*]) }
  582. }
  583. JsonValue::Object(map) => {
  584. let map = map_lit(quote! { ::serde_json::Map }, map, str_lit, json_value_lit);
  585. quote! { #prefix::Object(#map) }
  586. }
  587. }
  588. }
  589. /// Write a `TokenStream` of the `$struct`'s fields to the `$tokens`.
  590. ///
  591. /// All fields must represent a binding of the same name that implements `ToTokens`.
  592. macro_rules! literal_struct {
  593. ($tokens:ident, $struct:ident, $($field:ident),+) => {
  594. $tokens.append_all(quote! {
  595. ::tauri::utils::config::$struct {
  596. $($field: #$field),+
  597. }
  598. });
  599. };
  600. }
  601. impl ToTokens for WindowUrl {
  602. fn to_tokens(&self, tokens: &mut TokenStream) {
  603. let prefix = quote! { ::tauri::utils::config::WindowUrl };
  604. tokens.append_all(match self {
  605. Self::App(path) => {
  606. let path = path_buf_lit(&path);
  607. quote! { #prefix::App(#path) }
  608. }
  609. Self::External(url) => {
  610. let url = url.as_str();
  611. quote! { #prefix::External(#url.parse().unwrap()) }
  612. }
  613. })
  614. }
  615. }
  616. impl ToTokens for WindowConfig {
  617. fn to_tokens(&self, tokens: &mut TokenStream) {
  618. let label = str_lit(&self.label);
  619. let url = &self.url;
  620. let file_drop_enabled = self.file_drop_enabled;
  621. let center = self.center;
  622. let x = opt_lit(self.x.as_ref());
  623. let y = opt_lit(self.y.as_ref());
  624. let width = self.width;
  625. let height = self.height;
  626. let min_width = opt_lit(self.min_width.as_ref());
  627. let min_height = opt_lit(self.min_height.as_ref());
  628. let max_width = opt_lit(self.max_width.as_ref());
  629. let max_height = opt_lit(self.max_height.as_ref());
  630. let resizable = self.resizable;
  631. let title = str_lit(&self.title);
  632. let fullscreen = self.fullscreen;
  633. let focus = self.focus;
  634. let transparent = self.transparent;
  635. let maximized = self.maximized;
  636. let visible = self.visible;
  637. let decorations = self.decorations;
  638. let always_on_top = self.always_on_top;
  639. let skip_taskbar = self.skip_taskbar;
  640. literal_struct!(
  641. tokens,
  642. WindowConfig,
  643. label,
  644. url,
  645. file_drop_enabled,
  646. center,
  647. x,
  648. y,
  649. width,
  650. height,
  651. min_width,
  652. min_height,
  653. max_width,
  654. max_height,
  655. resizable,
  656. title,
  657. fullscreen,
  658. focus,
  659. transparent,
  660. maximized,
  661. visible,
  662. decorations,
  663. always_on_top,
  664. skip_taskbar
  665. );
  666. }
  667. }
  668. impl ToTokens for CliArg {
  669. fn to_tokens(&self, tokens: &mut TokenStream) {
  670. let short = opt_lit(self.short.as_ref());
  671. let name = str_lit(&self.name);
  672. let description = opt_str_lit(self.description.as_ref());
  673. let long_description = opt_str_lit(self.long_description.as_ref());
  674. let takes_value = opt_lit(self.takes_value.as_ref());
  675. let multiple = opt_lit(self.multiple.as_ref());
  676. let multiple_occurrences = opt_lit(self.multiple_occurrences.as_ref());
  677. let number_of_values = opt_lit(self.number_of_values.as_ref());
  678. let possible_values = opt_vec_str_lit(self.possible_values.as_ref());
  679. let min_values = opt_lit(self.min_values.as_ref());
  680. let max_values = opt_lit(self.max_values.as_ref());
  681. let required = opt_lit(self.required.as_ref());
  682. let required_unless_present = opt_str_lit(self.required_unless_present.as_ref());
  683. let required_unless_present_all = opt_vec_str_lit(self.required_unless_present_all.as_ref());
  684. let required_unless_present_any = opt_vec_str_lit(self.required_unless_present_any.as_ref());
  685. let conflicts_with = opt_str_lit(self.conflicts_with.as_ref());
  686. let conflicts_with_all = opt_vec_str_lit(self.conflicts_with_all.as_ref());
  687. let requires = opt_str_lit(self.requires.as_ref());
  688. let requires_all = opt_vec_str_lit(self.requires_all.as_ref());
  689. let requires_if = opt_vec_str_lit(self.requires_if.as_ref());
  690. let required_if_eq = opt_vec_str_lit(self.required_if_eq.as_ref());
  691. let require_equals = opt_lit(self.require_equals.as_ref());
  692. let index = opt_lit(self.index.as_ref());
  693. literal_struct!(
  694. tokens,
  695. CliArg,
  696. short,
  697. name,
  698. description,
  699. long_description,
  700. takes_value,
  701. multiple,
  702. multiple_occurrences,
  703. number_of_values,
  704. possible_values,
  705. min_values,
  706. max_values,
  707. required,
  708. required_unless_present,
  709. required_unless_present_all,
  710. required_unless_present_any,
  711. conflicts_with,
  712. conflicts_with_all,
  713. requires,
  714. requires_all,
  715. requires_if,
  716. required_if_eq,
  717. require_equals,
  718. index
  719. );
  720. }
  721. }
  722. impl ToTokens for CliConfig {
  723. fn to_tokens(&self, tokens: &mut TokenStream) {
  724. let description = opt_str_lit(self.description.as_ref());
  725. let long_description = opt_str_lit(self.long_description.as_ref());
  726. let before_help = opt_str_lit(self.before_help.as_ref());
  727. let after_help = opt_str_lit(self.after_help.as_ref());
  728. let args = {
  729. let args = self.args.as_ref().map(|args| {
  730. let arg = args.iter().map(|a| quote! { #a });
  731. quote! { vec![#(#arg),*] }
  732. });
  733. opt_lit(args.as_ref())
  734. };
  735. let subcommands = opt_lit(
  736. self
  737. .subcommands
  738. .as_ref()
  739. .map(|map| {
  740. map_lit(
  741. quote! { ::std::collections::HashMap },
  742. map,
  743. str_lit,
  744. identity,
  745. )
  746. })
  747. .as_ref(),
  748. );
  749. literal_struct!(
  750. tokens,
  751. CliConfig,
  752. description,
  753. long_description,
  754. before_help,
  755. after_help,
  756. args,
  757. subcommands
  758. );
  759. }
  760. }
  761. impl ToTokens for BundleConfig {
  762. fn to_tokens(&self, tokens: &mut TokenStream) {
  763. let identifier = str_lit(&self.identifier);
  764. let icon = vec_lit(&self.icon, str_lit);
  765. literal_struct!(tokens, BundleConfig, identifier, icon);
  766. }
  767. }
  768. impl ToTokens for AppUrl {
  769. fn to_tokens(&self, tokens: &mut TokenStream) {
  770. let prefix = quote! { ::tauri::utils::config::AppUrl };
  771. tokens.append_all(match self {
  772. Self::Url(url) => {
  773. quote! { #prefix::Url(#url) }
  774. }
  775. Self::Files(files) => {
  776. let files = vec_lit(files, path_buf_lit);
  777. quote! { #prefix::Files(#files) }
  778. }
  779. })
  780. }
  781. }
  782. impl ToTokens for BuildConfig {
  783. fn to_tokens(&self, tokens: &mut TokenStream) {
  784. let dev_path = &self.dev_path;
  785. let dist_dir = &self.dist_dir;
  786. let with_global_tauri = self.with_global_tauri;
  787. literal_struct!(tokens, BuildConfig, dev_path, dist_dir, with_global_tauri);
  788. }
  789. }
  790. impl ToTokens for UpdaterConfig {
  791. fn to_tokens(&self, tokens: &mut TokenStream) {
  792. let active = self.active;
  793. let dialog = self.dialog;
  794. let pubkey = opt_str_lit(self.pubkey.as_ref());
  795. let endpoints = opt_vec_str_lit(self.endpoints.as_ref());
  796. literal_struct!(tokens, UpdaterConfig, active, dialog, pubkey, endpoints);
  797. }
  798. }
  799. impl ToTokens for SecurityConfig {
  800. fn to_tokens(&self, tokens: &mut TokenStream) {
  801. let csp = opt_str_lit(self.csp.as_ref());
  802. literal_struct!(tokens, SecurityConfig, csp);
  803. }
  804. }
  805. impl ToTokens for SystemTrayConfig {
  806. fn to_tokens(&self, tokens: &mut TokenStream) {
  807. let icon_as_template = self.icon_as_template;
  808. let icon_path = path_buf_lit(&self.icon_path);
  809. literal_struct!(tokens, SystemTrayConfig, icon_path, icon_as_template);
  810. }
  811. }
  812. impl ToTokens for TauriConfig {
  813. fn to_tokens(&self, tokens: &mut TokenStream) {
  814. let windows = vec_lit(&self.windows, identity);
  815. let cli = opt_lit(self.cli.as_ref());
  816. let bundle = &self.bundle;
  817. let updater = &self.updater;
  818. let security = &self.security;
  819. let system_tray = opt_lit(self.system_tray.as_ref());
  820. literal_struct!(
  821. tokens,
  822. TauriConfig,
  823. windows,
  824. cli,
  825. bundle,
  826. updater,
  827. security,
  828. system_tray
  829. );
  830. }
  831. }
  832. impl ToTokens for PluginConfig {
  833. fn to_tokens(&self, tokens: &mut TokenStream) {
  834. let config = map_lit(
  835. quote! { ::std::collections::HashMap },
  836. &self.0,
  837. str_lit,
  838. json_value_lit,
  839. );
  840. tokens.append_all(quote! { ::tauri::utils::config::PluginConfig(#config) })
  841. }
  842. }
  843. impl ToTokens for PackageConfig {
  844. fn to_tokens(&self, tokens: &mut TokenStream) {
  845. let product_name = opt_str_lit(self.product_name.as_ref());
  846. let version = opt_str_lit(self.version.as_ref());
  847. literal_struct!(tokens, PackageConfig, product_name, version);
  848. }
  849. }
  850. impl ToTokens for Config {
  851. fn to_tokens(&self, tokens: &mut TokenStream) {
  852. let package = &self.package;
  853. let tauri = &self.tauri;
  854. let build = &self.build;
  855. let plugins = &self.plugins;
  856. literal_struct!(tokens, Config, package, tauri, build, plugins);
  857. }
  858. }
  859. }
  860. #[cfg(test)]
  861. mod test {
  862. use super::*;
  863. // TODO: create a test that compares a config to a json config
  864. #[test]
  865. // test all of the default functions
  866. fn test_defaults() {
  867. // get default tauri config
  868. let t_config = TauriConfig::default();
  869. // get default build config
  870. let b_config = BuildConfig::default();
  871. // get default dev path
  872. let d_path = default_dev_path();
  873. // get default window
  874. let d_windows = default_window_config();
  875. // get default title
  876. let d_title = default_title();
  877. // get default bundle
  878. let d_bundle = BundleConfig::default();
  879. // get default updater
  880. let d_updater = UpdaterConfig::default();
  881. // create a tauri config.
  882. let tauri = TauriConfig {
  883. windows: vec![WindowConfig {
  884. label: "main".to_string(),
  885. url: WindowUrl::default(),
  886. file_drop_enabled: true,
  887. center: false,
  888. x: None,
  889. y: None,
  890. width: 800f64,
  891. height: 600f64,
  892. min_width: None,
  893. min_height: None,
  894. max_width: None,
  895. max_height: None,
  896. resizable: true,
  897. title: String::from("Tauri App"),
  898. fullscreen: false,
  899. focus: false,
  900. transparent: false,
  901. maximized: false,
  902. visible: true,
  903. decorations: true,
  904. always_on_top: false,
  905. skip_taskbar: false,
  906. }],
  907. bundle: BundleConfig {
  908. identifier: String::from(""),
  909. icon: Vec::new(),
  910. },
  911. cli: None,
  912. updater: UpdaterConfig {
  913. active: false,
  914. dialog: true,
  915. pubkey: None,
  916. endpoints: None,
  917. },
  918. security: SecurityConfig { csp: None },
  919. system_tray: None,
  920. };
  921. // create a build config
  922. let build = BuildConfig {
  923. dev_path: AppUrl::Url(WindowUrl::External(
  924. Url::parse("http://localhost:8080").unwrap(),
  925. )),
  926. dist_dir: AppUrl::Url(WindowUrl::App("../dist".into())),
  927. with_global_tauri: false,
  928. };
  929. // test the configs
  930. assert_eq!(t_config, tauri);
  931. assert_eq!(b_config, build);
  932. assert_eq!(d_bundle, tauri.bundle);
  933. assert_eq!(d_updater, tauri.updater);
  934. assert_eq!(
  935. d_path,
  936. AppUrl::Url(WindowUrl::External(
  937. Url::parse("http://localhost:8080").unwrap()
  938. ))
  939. );
  940. assert_eq!(d_title, tauri.windows[0].title);
  941. assert_eq!(d_windows, tauri.windows);
  942. }
  943. }