config.rs 31 KB

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