config_definition.rs 19 KB

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