config.rs 30 KB

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