From ddd6b6d2151cca92cbb1cd0729ee37e485ec5653 Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Thu, 1 Aug 2024 00:04:23 +0800 Subject: [PATCH 1/9] the basics --- Cargo.lock | 6 - Cargo.toml | 29 +++- examples/app/src-tauri/Cargo.toml | 3 +- examples/app/src-tauri/src/main.rs | 57 ++++---- examples/app/src/bindings.ts | 12 +- examples/custom-plugin/plugin/Cargo.toml | 2 +- examples/custom-plugin/plugin/src/lib.rs | 33 ++--- macros/src/collect_commands.rs | 44 ------ macros/src/lib.rs | 7 - src/builder.rs | 166 +++++++++++++++++++++++ src/event.rs | 26 +--- src/internal.rs | 51 +++++++ src/lib.rs | 21 ++- src/macros.rs | 60 ++++++++ 14 files changed, 361 insertions(+), 156 deletions(-) delete mode 100644 macros/src/collect_commands.rs create mode 100644 src/builder.rs create mode 100644 src/internal.rs create mode 100644 src/macros.rs diff --git a/Cargo.lock b/Cargo.lock index af5a1b2..60c131a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2780,7 +2780,6 @@ dependencies = [ [[package]] name = "specta" version = "2.0.0-rc.16" -source = "git+https://github.com/oscartbeaumont/specta.git?rev=cfa98fa10484e55923497f3cc21edf7418667c76#cfa98fa10484e55923497f3cc21edf7418667c76" dependencies = [ "paste", "specta-macros", @@ -2790,7 +2789,6 @@ dependencies = [ [[package]] name = "specta-macros" version = "2.0.0-rc.16" -source = "git+https://github.com/oscartbeaumont/specta.git?rev=cfa98fa10484e55923497f3cc21edf7418667c76#cfa98fa10484e55923497f3cc21edf7418667c76" dependencies = [ "Inflector", "proc-macro2", @@ -2801,7 +2799,6 @@ dependencies = [ [[package]] name = "specta-serde" version = "0.0.3" -source = "git+https://github.com/oscartbeaumont/specta.git?rev=cfa98fa10484e55923497f3cc21edf7418667c76#cfa98fa10484e55923497f3cc21edf7418667c76" dependencies = [ "specta", "thiserror", @@ -2810,7 +2807,6 @@ dependencies = [ [[package]] name = "specta-typescript" version = "0.0.3" -source = "git+https://github.com/oscartbeaumont/specta.git?rev=cfa98fa10484e55923497f3cc21edf7418667c76#cfa98fa10484e55923497f3cc21edf7418667c76" dependencies = [ "specta", "specta-serde", @@ -2820,7 +2816,6 @@ dependencies = [ [[package]] name = "specta-util" version = "0.0.3" -source = "git+https://github.com/oscartbeaumont/specta.git?rev=cfa98fa10484e55923497f3cc21edf7418667c76#cfa98fa10484e55923497f3cc21edf7418667c76" dependencies = [ "serde", "specta", @@ -3218,7 +3213,6 @@ dependencies = [ "serde_json", "specta", "specta-typescript", - "specta-util", "tauri", "tauri-build", "tauri-plugin-os", diff --git a/Cargo.toml b/Cargo.toml index a0384db..0104356 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ rustdoc-args = ["--cfg", "docsrs"] [features] default = [] +derive = ["dep:tauri-specta-macros"] javascript = ["dep:specta-typescript"] typescript = ["dep:specta-typescript"] @@ -30,7 +31,7 @@ UNSTABLE_channels = [] specta = { workspace = true, features = ["function"] } specta-typescript = { workspace = true, optional = true } specta-util = { workspace = true } -tauri-specta-macros = { version = "=2.0.0-rc.5", path = "./macros" } +tauri-specta-macros = { version = "=2.0.0-rc.5", optional = true, path = "./macros" } serde = "1" serde_json = "1" thiserror = "1" @@ -48,6 +49,18 @@ members = [ "macros", ] +[workspace.lints.rust] +unsafe_code = { level = "forbid", priority = -1 } +missing_docs = { level = "warn", priority = -1 } + +[workspace.lints.clippy] +all = { level = "warn", priority = -1 } +cargo = { level = "warn", priority = -1 } +unwrap_used = { level = "warn", priority = -1 } +panic = { level = "warn", priority = -1 } +todo = { level = "warn", priority = -1 } +panic_in_result_fn = { level = "warn", priority = -1 } + [workspace.dependencies] tauri = { version = "=2.0.0-beta.25" } specta = { version = "=2.0.0-rc.16" } @@ -55,9 +68,13 @@ specta-util = { version = "0.0.3" } specta-typescript = { version = "0.0.3" } [patch.crates-io] -# tauri = { git = "https://github.com/oscartbeaumont/tauri.git", branch = "fix-channel-specta-remote-impl" } -# tauri-build = { git = "https://github.com/oscartbeaumont/tauri.git", branch = "fix-channel-specta-remote-impl" } +# tauri = { git = "https://github.com/oscartbeaumont/tauri.git", rev = "ddc64b706a7f2db271d40e9b216187b1aa153efa" } +# tauri-build = { git = "https://github.com/oscartbeaumont/tauri.git", rev = "ddc64b706a7f2db271d40e9b216187b1aa153efa" } + +# specta = { git = "https://github.com/oscartbeaumont/specta.git", rev = "cfa98fa10484e55923497f3cc21edf7418667c76" } +# specta-util = { git = "https://github.com/oscartbeaumont/specta.git", rev = "cfa98fa10484e55923497f3cc21edf7418667c76" } +# specta-typescript = { git = "https://github.com/oscartbeaumont/specta.git", rev = "cfa98fa10484e55923497f3cc21edf7418667c76" } -specta = { git = "https://github.com/oscartbeaumont/specta.git", rev = "cfa98fa10484e55923497f3cc21edf7418667c76" } -specta-util = { git = "https://github.com/oscartbeaumont/specta.git", rev = "cfa98fa10484e55923497f3cc21edf7418667c76" } -specta-typescript = { git = "https://github.com/oscartbeaumont/specta.git", rev = "cfa98fa10484e55923497f3cc21edf7418667c76" } +specta = { path = "../specta/specta" } +specta-util = { path = "../specta/specta-util" } +specta-typescript = { path = "../specta/specta-typescript" } diff --git a/examples/app/src-tauri/Cargo.toml b/examples/app/src-tauri/Cargo.toml index 8a2b2e2..bcf94e7 100644 --- a/examples/app/src-tauri/Cargo.toml +++ b/examples/app/src-tauri/Cargo.toml @@ -17,8 +17,7 @@ serde_json = "1.0" specta = { workspace = true } serde = { version = "1.0", features = ["derive"] } tauri = { workspace = true, features = [] } -tauri-specta = { path = "../../../", features = ["typescript", "javascript"] } -specta-util = { workspace = true } +tauri-specta = { path = "../../../", features = ["derive", "typescript", "javascript"] } specta-typescript = { workspace = true } tauri-plugin-os = "^2.0.0-beta.3" thiserror = "1" diff --git a/examples/app/src-tauri/src/main.rs b/examples/app/src-tauri/src/main.rs index 39e60c5..93ed49b 100644 --- a/examples/app/src-tauri/src/main.rs +++ b/examples/app/src-tauri/src/main.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use specta::Type; -use specta_util::TypeCollection; +use specta_typescript::Typescript; use tauri_specta::*; use thiserror::Error; @@ -116,38 +116,33 @@ pub struct Testing { } fn main() { - let (invoke_handler, register_events) = { - let builder = ts::builder() - .commands(tauri_specta::collect_commands![ - hello_world, - goodbye_world, - has_error, - nested::some_struct, - generic::, - deprecated, - typesafe_errors_using_thiserror, - typesafe_errors_using_thiserror_with_value - ]) - .events(tauri_specta::collect_events![crate::DemoEvent, EmptyEvent]) - .types(TypeCollection::default().register::()) - .config( - specta_typescript::Typescript::default() - .formatter(specta_typescript::formatter::prettier), - ) - .types(TypeCollection::default().register::()) - .statics(StaticCollection::default().register("universalConstant", 42)) - .header("/* These are my Tauri Specta Bindings! */"); - - #[cfg(debug_assertions)] - let builder = builder.path("../src/bindings.ts"); - - builder.build().unwrap() - }; + let mut builder = Builder2::::new() + .commands(tauri_specta::collect_commands![ + hello_world, + goodbye_world, + has_error, + // nested::some_struct, + // generic::, + deprecated, + typesafe_errors_using_thiserror, + typesafe_errors_using_thiserror_with_value + ]) + .events(tauri_specta::collect_events![crate::DemoEvent, EmptyEvent]) + .ty::() + .constant("universalConstant", 42); + + #[cfg(debug_assertions)] + builder.export_ts( + Typescript::default() + .formatter(specta_typescript::formatter::prettier) + .header("/* These are my Tauri Specta Bindings! */") + .path("../src/bindings.ts"), + ); tauri::Builder::default() - .invoke_handler(invoke_handler) - .setup(|app| { - register_events(app); + .invoke_handler(builder.invoke_handler()) + .setup(move |app| { + builder.mount_events(app); let handle = app.handle(); diff --git a/examples/app/src/bindings.ts b/examples/app/src/bindings.ts index c654066..9fe4f7f 100644 --- a/examples/app/src/bindings.ts +++ b/examples/app/src/bindings.ts @@ -23,12 +23,6 @@ try { else return { status: "error", error: e as any }; } }, -async someStruct() : Promise { -return await TAURI_INVOKE("some_struct"); -}, -async generic() : Promise { -await TAURI_INVOKE("generic"); -}, /** * @deprecated This is a deprecated function */ @@ -65,17 +59,13 @@ emptyEvent: "empty-event" /** user-defined statics **/ - export const universalConstant = 42 as const; + /** user-defined types **/ export type Custom = string -export type DemoEvent = string -export type EmptyEvent = null export type MyError = { type: "IoError" } | { type: "AnotherError"; data: string } export type MyError2 = { type: "IoError"; data: string } -export type MyStruct = { some_field: string } -export type Testing = { a: string } /** tauri-specta globals **/ diff --git a/examples/custom-plugin/plugin/Cargo.toml b/examples/custom-plugin/plugin/Cargo.toml index 87b610e..ece263b 100644 --- a/examples/custom-plugin/plugin/Cargo.toml +++ b/examples/custom-plugin/plugin/Cargo.toml @@ -12,7 +12,7 @@ rand = "0.8.5" serde = "1" specta = { workspace = true } tauri = { workspace = true } -tauri-specta = { path = "../../../", features = ["typescript"] } +tauri-specta = { path = "../../../", features = ["derive", "typescript"] } [dev-dependencies] specta-typescript = { workspace = true } \ No newline at end of file diff --git a/examples/custom-plugin/plugin/src/lib.rs b/examples/custom-plugin/plugin/src/lib.rs index 3fbf7c9..560bf35 100644 --- a/examples/custom-plugin/plugin/src/lib.rs +++ b/examples/custom-plugin/plugin/src/lib.rs @@ -14,26 +14,22 @@ fn add_numbers(a: i32, b: i32) -> i32 { #[derive(Clone, serde::Serialize, specta::Type, Event)] struct RandomNumber(i32); -// We recommend re-using the builder via a macro rather than function as the builder's -// generics can be tricky to deal with -macro_rules! specta_builder { - () => { - ts::builder() - .commands(collect_commands![add_numbers]) - .events(collect_events![RandomNumber]) - }; -} - const PLUGIN_NAME: &str = "specta-example"; +fn builder() -> tauri_specta::Builder2 { + tauri_specta::Builder2::new() + .plugin_name(PLUGIN_NAME) + .commands(collect_commands![add_numbers]) + .events(collect_events![RandomNumber]) +} + pub fn init() -> TauriPlugin { - let (invoke_handler, register_events) = - specta_builder!().build_plugin_utils(PLUGIN_NAME).unwrap(); + let builder = builder(); Builder::new(PLUGIN_NAME) - .invoke_handler(invoke_handler) + .invoke_handler(builder.invoke_handler()) .setup(move |app, _| { - register_events(app); + builder.mount_events(app); let app = app.clone(); std::thread::spawn(move || loop { @@ -52,13 +48,12 @@ mod test { #[test] fn export_types() { - specta_builder!() - .path("./bindings.ts") - .config( + builder() + .export_ts( specta_typescript::Typescript::default() - .formatter(specta_typescript::formatter::prettier), + .formatter(specta_typescript::formatter::prettier) + .path("./bindings.ts"), ) - .export_for_plugin(PLUGIN_NAME) .expect("failed to export specta types"); } } diff --git a/macros/src/collect_commands.rs b/macros/src/collect_commands.rs deleted file mode 100644 index 9f4ce9c..0000000 --- a/macros/src/collect_commands.rs +++ /dev/null @@ -1,44 +0,0 @@ -use quote::quote; -use syn::{ - parse::{Parse, ParseStream}, - parse_macro_input, - punctuated::Punctuated, - Path, Token, -}; - -pub struct Input { - paths: Punctuated, -} - -impl Parse for Input { - fn parse(input: ParseStream) -> syn::Result { - Ok(Self { - paths: Punctuated::parse_terminated(input)?, - }) - } -} - -pub fn proc_macro(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let Input { paths } = parse_macro_input!(input as Input); - - let tauri_paths = paths.iter().map(|p| { - let Path { - leading_colon, - segments, - } = p; - - let segments = segments.iter().map(|s| &s.ident); - - quote!(#leading_colon #(#segments)::*) - }); - - let body = quote! {( - ::specta::function::collect_functions![#paths], - ::tauri::generate_handler![#(#tauri_paths),*], - )}; - - quote! {{ - #body - }} - .into() -} diff --git a/macros/src/lib.rs b/macros/src/lib.rs index e59e482..d7aacc0 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -1,5 +1,3 @@ -mod collect_commands; - use heck::ToKebabCase; use quote::quote; use syn::{parse_macro_input, DeriveInput}; @@ -19,8 +17,3 @@ pub fn derive_type(input: proc_macro::TokenStream) -> proc_macro::TokenStream { } .into() } - -#[proc_macro] -pub fn collect_commands(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - collect_commands::proc_macro(input) -} diff --git a/src/builder.rs b/src/builder.rs new file mode 100644 index 0000000..42426b5 --- /dev/null +++ b/src/builder.rs @@ -0,0 +1,166 @@ +use std::{ + borrow::Cow, + collections::HashMap, + fs::{self, File}, + io::Write, +}; + +use serde::Serialize; +use specta::{datatype::DataType, NamedType, Type, TypeMap}; +use specta_typescript::Typescript; +use tauri::{ipc::Invoke, App, Runtime}; + +use crate::{ + internal::{Commands, Events}, + EventRegistry, PluginName, +}; + +pub struct Builder { + plugin_name: Option<&'static str>, + commands: Commands, + events: Events, + types: TypeMap, + constants: HashMap, (DataType, serde_json::Value)>, +} + +impl Default for Builder { + fn default() -> Self { + Self { + plugin_name: None, + commands: Commands::default(), + events: Events::default(), + types: TypeMap::default(), + constants: HashMap::default(), + } + } +} + +impl Builder { + /// Construct a new Tauri Specta builder. + pub fn new() -> Self { + Self::default() + } + + /// Set the name of the current plugin name. + /// + /// This is used to ensure the generated bindings correctly reference the plugin. + pub fn plugin_name(self, plugin_name: &'static str) -> Self { + Self { + plugin_name: Some(plugin_name), + ..self + } + } + + /// Register commands with the builder. + /// + /// WARNING: This method will overwrite any previously registered commands. + pub fn commands(self, commands: Commands) -> Self { + Self { commands, ..self } + } + + /// Register events with the builder. + /// + /// WARNING: This method will overwrite any previously registered events. + pub fn events(self, events: Events) -> Self { + Self { events, ..self } + } + /// Export a new type with the frontend. + /// + /// This is useful if you want to export types that do not appear in any events or commands. + pub fn ty(mut self) -> Self { + let dt = T::definition_named_data_type(&mut self.types); + self.types.insert(T::sid(), dt); + self + } + + /// Export a constant value to the frontend. + /// + /// This is useful to share application-wide constants or expose data which is generated by Rust. + #[track_caller] + pub fn constant(mut self, k: impl Into>, v: T) -> Self { + let v = serde_json::to_value(v).expect("Tauri Specta failed to serialize constant"); + self.constants + .insert(k.into(), (T::reference(&mut self.types, &[]).inner, v)); + self + } + + // TODO: Maybe method to merge in a `TypeCollection` + + // TODO: Should we put a `.build` command here to ensure it's immutable from now on? + + /// The Tauri invoke handler to trigger commands registered with the builder. + pub fn invoke_handler(&self) -> impl Fn(Invoke) -> bool + Send + Sync + 'static { + let commands = self.commands.0.clone(); + move |invoke| commands(invoke) + } + + /// Mount all of the events in the builder onto a Tauri app. + pub fn mount_events(&self, app: &mut App) { + let registry = EventRegistry::get_or_manage(app); + registry.register_collection(self.events.0.clone(), None); + } + + // TODO: Restructure to use a `LanguageExt` trait system + + // TODO: Make this not-mutable + pub fn export_ts( + &mut self, + language: Typescript, + ) -> Result<(), specta_typescript::ExportError> { + if let Some(path) = &language.path { + if let Some(export_dir) = path.parent() { + fs::create_dir_all(export_dir)?; + } + + let mut file = File::create(&path)?; + + // TODO: Maybe do this in the `commands` to make sure this method can take `&self` + let commands = (self.commands.1)(&mut self.types); + + // TODO: This is required for channels to work correctly. + // This should be unfeature gated once the upstream fix is merged: https://github.com/tauri-apps/tauri/pull/10435 + // #[cfg(feature = "UNSTABLE_channels")] + // self.types + // .remove( as specta::NamedType>::sid()); + + let dependant_types = self + .types + .iter() + .map({ + let language = &language; + |(_sid, ndt)| { + specta_typescript::export_named_datatype(language, ndt, &self.types) + } + }) + .collect::, _>>() + .map(|v| v.join("\n"))?; + + let cfg = crate::ExportConfig { + plugin_name: self.plugin_name.map(PluginName), + path: language.path.clone(), + header: language.header.clone(), + inner: language.clone(), + }; + + let rendered = crate::js_ts::render_all_parts::( + &commands, + &self.events.1, + &self.types, + &Default::default(), // TODO: fix statics + &cfg, + &dependant_types, + crate::ts::GLOBALS, + )?; + + write!(file, "{}", format!("{}\n{rendered}", cfg.inner.header))?; + + cfg.inner.run_format(path.clone()).ok(); + } + + Ok(()) + } + + pub fn export_js_doc(&self, language: Typescript) { + // TODO + } +} diff --git a/src/event.rs b/src/event.rs index 462c752..b48bfcb 100644 --- a/src/event.rs +++ b/src/event.rs @@ -22,7 +22,7 @@ impl EventRegistryMeta { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct EventCollection(pub(crate) BTreeSet, BTreeSet<&'static str>); impl EventCollection { @@ -37,6 +37,7 @@ impl EventCollection { } } +// TODO: Should this be pub #[derive(Default)] pub(crate) struct EventRegistry(pub(crate) RwLock>); @@ -193,26 +194,3 @@ pub struct EventDataType { #[doc(hidden)] pub type CollectEventsTuple = (EventCollection, Vec, specta::TypeMap); - -#[macro_export] -macro_rules! collect_events { - ($($event:path),* $(,)?) => {{ - let mut collection: $crate::EventCollection = ::core::default::Default::default(); - - $(collection.register::<$event>();)* - - let mut type_map = Default::default(); - - let event_data_types = [$( - $crate::EventDataType { - name: <$event as $crate::Event>::NAME, - typ: <$event as ::specta::Type>::reference(&mut type_map, &[]).inner - } - ),*] - .into_iter() - .collect::>(); - - let result: $crate::CollectEventsTuple = (collection, event_data_types, type_map); - result - }}; -} diff --git a/src/internal.rs b/src/internal.rs new file mode 100644 index 0000000..7c646b7 --- /dev/null +++ b/src/internal.rs @@ -0,0 +1,51 @@ +//! Internal logic for Tauri Specta. +//! Nothing in this module has to conform to semver so it should not be used outside of this crate. +//! It has to be public so macro's can access it. + +use std::sync::Arc; + +use specta::{datatype, TypeMap}; +use tauri::{ipc::Invoke, Runtime}; + +use crate::{EventCollection, EventDataType}; + +type SpectaCollectTypes = fn(&mut TypeMap) -> Vec; + +/// A wrapper around the output of the `collect_commands` macro. +/// This acts to seal the implementation details of the macro. +pub struct Commands( + // Bounds copied from `tauri::Builder::invoke_handler` + pub(crate) Arc) -> bool + Send + Sync + 'static>, + pub(crate) SpectaCollectTypes, +); + +impl Default for Commands { + fn default() -> Self { + Self( + Arc::new(tauri::generate_handler![]), + ::specta::function::collect_functions![], + ) + } +} + +/// A wrapper around the output of the `collect_commands` macro. +/// This acts to seal the implementation details of the macro. +#[derive(Default)] +pub struct Events( + pub(crate) EventCollection, + pub(crate) Vec, + pub(crate) TypeMap, +); + +/// called by `collect_commands` to construct `Commands` +pub fn command(f: F, types: SpectaCollectTypes) -> Commands +where + F: Fn(Invoke) -> bool + Send + Sync + 'static, +{ + Commands(Arc::new(f), types) +} + +/// called by `collect_events` to construct `Events` +pub fn events(a: EventCollection, b: Vec, c: TypeMap) -> Events { + Events(a, b, c) +} diff --git a/src/lib.rs b/src/lib.rs index dbc278f..9739123 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -107,11 +107,12 @@ //! await commands.greet("Brendan"); //! ``` //! -#![forbid(unsafe_code)] -#![warn(clippy::all, clippy::unwrap_used, clippy::panic - // , missing_docs -)] #![cfg_attr(docsrs, feature(doc_cfg))] +#![doc( + // TODO: Tauri Specta logo + html_logo_url = "https://github.com/oscartbeaumont/specta/raw/main/.github/logo-128.png", + html_favicon_url = "https://github.com/oscartbeaumont/specta/raw/main/.github/logo-128.png" +)] use std::{ borrow::{Borrow, Cow}, @@ -126,8 +127,18 @@ use specta::{datatype, datatype::NamedDataType, SpectaID, TypeMap}; use specta_util::TypeCollection; use tauri::{ipc::Invoke, Manager, Runtime}; + +#[cfg(feature = "derive")] +#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] pub use tauri_specta_macros::Event; +mod builder; +#[doc(hidden)] +pub mod internal; +mod macros; + +pub use builder::Builder as Builder2; // TODO: Rename + /// The exporter for [Javascript](https://www.javascript.com). #[cfg(feature = "javascript")] #[cfg_attr(docsrs, doc(cfg(feature = "javascript")))] @@ -153,7 +164,7 @@ const DEFAULT_COLLECT_FN: CollectFunctionsResult = |_| vec![]; pub type CollectCommandsTuple = (CollectFunctionsResult, TInvokeHandler); -pub use tauri_specta_macros::collect_commands; +// pub use tauri_specta_macros::collect_commands; /// A set of functions that produce language-specific code pub trait ExportLanguage: 'static { diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..eeff2b7 --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,60 @@ +// TODO: Hide it's implementation details from the generated rustdoc. +#[macro_export] +macro_rules! collect_commands { + () => { + $crate::internal::command(::tauri::generate_handler![], ::specta::function::collect_functions![]) + }; + ($i:ident) => { + $crate::internal::command(::tauri::generate_handler![$i], ::specta::function::collect_functions![$i]) + }; + ($i:ident, $($rest:tt)*) => { + $crate::internal::command($crate::collect_commands!(@internal; $i; $($rest)*), ::specta::function::collect_functions![$i, $($rest)*]) + }; + ($i:ident::<$g:path>) => { + $crate::internal::command(::tauri::generate_handler![$i], ::specta::function::collect_functions![$i<$g>]) + }; + ($i:ident::<$g:path>, $($rest:tt)*) => { + $crate::internal::command($crate::collect_commands!(@internal; $i; $($rest)*), ::specta::function::collect_functions![$i<$g>, $($rest)*]) + }; + // + (@internal; $($b:path),*;) => { + ::tauri::generate_handler![$($b),*] + }; + (@internal; $($b:path),*; $i:ident) => { + ::tauri::generate_handler![$($b),*, $i] + }; + (@internal; $($b:path),*; $i:ident, $($rest:tt)*) => { + $crate::collect_commands!(@internal; $($b),*, $i; $($rest)*) + }; + (@internal; $($b:path),*; $i:ident::<$g:path>) => { + ::tauri::generate_handler![$($b),*, $i] + }; + (@internal; $($b:path),*; $i:ident::<$g:ident>, $($rest:tt)*) => { + $crate::collect_commands!(@internal; $($b),*, $i; $($rest)*) + }; +} + +// TODO: Hide it's implementation details from the generated rustdoc. +#[macro_export] +macro_rules! collect_events { + ($($event:path),* $(,)?) => {{ + // TODO: Cleanup the internals of this + + let mut collection: $crate::EventCollection = ::core::default::Default::default(); + + $(collection.register::<$event>();)* + + let mut type_map = Default::default(); + + let event_data_types = [$( + $crate::EventDataType { + name: <$event as $crate::Event>::NAME, + typ: <$event as ::specta::Type>::reference(&mut type_map, &[]).inner + } + ),*] + .into_iter() + .collect::>(); + + $crate::internal::events(collection, event_data_types, type_map) + }}; +} From 56362a5d173b3a56912a9a66b4ed2e98e306f247 Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Thu, 1 Aug 2024 10:52:07 +0800 Subject: [PATCH 2/9] drop some more legacy stuff --- Cargo.toml | 3 + examples/app/src-tauri/src/main.rs | 16 +- src/builder.rs | 2 +- src/js.rs | 288 +++++++++++----------- src/js_ts.rs | 4 +- src/lib.rs | 375 +---------------------------- src/ts.rs | 12 +- tests/tauri_command.rs | 80 ++++++ 8 files changed, 247 insertions(+), 533 deletions(-) create mode 100644 tests/tauri_command.rs diff --git a/Cargo.toml b/Cargo.toml index 0104356..beeeabf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,9 @@ typescript = ["dep:specta-typescript"] # TODO: https://github.com/tauri-apps/tauri/pull/10435 UNSTABLE_channels = [] +[lints] +workspace = true + [dependencies] # Public specta = { workspace = true, features = ["function"] } diff --git a/examples/app/src-tauri/src/main.rs b/examples/app/src-tauri/src/main.rs index 93ed49b..072f07f 100644 --- a/examples/app/src-tauri/src/main.rs +++ b/examples/app/src-tauri/src/main.rs @@ -116,7 +116,7 @@ pub struct Testing { } fn main() { - let mut builder = Builder2::::new() + let mut builder = Builder::::new() .commands(tauri_specta::collect_commands![ hello_world, goodbye_world, @@ -132,12 +132,14 @@ fn main() { .constant("universalConstant", 42); #[cfg(debug_assertions)] - builder.export_ts( - Typescript::default() - .formatter(specta_typescript::formatter::prettier) - .header("/* These are my Tauri Specta Bindings! */") - .path("../src/bindings.ts"), - ); + builder + .export_ts( + Typescript::default() + .formatter(specta_typescript::formatter::prettier) + .header("/* These are my Tauri Specta Bindings! */") + .path("../src/bindings.ts"), + ) + .expect("Failed to export typescript bindings"); tauri::Builder::default() .invoke_handler(builder.invoke_handler()) diff --git a/src/builder.rs b/src/builder.rs index 42426b5..6e97cfa 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -142,7 +142,7 @@ impl Builder { inner: language.clone(), }; - let rendered = crate::js_ts::render_all_parts::( + let rendered = crate::js_ts::render_all_parts::( &commands, &self.events.1, &self.types, diff --git a/src/js.rs b/src/js.rs index 7a971c5..9c67140 100644 --- a/src/js.rs +++ b/src/js.rs @@ -1,144 +1,144 @@ -use crate::*; -use heck::ToLowerCamelCase; -use indoc::formatdoc; -use specta::{datatype, datatype::FunctionResultVariant}; -use specta_typescript as ts; -use specta_typescript::js_doc; -use tauri::Runtime; - -/// Implements [`ExportLanguage`] for JS exporting -pub struct Language; - -pub fn builder() -> Builder, NoEvents> { - Builder::default() -} - -pub const GLOBALS: &str = include_str!("./globals.js"); - -type Config = specta_typescript::Typescript; - -pub type ExportConfig = crate::ExportConfig; - -impl ExportLanguage for Language { - type Config = Config; - type Error = ts::ExportError; - - fn run_format(path: PathBuf, cfg: &ExportConfig) { - cfg.inner.run_format(path).ok(); - } - - /// Renders a collection of [`FunctionDataType`] into a JavaScript string. - fn render_commands( - commands: &[datatype::Function], - type_map: &TypeMap, - cfg: &ExportConfig, - ) -> Result { - let commands = commands - .iter() - .map(|function| { - let jsdoc = { - let ret_type = js_ts::handle_result(function, type_map, cfg)?; - - let mut builder = js_doc::Builder::default(); - - if let Some(d) = function.deprecated() { - builder.push_deprecated(d); - } - - if !function.docs().is_empty() { - builder.extend(function.docs().split("\n")); - } - - builder.extend(function.args().flat_map(|(name, typ)| { - ts::datatype( - &cfg.inner, - &FunctionResultVariant::Value(typ.clone()), - type_map, - ) - .map(|typ| { - let name = name.to_lower_camel_case(); - - format!("@param {{ {typ} }} {name}") - }) - })); - builder.push(&format!("@returns {{ Promise<{ret_type}> }}")); - - builder.build() - }; - - Ok(js_ts::function( - &jsdoc, - &function.name().to_lower_camel_case(), - // TODO: Don't `collect` the whole thing - &js_ts::arg_names(&function.args().cloned().collect::>()), - None, - &js_ts::command_body(cfg, function, false), - )) - }) - .collect::, Self::Error>>()? - .join(",\n"); - - Ok(formatdoc! { - r#" - export const commands = {{ - {commands} - }}"# - }) - } - - fn render_events( - events: &[EventDataType], - type_map: &TypeMap, - cfg: &ExportConfig, - ) -> Result { - if events.is_empty() { - return Ok(Default::default()); - } - - let (events_types, events_map) = js_ts::events_data(events, cfg, type_map)?; - - let events = { - let mut builder = js_doc::Builder::default(); - - builder.push("@type {typeof __makeEvents__<{"); - builder.extend(events_types); - builder.push("}>}"); - - builder.build() - }; - - Ok(formatdoc! { - r#" - {events} - const __typedMakeEvents__ = __makeEvents__; - - export const events = __typedMakeEvents__({{ - {events_map} - }})"# - }) - } - - fn render( - commands: &[datatype::Function], - events: &[EventDataType], - type_map: &TypeMap, - statics: &StaticCollection, - cfg: &ExportConfig, - ) -> Result { - let dependant_types = type_map - .iter() - .map(|(_sid, ndt)| js_doc::typedef_named_datatype(&cfg.inner, ndt, type_map)) - .collect::, _>>() - .map(|v| v.join("\n"))?; - - js_ts::render_all_parts::( - commands, - events, - type_map, - statics, - cfg, - &dependant_types, - GLOBALS, - ) - } -} +// use crate::*; +// use heck::ToLowerCamelCase; +// use indoc::formatdoc; +// use specta::{datatype, datatype::FunctionResultVariant}; +// use specta_typescript as ts; +// use specta_typescript::js_doc; +// use tauri::Runtime; + +// /// Implements [`ExportLanguage`] for JS exporting +// pub struct Language; + +// pub fn builder() -> Builder, NoEvents> { +// Builder::default() +// } + +// pub const GLOBALS: &str = include_str!("./globals.js"); + +// type Config = specta_typescript::Typescript; + +// pub type ExportConfig = crate::ExportConfig; + +// impl ExportLanguage for Language { +// type Config = Config; +// type Error = ts::ExportError; + +// fn run_format(path: PathBuf, cfg: &ExportConfig) { +// cfg.inner.run_format(path).ok(); +// } + +// /// Renders a collection of [`FunctionDataType`] into a JavaScript string. +// fn render_commands( +// commands: &[datatype::Function], +// type_map: &TypeMap, +// cfg: &ExportConfig, +// ) -> Result { +// let commands = commands +// .iter() +// .map(|function| { +// let jsdoc = { +// let ret_type = js_ts::handle_result(function, type_map, cfg)?; + +// let mut builder = js_doc::Builder::default(); + +// if let Some(d) = function.deprecated() { +// builder.push_deprecated(d); +// } + +// if !function.docs().is_empty() { +// builder.extend(function.docs().split("\n")); +// } + +// builder.extend(function.args().flat_map(|(name, typ)| { +// ts::datatype( +// &cfg.inner, +// &FunctionResultVariant::Value(typ.clone()), +// type_map, +// ) +// .map(|typ| { +// let name = name.to_lower_camel_case(); + +// format!("@param {{ {typ} }} {name}") +// }) +// })); +// builder.push(&format!("@returns {{ Promise<{ret_type}> }}")); + +// builder.build() +// }; + +// Ok(js_ts::function( +// &jsdoc, +// &function.name().to_lower_camel_case(), +// // TODO: Don't `collect` the whole thing +// &js_ts::arg_names(&function.args().cloned().collect::>()), +// None, +// &js_ts::command_body(cfg, function, false), +// )) +// }) +// .collect::, Self::Error>>()? +// .join(",\n"); + +// Ok(formatdoc! { +// r#" +// export const commands = {{ +// {commands} +// }}"# +// }) +// } + +// fn render_events( +// events: &[EventDataType], +// type_map: &TypeMap, +// cfg: &ExportConfig, +// ) -> Result { +// if events.is_empty() { +// return Ok(Default::default()); +// } + +// let (events_types, events_map) = js_ts::events_data(events, cfg, type_map)?; + +// let events = { +// let mut builder = js_doc::Builder::default(); + +// builder.push("@type {typeof __makeEvents__<{"); +// builder.extend(events_types); +// builder.push("}>}"); + +// builder.build() +// }; + +// Ok(formatdoc! { +// r#" +// {events} +// const __typedMakeEvents__ = __makeEvents__; + +// export const events = __typedMakeEvents__({{ +// {events_map} +// }})"# +// }) +// } + +// fn render( +// commands: &[datatype::Function], +// events: &[EventDataType], +// type_map: &TypeMap, +// statics: &StaticCollection, +// cfg: &ExportConfig, +// ) -> Result { +// let dependant_types = type_map +// .iter() +// .map(|(_sid, ndt)| js_doc::typedef_named_datatype(&cfg.inner, ndt, type_map)) +// .collect::, _>>() +// .map(|v| v.join("\n"))?; + +// js_ts::render_all_parts::( +// commands, +// events, +// type_map, +// statics, +// cfg, +// &dependant_types, +// GLOBALS, +// ) +// } +// } diff --git a/src/js_ts.rs b/src/js_ts.rs index 85d3f1d..b4d1b7f 100644 --- a/src/js_ts.rs +++ b/src/js_ts.rs @@ -7,8 +7,8 @@ use specta::{ datatype::{DataType, FunctionResultVariant}, TypeMap, }; -use specta_typescript as ts; use specta_typescript::ExportError; +use specta_typescript::{self as ts}; use crate::{EventDataType, ExportLanguage, ItemType, StaticCollection}; @@ -23,6 +23,8 @@ pub fn render_all_parts Vec; - -const DEFAULT_COLLECT_FN: CollectFunctionsResult = |_| vec![]; - -pub type CollectCommandsTuple = (CollectFunctionsResult, TInvokeHandler); - -// pub use tauri_specta_macros::collect_commands; - /// A set of functions that produce language-specific code pub trait ExportLanguage: 'static { - type Config: Default + Clone; + type Config: Default + Clone; // TODO: Remove type Error: fmt::Debug + error::Error + From; // TODO: Review if this `From` should be removed before stabilisation fn run_format(path: PathBuf, cfg: &ExportConfig); @@ -196,354 +179,6 @@ pub trait ExportLanguage: 'static { ) -> Result; } -pub trait CommandsTypeState: 'static { - type Runtime: tauri::Runtime; - type InvokeHandler: Fn(Invoke) -> bool + Send + Sync + 'static; - - fn split(self) -> CollectCommandsTuple; - - fn macro_data(&self) -> CollectFunctionsResult; -} - -fn dummy_invoke_handler(_: Invoke) -> bool { - false -} - -pub struct NoCommands(CollectFunctionsResult, PhantomData); - -impl CommandsTypeState for NoCommands -where - TRuntime: tauri::Runtime, -{ - type Runtime = TRuntime; - type InvokeHandler = fn(Invoke) -> bool; - - fn split(self) -> CollectCommandsTuple { - (DEFAULT_COLLECT_FN, dummy_invoke_handler) - } - - fn macro_data(&self) -> CollectFunctionsResult { - self.0 - } -} - -pub struct Commands( - CollectCommandsTuple, - PhantomData, -); - -impl CommandsTypeState for Commands -where - TRuntime: tauri::Runtime, - TInvokeHandler: Fn(Invoke) -> bool + Send + Sync + 'static, -{ - type Runtime = TRuntime; - type InvokeHandler = TInvokeHandler; - - fn split(self) -> CollectCommandsTuple { - self.0 - } - - fn macro_data(&self) -> CollectFunctionsResult { - self.0 .0 - } -} - -pub trait EventsTypeState: 'static { - fn get(self) -> CollectEventsTuple; -} - -pub struct NoEvents; - -impl EventsTypeState for NoEvents { - fn get(self) -> CollectEventsTuple { - Default::default() - } -} - -pub struct Events(CollectEventsTuple); - -impl EventsTypeState for Events { - fn get(self) -> CollectEventsTuple { - self.0 - } -} - -/// General exporter, takes a generic for the specific language that is being exported to. -pub struct Builder { - lang: PhantomData, - commands: TCommands, - events: TEvents, - config: ExportConfig, - types: TypeCollection, - statics: StaticCollection, -} - -impl Default for Builder, NoEvents> -where - TLang: ExportLanguage, -{ - fn default() -> Self { - Self { - lang: PhantomData, - commands: NoCommands(DEFAULT_COLLECT_FN, Default::default()), - events: NoEvents, - config: Default::default(), - types: TypeCollection::default(), - statics: StaticCollection::default(), - } - } -} - -impl Builder, TEvents> -where - TLang: ExportLanguage, - TRuntime: tauri::Runtime, -{ - pub fn commands) -> bool + Send + Sync + 'static>( - self, - commands: CollectCommandsTuple, - ) -> Builder, TEvents> { - Builder { - lang: self.lang, - commands: Commands(commands, Default::default()), - events: self.events, - config: self.config, - types: self.types, - statics: self.statics, - } - } -} - -impl Builder -where - TLang: ExportLanguage, -{ - pub fn events(self, events: CollectEventsTuple) -> Builder { - Builder { - lang: self.lang, - events: Events(events), - commands: self.commands, - config: self.config, - types: self.types, - statics: self.statics, - } - } -} - -impl Builder -where - TLang: ExportLanguage, -{ - /// Allows for exporting types that are not part of any of the commands or events. - /// - /// ```rs - /// use tauri_specta::ts; - /// use specta::{Type, TypeCollection}; - /// - /// #[derive(Type)] - /// pub struct Custom(String); - /// - /// ts::build() - /// .types({ - /// let mut collection = TypeCollection::default(); - /// collection.register::(); - /// collection - /// }); - /// ``` - pub fn types(mut self, types: impl Borrow) -> Self { - self.types.extend(types); - self - } - - /// Allows for exporting static along with your commands and events. - /// - /// ```rs - /// use tauri_specta::{ts, StaticCollection}; - /// - /// ts::build() - /// .statics(StaticCollection::default().register("universalConstant", 42)); - /// ``` - pub fn statics(mut self, statics: impl Borrow) -> Self { - self.statics.extend(statics); - self - } - - /// Allows for specifying a custom [`ExportConfiguration`](specta::ts::ExportConfiguration). - pub fn config(mut self, config: TLang::Config) -> Self { - self.config.inner = config; - self - } - - /// Allows for specifying a custom header to - pub fn header(mut self, header: &'static str) -> Self { - self.config.header = header.into(); - self - } - - pub fn path(mut self, path: impl AsRef) -> Self { - self.config.path = Some(path.as_ref().to_path_buf()); - self - } -} - -pub struct PluginUtils -where - TCommands: CommandsTypeState, - TManager: Manager, - TSetup: FnOnce(&TManager), -{ - pub invoke_handler: TCommands::InvokeHandler, - pub setup: TSetup, - phantom: PhantomData, -} - -impl Builder -where - TLang: ExportLanguage, - TCommands: CommandsTypeState, - TEvents: EventsTypeState, -{ - fn build_inner(self) -> Result<(TCommands::InvokeHandler, EventCollection), TLang::Error> { - let cfg = self.config.clone(); - - let (rendered, (invoke_handler, events)) = self.render()?; - - if let Some(path) = cfg.path.clone() { - if let Some(export_dir) = path.parent() { - fs::create_dir_all(export_dir)?; - } - - let mut file = File::create(&path)?; - - write!(file, "{}", rendered)?; - - TLang::run_format(path, &cfg); - } - - Ok((invoke_handler, events)) - } - - fn render(self) -> Result<(String, (TCommands::InvokeHandler, EventCollection)), TLang::Error> { - let Self { - commands, - config, - events, - types, - statics, - .. - } = self; - - let (export_fn, invoke_handler) = commands.split(); - - let (events_registry, events, mut type_map) = events.get(); - let commands = export_fn(&mut type_map); - - types.collect(&mut type_map); - // TODO: This is required for channels to work correctly. - // This should be unfeature gated once the upstream fix is merged: https://github.com/tauri-apps/tauri/pull/10435 - #[cfg(feature = "UNSTABLE_channels")] - type_map.remove( as specta::NamedType>::sid()); - - let rendered = TLang::render(&commands, &events, &type_map, &statics, &config)?; - - Ok(( - format!("{}\n{rendered}", &config.header), - (invoke_handler, events_registry), - )) - } -} - -impl Builder -where - TLang: ExportLanguage, - TCommands: CommandsTypeState, -{ - #[must_use] - pub fn build_plugin_utils( - mut self, - plugin_name: &'static str, - ) -> Result { - let plugin_name = PluginName::new(plugin_name); - - self.config.plugin_name = Some(plugin_name); - - Ok(self.build_inner()?.0) - } - - #[must_use] - pub fn build(self) -> Result { - Ok(self.build_inner()?.0) - } -} - -impl Builder -where - TLang: ExportLanguage, - TCommands: CommandsTypeState, -{ - #[must_use] - pub fn build_plugin_utils>( - mut self, - plugin_name: &'static str, - ) -> Result<(TCommands::InvokeHandler, impl FnOnce(&TManager)), TLang::Error> { - let plugin_name = PluginName::new(plugin_name); - - self.config.plugin_name = Some(plugin_name); - - let (invoke_handler, event_collection) = self.build_inner()?; - - Ok((invoke_handler, move |app: &_| { - let registry = EventRegistry::get_or_manage(app); - registry.register_collection(event_collection, Some(plugin_name)); - })) - } - - #[must_use] - pub fn build>( - self, - ) -> Result<(TCommands::InvokeHandler, impl FnOnce(&TManager)), TLang::Error> { - let (invoke_handler, event_collection) = self.build_inner()?; - - Ok((invoke_handler, move |app: &_| { - let registry = EventRegistry::get_or_manage(app); - registry.register_collection(event_collection, None); - })) - } -} - -// TODO: Add a proper solution to this into Specta -fn collect_typemap<'a>(iter: impl Iterator + 'a) -> TypeMap { - let mut type_map = TypeMap::default(); - - for (sid, ndt) in iter { - type_map.insert(sid, ndt.clone()); - } - - type_map -} - -type HardcodedRuntime = tauri::Wry; - -// Standalone export functions for -impl Builder -where - TLang: ExportLanguage, - TCommands: CommandsTypeState, - TEvents: EventsTypeState, -{ - /// Exports the output of [`internal::render`] for a collection of [`FunctionDataType`] into a TypeScript file. - pub fn export(self) -> Result<(), TLang::Error> { - self.build_inner().map(|_| ()) - } - - pub fn export_for_plugin(mut self, plugin_name: &'static str) -> Result<(), TLang::Error> { - self.config.plugin_name = Some(PluginName::new(plugin_name)); - - self.export() - } -} - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub(crate) struct PluginName(&'static str); diff --git a/src/ts.rs b/src/ts.rs index 1b6190d..b1be68a 100644 --- a/src/ts.rs +++ b/src/ts.rs @@ -4,21 +4,13 @@ use indoc::formatdoc; use specta::{datatype, datatype::FunctionResultVariant}; use specta_typescript as ts; use specta_typescript::{js_doc, ExportError}; -use tauri::Runtime; -/// Implements [`ExportLanguage`] for TypeScript exporting -pub struct Language; - -pub fn builder() -> Builder, NoEvents> { - Builder::default() -} - -pub const GLOBALS: &str = include_str!("./globals.ts"); +const GLOBALS: &str = include_str!("./globals.ts"); type Config = specta_typescript::Typescript; pub type ExportConfig = crate::ExportConfig; -impl ExportLanguage for Language { +impl ExportLanguage for specta_typescript::Typescript { type Config = Config; type Error = ts::ExportError; diff --git a/tests/tauri_command.rs b/tests/tauri_command.rs new file mode 100644 index 0000000..bef2b6b --- /dev/null +++ b/tests/tauri_command.rs @@ -0,0 +1,80 @@ +// #![allow(unused)] + +// use serde::Serialize; +// use specta::{specta, Type}; +// use tauri::{State, Window}; +// use tauri_specta::collect_commands; + +// // Test different combinations of results + +// #[tauri::command] +// #[specta] +// fn basic() -> String { +// format!("Hello, world!") +// } + +// #[tauri::command] +// #[specta] +// fn result() -> Result { +// Ok(format!("Hello, world!")) +// } + +// #[tauri::command(async)] +// #[specta] +// async fn async_() -> String { +// format!("Hello, world!") +// } + +// #[tauri::command(async)] +// #[specta] +// async fn async_result() -> Result { +// Ok(format!("Hello, world!")) +// } + +// #[tauri::command(async)] +// #[specta] +// async fn async_impl() -> impl Serialize + Type { +// "Hello, World!" +// } + +// // Test different combinations of args + +// #[tauri::command] +// #[specta] +// fn value(input: String) -> String { +// format!("Hello, world!") +// } + +// #[tauri::command] +// #[specta] +// fn state(state: State) -> String { +// format!("Hello, world!") +// } + +// #[tauri::command] +// #[specta] +// fn window(window: Window) -> String { +// format!("Hello, world!") +// } + +// #[tauri::command] +// #[specta] +// fn state_value(state: State<()>, a: String) -> String { +// format!("Hello, world!") +// } + +// #[tauri::command] +// #[specta] +// fn state_many_values(state: State<()>, a: String, b: i32, c: bool, d: Box) -> String { +// format!("Hello, world!") +// } + +// #[test] +// fn test_collect_commands() { +// // collect_commands![]; +// // collect_commands![hello_world]; +// // collect_commands![hello_world,]; +// // collect_commands![hello_world, goodbye_world]; +// // collect_commands![generic::]; +// // collect_commands![generic::,]; +// } From 3087ba33d9083a48e6821e25a601f50c46be3bf3 Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Thu, 1 Aug 2024 11:12:35 +0800 Subject: [PATCH 3/9] Drop `ExportConfig` --- src/builder.rs | 16 +++------- src/js_ts.rs | 81 ++++++++++++++++++++---------------------------- src/lib.rs | 84 +++++++++++++++++++++++++++----------------------- src/ts.rs | 43 ++++++++++---------------- 4 files changed, 101 insertions(+), 123 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 6e97cfa..4e25ade 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -135,32 +135,26 @@ impl Builder { .collect::, _>>() .map(|v| v.join("\n"))?; - let cfg = crate::ExportConfig { - plugin_name: self.plugin_name.map(PluginName), - path: language.path.clone(), - header: language.header.clone(), - inner: language.clone(), - }; - let rendered = crate::js_ts::render_all_parts::( &commands, &self.events.1, &self.types, &Default::default(), // TODO: fix statics - &cfg, + &language, + &self.plugin_name, &dependant_types, crate::ts::GLOBALS, )?; - write!(file, "{}", format!("{}\n{rendered}", cfg.inner.header))?; + write!(file, "{}", format!("{}\n{rendered}", language.header))?; - cfg.inner.run_format(path.clone()).ok(); + language.run_format(path.clone()).ok(); } Ok(()) } pub fn export_js_doc(&self, language: Typescript) { - // TODO + todo!(); } } diff --git a/src/js_ts.rs b/src/js_ts.rs index b4d1b7f..7126dab 100644 --- a/src/js_ts.rs +++ b/src/js_ts.rs @@ -7,30 +7,29 @@ use specta::{ datatype::{DataType, FunctionResultVariant}, TypeMap, }; -use specta_typescript::ExportError; use specta_typescript::{self as ts}; +use specta_typescript::{ExportError, Typescript}; -use crate::{EventDataType, ExportLanguage, ItemType, StaticCollection}; +use crate::{apply_as_prefix, EventDataType, ItemType, LanguageExt, StaticCollection}; -pub const DO_NOT_EDIT: &str = "// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually."; +pub(crate) const DO_NOT_EDIT: &str = "// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually."; +// TODO: Remove this const CRINGE_ESLINT_DISABLE: &str = "/* eslint-disable */ "; -pub type ExportConfig = crate::ExportConfig; - -pub fn render_all_parts>( +// TODO: Can we avoid hardcoding error type??? +pub fn render_all_parts>( commands: &[datatype::Function], events: &[EventDataType], type_map: &TypeMap, statics: &StaticCollection, - // plugin_name: &str, - // cfg: &Typescript, - cfg: &ExportConfig, + cfg: &Typescript, + plugin_name: &Option<&'static str>, dependant_types: &str, globals: &str, ) -> Result { - let commands = T::render_commands(commands, type_map, cfg)?; - let events = T::render_events(events, type_map, cfg)?; + let commands = cfg.render_commands(commands, type_map, plugin_name)?; + let events = cfg.render_events(events, type_map, plugin_name)?; let statics = statics .statics @@ -148,37 +147,31 @@ fn tauri_invoke(name: &str, arg_usages: Option) -> String { pub fn handle_result( function: &datatype::Function, type_map: &TypeMap, - cfg: &ExportConfig, + cfg: &Typescript, ) -> Result { Ok(match &function.result() { Some(FunctionResultVariant::Result(t, e)) => { format!( "Result<{}, {}>", - ts::datatype( - &cfg.inner, - &FunctionResultVariant::Value(t.clone()), - type_map - )?, - ts::datatype( - &cfg.inner, - &FunctionResultVariant::Value(e.clone()), - type_map - )? + ts::datatype(cfg, &FunctionResultVariant::Value(t.clone()), type_map)?, + ts::datatype(cfg, &FunctionResultVariant::Value(e.clone()), type_map)? ) } - Some(FunctionResultVariant::Value(t)) => ts::datatype( - &cfg.inner, - &FunctionResultVariant::Value(t.clone()), - type_map, - )?, + Some(FunctionResultVariant::Value(t)) => { + ts::datatype(cfg, &FunctionResultVariant::Value(t.clone()), type_map)? + } None => "void".to_string(), }) } -pub fn command_body(cfg: &ExportConfig, function: &datatype::Function, as_any: bool) -> String { - let name = cfg - .plugin_name - .map(|n| n.apply_as_prefix(&function.name(), ItemType::Command)) +pub fn command_body( + plugin_name: &Option<&'static str>, + function: &datatype::Function, + as_any: bool, +) -> String { + let name = plugin_name + .as_ref() + .map(|n| apply_as_prefix(&n, &function.name(), ItemType::Command)) .unwrap_or_else(|| function.name().to_string()); maybe_return_as_result_tuple( @@ -194,13 +187,13 @@ pub fn command_body(cfg: &ExportConfig, function: &datatype::Function, as_any: b ) } -pub fn events_map(events: &[EventDataType], cfg: &ExportConfig) -> String { +pub fn events_map(events: &[EventDataType], plugin_name: &Option<&'static str>) -> String { events .iter() .map(|event| { - let name_str = cfg - .plugin_name - .map(|n| n.apply_as_prefix(event.name, ItemType::Event)) + let name_str = plugin_name + .as_ref() + .map(|n| apply_as_prefix(n, event.name, ItemType::Event)) .unwrap_or_else(|| event.name.to_string()); let name_camel = event.name.to_lower_camel_case(); @@ -212,7 +205,7 @@ pub fn events_map(events: &[EventDataType], cfg: &ExportConfig) -> String { pub fn events_types( events: &[EventDataType], - cfg: &ExportConfig, + cfg: &Typescript, type_map: &TypeMap, ) -> Result, ExportError> { events @@ -221,7 +214,7 @@ pub fn events_types( let name_camel = event.name.to_lower_camel_case(); let typ = ts::datatype( - &cfg.inner, + cfg, &FunctionResultVariant::Value(event.typ.clone()), type_map, )?; @@ -233,20 +226,12 @@ pub fn events_types( pub fn events_data( events: &[EventDataType], - cfg: &ExportConfig, + cfg: &Typescript, + plugin_name: &Option<&'static str>, type_map: &TypeMap, ) -> Result<(Vec, String), ExportError> { Ok(( events_types(events, cfg, type_map)?, - events_map(events, cfg), + events_map(events, plugin_name), )) } - -impl From for ExportConfig { - fn from(config: specta_typescript::Typescript) -> Self { - Self { - header: CRINGE_ESLINT_DISABLE.into(), - ..Self::new(config) - } - } -} diff --git a/src/lib.rs b/src/lib.rs index 132807d..bb25a4f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -116,7 +116,7 @@ use std::{borrow::Cow, error, fmt, path::PathBuf}; -use specta::{datatype, TypeMap}; +use specta::{datatype, Language, TypeMap}; #[cfg(feature = "derive")] #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] @@ -127,7 +127,7 @@ mod builder; pub mod internal; mod macros; -pub use builder::Builder; // TODO: Rename +pub use builder::Builder; /// The exporter for [Javascript](https://www.javascript.com). #[cfg(feature = "javascript")] @@ -149,36 +149,32 @@ mod statics; pub use event::*; pub use statics::StaticCollection; -/// A set of functions that produce language-specific code -pub trait ExportLanguage: 'static { - type Config: Default + Clone; // TODO: Remove - type Error: fmt::Debug + error::Error + From; // TODO: Review if this `From` should be removed before stabilisation - - fn run_format(path: PathBuf, cfg: &ExportConfig); - - fn render_events( - events: &[EventDataType], +pub trait LanguageExt: Language { + fn render_commands( + &self, + commands: &[datatype::Function], type_map: &TypeMap, - cfg: &ExportConfig, + plugin_name: &Option<&'static str>, ) -> Result; - /// Renders a collection of [`FunctionDataType`] into a string. - fn render_commands( - commands: &[datatype::Function], + fn render_events( + &self, + events: &[EventDataType], type_map: &TypeMap, - cfg: &ExportConfig, + plugin_name: &Option<&'static str>, ) -> Result; - /// Renders the output of [`globals`], [`render_functions`] and all dependant types into a TypeScript string. fn render( + &self, commands: &[datatype::Function], events: &[EventDataType], type_map: &TypeMap, statics: &StaticCollection, - cfg: &ExportConfig, + plugin_name: &Option<&'static str>, ) -> Result; } +// TODO: Remove #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub(crate) struct PluginName(&'static str); @@ -205,25 +201,37 @@ impl PluginName { } } -/// The configuration for the generator -#[derive(Default, Clone)] -pub struct ExportConfig { - /// The name of the plugin to invoke. - /// - /// If there is no plugin name (i.e. this is an app), this should be `None`. - pub(crate) plugin_name: Option, - /// The specta export configuration - pub(crate) inner: TConfig, - pub(crate) path: Option, - pub(crate) header: Cow<'static, str>, +pub(crate) fn apply_as_prefix(plugin_name: &str, s: &str, item_type: ItemType) -> String { + format!( + "plugin:{}{}{}", + plugin_name, + match item_type { + ItemType::Event => ":", + ItemType::Command => "|", + }, + s, + ) } -impl ExportConfig { - /// Creates a new [`ExportConfiguration`] from a [`specta::ts::ExportConfiguration`] - pub fn new(config: TConfig) -> Self { - Self { - inner: config, - ..Default::default() - } - } -} +// // TODO: Remove +// #[derive(Default, Clone)] +// pub struct ExportConfig { +// /// The name of the plugin to invoke. +// /// +// /// If there is no plugin name (i.e. this is an app), this should be `None`. +// pub(crate) plugin_name: Option, +// /// The specta export configuration +// pub(crate) inner: TConfig, +// pub(crate) path: Option, +// pub(crate) header: Cow<'static, str>, +// } + +// impl ExportConfig { +// /// Creates a new [`ExportConfiguration`] from a [`specta::ts::ExportConfiguration`] +// pub fn new(config: TConfig) -> Self { +// Self { +// inner: config, +// ..Default::default() +// } +// } +// } diff --git a/src/ts.rs b/src/ts.rs index b1be68a..c9f588a 100644 --- a/src/ts.rs +++ b/src/ts.rs @@ -5,24 +5,16 @@ use specta::{datatype, datatype::FunctionResultVariant}; use specta_typescript as ts; use specta_typescript::{js_doc, ExportError}; -const GLOBALS: &str = include_str!("./globals.ts"); - -type Config = specta_typescript::Typescript; -pub type ExportConfig = crate::ExportConfig; - -impl ExportLanguage for specta_typescript::Typescript { - type Config = Config; - type Error = ts::ExportError; - - fn run_format(path: PathBuf, cfg: &ExportConfig) { - cfg.inner.run_format(path).ok(); - } +// TODO: Make private +pub(crate) const GLOBALS: &str = include_str!("./globals.ts"); +impl LanguageExt for specta_typescript::Typescript { /// Renders a collection of [`FunctionDataType`] into a TypeScript string. fn render_commands( + &self, commands: &[datatype::Function], type_map: &TypeMap, - cfg: &ExportConfig, + plugin_name: &Option<&'static str>, ) -> Result { let commands = commands .iter() @@ -30,16 +22,12 @@ impl ExportLanguage for specta_typescript::Typescript { let arg_defs = function .args() .map(|(name, typ)| { - ts::datatype( - &cfg.inner, - &FunctionResultVariant::Value(typ.clone()), - type_map, - ) - .map(|ty| format!("{}: {}", name.to_lower_camel_case(), ty)) + ts::datatype(self, &FunctionResultVariant::Value(typ.clone()), type_map) + .map(|ty| format!("{}: {}", name.to_lower_camel_case(), ty)) }) .collect::, _>>()?; - let ret_type = js_ts::handle_result(function, type_map, cfg)?; + let ret_type = js_ts::handle_result(function, type_map, self)?; let docs = { let mut builder = js_doc::Builder::default(); @@ -59,7 +47,7 @@ impl ExportLanguage for specta_typescript::Typescript { &function.name().to_lower_camel_case(), &arg_defs, Some(&ret_type), - &js_ts::command_body(cfg, function, true), + &js_ts::command_body(plugin_name, function, true), )) }) .collect::, ExportError>>()? @@ -74,15 +62,16 @@ impl ExportLanguage for specta_typescript::Typescript { } fn render_events( + &self, events: &[EventDataType], type_map: &TypeMap, - cfg: &ExportConfig, + plugin_name: &Option<&'static str>, ) -> Result { if events.is_empty() { return Ok(Default::default()); } - let (events_types, events_map) = js_ts::events_data(events, cfg, type_map)?; + let (events_types, events_map) = js_ts::events_data(events, self, plugin_name, type_map)?; let events_types = events_types.join(",\n"); @@ -97,15 +86,16 @@ impl ExportLanguage for specta_typescript::Typescript { } fn render( + &self, commands: &[datatype::Function], events: &[EventDataType], type_map: &TypeMap, statics: &StaticCollection, - cfg: &ExportConfig, + plugin_name: &Option<&'static str>, ) -> Result { let dependant_types = type_map .iter() - .map(|(_sid, ndt)| ts::export_named_datatype(&cfg.inner, ndt, type_map)) + .map(|(_sid, ndt)| ts::export_named_datatype(&self, ndt, type_map)) .collect::, _>>() .map(|v| v.join("\n"))?; @@ -114,7 +104,8 @@ impl ExportLanguage for specta_typescript::Typescript { events, type_map, statics, - cfg, + self, + plugin_name, &dependant_types, GLOBALS, ) From b5cc0644d67d6dadba9506c02c204f7517502e82 Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Thu, 1 Aug 2024 11:16:49 +0800 Subject: [PATCH 4/9] Remove `PluginName` --- src/builder.rs | 2 +- src/event.rs | 9 +++++---- src/lib.rs | 46 +--------------------------------------------- 3 files changed, 7 insertions(+), 50 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 4e25ade..487c4b9 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -12,7 +12,7 @@ use tauri::{ipc::Invoke, App, Runtime}; use crate::{ internal::{Commands, Events}, - EventRegistry, PluginName, + EventRegistry, }; pub struct Builder { diff --git a/src/event.rs b/src/event.rs index b48bfcb..2c396d8 100644 --- a/src/event.rs +++ b/src/event.rs @@ -7,17 +7,18 @@ use serde::{de::DeserializeOwned, Serialize}; use specta::{DataType, NamedType, SpectaID}; use tauri::{Emitter, EventId, EventTarget, Listener, Manager, Runtime}; -use crate::PluginName; +use crate::apply_as_prefix; #[derive(Clone, Copy)] pub struct EventRegistryMeta { - plugin_name: Option, + plugin_name: Option<&'static str>, } impl EventRegistryMeta { fn wrap_with_plugin(&self, input: &str) -> String { self.plugin_name - .map(|n| n.apply_as_prefix(input, crate::ItemType::Event)) + .as_ref() + .map(|n| apply_as_prefix(n, input, crate::ItemType::Event)) .unwrap_or_else(|| input.to_string()) } } @@ -45,7 +46,7 @@ impl EventRegistry { pub fn register_collection( &self, collection: EventCollection, - plugin_name: Option, + plugin_name: Option<&'static str>, ) { let mut registry = self.0.write().expect("Failed to write EventRegistry"); diff --git a/src/lib.rs b/src/lib.rs index bb25a4f..cb7bca3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -174,33 +174,12 @@ pub trait LanguageExt: Language { ) -> Result; } -// TODO: Remove -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub(crate) struct PluginName(&'static str); - +// TODO: Remove this pub(crate) enum ItemType { Event, Command, } -impl PluginName { - pub fn new(plugin_name: &'static str) -> Self { - Self(plugin_name) - } - - pub fn apply_as_prefix(&self, s: &str, item_type: ItemType) -> String { - format!( - "plugin:{}{}{}", - self.0, - match item_type { - ItemType::Event => ":", - ItemType::Command => "|", - }, - s, - ) - } -} - pub(crate) fn apply_as_prefix(plugin_name: &str, s: &str, item_type: ItemType) -> String { format!( "plugin:{}{}{}", @@ -212,26 +191,3 @@ pub(crate) fn apply_as_prefix(plugin_name: &str, s: &str, item_type: ItemType) - s, ) } - -// // TODO: Remove -// #[derive(Default, Clone)] -// pub struct ExportConfig { -// /// The name of the plugin to invoke. -// /// -// /// If there is no plugin name (i.e. this is an app), this should be `None`. -// pub(crate) plugin_name: Option, -// /// The specta export configuration -// pub(crate) inner: TConfig, -// pub(crate) path: Option, -// pub(crate) header: Cow<'static, str>, -// } - -// impl ExportConfig { -// /// Creates a new [`ExportConfiguration`] from a [`specta::ts::ExportConfiguration`] -// pub fn new(config: TConfig) -> Self { -// Self { -// inner: config, -// ..Default::default() -// } -// } -// } From bda241d5b0c746fab6a7ff7e1fb5c83043ef2ccf Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Thu, 1 Aug 2024 11:21:38 +0800 Subject: [PATCH 5/9] Drop `StaticCollection` --- src/builder.rs | 1 - src/js_ts.rs | 52 ++++++++++++++++++++++++++------------------------ src/lib.rs | 5 ----- src/ts.rs | 2 -- 4 files changed, 27 insertions(+), 33 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 487c4b9..79b522f 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -139,7 +139,6 @@ impl Builder { &commands, &self.events.1, &self.types, - &Default::default(), // TODO: fix statics &language, &self.plugin_name, &dependant_types, diff --git a/src/js_ts.rs b/src/js_ts.rs index 7126dab..0cf6395 100644 --- a/src/js_ts.rs +++ b/src/js_ts.rs @@ -10,7 +10,7 @@ use specta::{ use specta_typescript::{self as ts}; use specta_typescript::{ExportError, Typescript}; -use crate::{apply_as_prefix, EventDataType, ItemType, LanguageExt, StaticCollection}; +use crate::{apply_as_prefix, EventDataType, ItemType, LanguageExt}; pub(crate) const DO_NOT_EDIT: &str = "// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually."; // TODO: Remove this @@ -22,7 +22,6 @@ pub fn render_all_parts>( commands: &[datatype::Function], events: &[EventDataType], type_map: &TypeMap, - statics: &StaticCollection, cfg: &Typescript, plugin_name: &Option<&'static str>, dependant_types: &str, @@ -31,29 +30,32 @@ pub fn render_all_parts>( let commands = cfg.render_commands(commands, type_map, plugin_name)?; let events = cfg.render_events(events, type_map, plugin_name)?; - let statics = statics - .statics - .iter() - .map(|(name, value)| { - let mut as_const = None; - match &value { - serde_json::Value::Null => {} - serde_json::Value::Bool(_) - | serde_json::Value::Number(_) - | serde_json::Value::String(_) - | serde_json::Value::Array(_) - | serde_json::Value::Object(_) => as_const = Some(" as const"), - } - - format!( - "export const {name} = {}{};", - serde_json::to_string(&value) - .expect("failed to serialize from `serde_json::Value`"), - as_const.unwrap_or("") - ) - }) - .collect::>() - .join("\n"); + // TODO: Bring this back + // let statics = statics + // .statics + // .iter() + // .map(|(name, value)| { + // let mut as_const = None; + // match &value { + // serde_json::Value::Null => {} + // serde_json::Value::Bool(_) + // | serde_json::Value::Number(_) + // | serde_json::Value::String(_) + // | serde_json::Value::Array(_) + // | serde_json::Value::Object(_) => as_const = Some(" as const"), + // } + + // format!( + // "export const {name} = {}{};", + // serde_json::to_string(&value) + // .expect("failed to serialize from `serde_json::Value`"), + // as_const.unwrap_or("") + // ) + // }) + // .collect::>() + // .join("\n"); + + let statics = ""; // TODO Ok(formatdoc! { r#" diff --git a/src/lib.rs b/src/lib.rs index cb7bca3..9bfca24 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,8 +114,6 @@ html_favicon_url = "https://github.com/oscartbeaumont/specta/raw/main/.github/logo-128.png" )] -use std::{borrow::Cow, error, fmt, path::PathBuf}; - use specta::{datatype, Language, TypeMap}; #[cfg(feature = "derive")] @@ -143,11 +141,9 @@ pub mod ts; mod js_ts; mod event; -mod statics; // TODO: Probs drop pub use event::*; -pub use statics::StaticCollection; pub trait LanguageExt: Language { fn render_commands( @@ -169,7 +165,6 @@ pub trait LanguageExt: Language { commands: &[datatype::Function], events: &[EventDataType], type_map: &TypeMap, - statics: &StaticCollection, plugin_name: &Option<&'static str>, ) -> Result; } diff --git a/src/ts.rs b/src/ts.rs index c9f588a..d2b1577 100644 --- a/src/ts.rs +++ b/src/ts.rs @@ -90,7 +90,6 @@ impl LanguageExt for specta_typescript::Typescript { commands: &[datatype::Function], events: &[EventDataType], type_map: &TypeMap, - statics: &StaticCollection, plugin_name: &Option<&'static str>, ) -> Result { let dependant_types = type_map @@ -103,7 +102,6 @@ impl LanguageExt for specta_typescript::Typescript { commands, events, type_map, - statics, self, plugin_name, &dependant_types, From 55a79c45db1858fa07a4718df11e1ae132a8dd06 Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Thu, 1 Aug 2024 12:11:49 +0800 Subject: [PATCH 6/9] Introduce `Configuration` --- src/builder.rs | 12 ++++++---- src/event.rs | 1 + src/js_ts.rs | 19 +++++++--------- src/lib.rs | 34 +++++++++++---------------- src/statics.rs | 39 ------------------------------- src/ts.rs | 62 ++++++++++++++++++-------------------------------- 6 files changed, 52 insertions(+), 115 deletions(-) delete mode 100644 src/statics.rs diff --git a/src/builder.rs b/src/builder.rs index 79b522f..47ce622 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -136,11 +136,15 @@ impl Builder { .map(|v| v.join("\n"))?; let rendered = crate::js_ts::render_all_parts::( - &commands, - &self.events.1, - &self.types, &language, - &self.plugin_name, + &crate::Configuration { + commands, + // TODO: Don't clone stuff + events: self.events.1.clone(), + type_map: self.types.clone(), + constants: (), + plugin_name: self.plugin_name, + }, &dependant_types, crate::ts::GLOBALS, )?; diff --git a/src/event.rs b/src/event.rs index 2c396d8..967311e 100644 --- a/src/event.rs +++ b/src/event.rs @@ -188,6 +188,7 @@ pub trait Event: NamedType { } } +#[derive(Debug, Clone)] pub struct EventDataType { pub name: &'static str, pub typ: DataType, diff --git a/src/js_ts.rs b/src/js_ts.rs index 0cf6395..fef976b 100644 --- a/src/js_ts.rs +++ b/src/js_ts.rs @@ -3,32 +3,29 @@ use std::borrow::Cow; use heck::ToLowerCamelCase; use indoc::formatdoc; use specta::{ - datatype, - datatype::{DataType, FunctionResultVariant}, + datatype::{self, DataType, FunctionResultVariant}, TypeMap, }; use specta_typescript::{self as ts}; use specta_typescript::{ExportError, Typescript}; -use crate::{apply_as_prefix, EventDataType, ItemType, LanguageExt}; +use crate::{apply_as_prefix, Configuration, EventDataType, ItemType, LanguageExt}; + +const DO_NOT_EDIT: &str = "// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually."; -pub(crate) const DO_NOT_EDIT: &str = "// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually."; // TODO: Remove this const CRINGE_ESLINT_DISABLE: &str = "/* eslint-disable */ "; // TODO: Can we avoid hardcoding error type??? pub fn render_all_parts>( - commands: &[datatype::Function], - events: &[EventDataType], - type_map: &TypeMap, - cfg: &Typescript, - plugin_name: &Option<&'static str>, + language: &T, + cfg: &Configuration, dependant_types: &str, globals: &str, ) -> Result { - let commands = cfg.render_commands(commands, type_map, plugin_name)?; - let events = cfg.render_events(events, type_map, plugin_name)?; + let commands = language.render_commands(&cfg)?; + let events = language.render_events(&cfg)?; // TODO: Bring this back // let statics = statics diff --git a/src/lib.rs b/src/lib.rs index 9bfca24..161e72e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -145,28 +145,20 @@ mod event; // TODO: Probs drop pub use event::*; -pub trait LanguageExt: Language { - fn render_commands( - &self, - commands: &[datatype::Function], - type_map: &TypeMap, - plugin_name: &Option<&'static str>, - ) -> Result; - - fn render_events( - &self, - events: &[EventDataType], - type_map: &TypeMap, - plugin_name: &Option<&'static str>, - ) -> Result; +#[derive(Debug, Clone)] +#[non_exhaustive] +pub struct Configuration { + commands: Vec, + events: Vec, + type_map: TypeMap, + constants: (), // TODO + plugin_name: Option<&'static str>, +} - fn render( - &self, - commands: &[datatype::Function], - events: &[EventDataType], - type_map: &TypeMap, - plugin_name: &Option<&'static str>, - ) -> Result; +pub trait LanguageExt: Language { + fn render_commands(&self, cfg: &Configuration) -> Result; + fn render_events(&self, cfg: &Configuration) -> Result; + fn render(&self, cfg: &Configuration) -> Result; } // TODO: Remove this diff --git a/src/statics.rs b/src/statics.rs deleted file mode 100644 index 171b536..0000000 --- a/src/statics.rs +++ /dev/null @@ -1,39 +0,0 @@ -// TODO: Restrict this to only non-JS/TS languages. - -use std::{ - borrow::{Borrow, Cow}, - collections::HashMap, -}; - -use serde::Serialize; - -/// Define a set of statics which can be included in the exporter -#[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct StaticCollection { - pub(crate) statics: HashMap, serde_json::Value>, -} - -impl StaticCollection { - /// Join another type collection into this one. - pub fn extend(&mut self, collection: impl Borrow) -> &mut Self { - self.statics.extend( - collection - .borrow() - .statics - .iter() - .map(|(k, v)| (k.clone(), v.clone())), - ); - self - } - - /// Register a static with the collection. - pub fn register( - &mut self, - name: impl Into>, - value: T, - ) -> &mut Self { - self.statics - .insert(name.into(), serde_json::to_value(&value).unwrap()); - self - } -} diff --git a/src/ts.rs b/src/ts.rs index d2b1577..51ab21e 100644 --- a/src/ts.rs +++ b/src/ts.rs @@ -1,7 +1,7 @@ -use crate::{js_ts, *}; +use crate::{js_ts, Configuration, LanguageExt}; use heck::ToLowerCamelCase; use indoc::formatdoc; -use specta::{datatype, datatype::FunctionResultVariant}; +use specta::datatype::FunctionResultVariant; use specta_typescript as ts; use specta_typescript::{js_doc, ExportError}; @@ -9,25 +9,24 @@ use specta_typescript::{js_doc, ExportError}; pub(crate) const GLOBALS: &str = include_str!("./globals.ts"); impl LanguageExt for specta_typescript::Typescript { - /// Renders a collection of [`FunctionDataType`] into a TypeScript string. - fn render_commands( - &self, - commands: &[datatype::Function], - type_map: &TypeMap, - plugin_name: &Option<&'static str>, - ) -> Result { - let commands = commands + fn render_commands(&self, cfg: &Configuration) -> Result { + let commands = cfg + .commands .iter() .map(|function| { let arg_defs = function .args() .map(|(name, typ)| { - ts::datatype(self, &FunctionResultVariant::Value(typ.clone()), type_map) - .map(|ty| format!("{}: {}", name.to_lower_camel_case(), ty)) + ts::datatype( + self, + &FunctionResultVariant::Value(typ.clone()), + &cfg.type_map, + ) + .map(|ty| format!("{}: {}", name.to_lower_camel_case(), ty)) }) .collect::, _>>()?; - let ret_type = js_ts::handle_result(function, type_map, self)?; + let ret_type = js_ts::handle_result(function, &cfg.type_map, self)?; let docs = { let mut builder = js_doc::Builder::default(); @@ -47,7 +46,7 @@ impl LanguageExt for specta_typescript::Typescript { &function.name().to_lower_camel_case(), &arg_defs, Some(&ret_type), - &js_ts::command_body(plugin_name, function, true), + &js_ts::command_body(&cfg.plugin_name, function, true), )) }) .collect::, ExportError>>()? @@ -61,17 +60,13 @@ impl LanguageExt for specta_typescript::Typescript { }) } - fn render_events( - &self, - events: &[EventDataType], - type_map: &TypeMap, - plugin_name: &Option<&'static str>, - ) -> Result { - if events.is_empty() { + fn render_events(&self, cfg: &Configuration) -> Result { + if cfg.events.is_empty() { return Ok(Default::default()); } - let (events_types, events_map) = js_ts::events_data(events, self, plugin_name, type_map)?; + let (events_types, events_map) = + js_ts::events_data(&cfg.events, self, &cfg.plugin_name, &cfg.type_map)?; let events_types = events_types.join(",\n"); @@ -85,27 +80,14 @@ impl LanguageExt for specta_typescript::Typescript { }) } - fn render( - &self, - commands: &[datatype::Function], - events: &[EventDataType], - type_map: &TypeMap, - plugin_name: &Option<&'static str>, - ) -> Result { - let dependant_types = type_map + fn render(&self, cfg: &Configuration) -> Result { + let dependant_types = cfg + .type_map .iter() - .map(|(_sid, ndt)| ts::export_named_datatype(&self, ndt, type_map)) + .map(|(_sid, ndt)| ts::export_named_datatype(&self, ndt, &cfg.type_map)) .collect::, _>>() .map(|v| v.join("\n"))?; - js_ts::render_all_parts::( - commands, - events, - type_map, - self, - plugin_name, - &dependant_types, - GLOBALS, - ) + js_ts::render_all_parts::(self, cfg, &dependant_types, GLOBALS) } } From 49ea2f53e80de55fca9e0735e3a38912d161e18d Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Thu, 1 Aug 2024 15:38:00 +0800 Subject: [PATCH 7/9] Make `export` generic on lang + jsdoc --- Cargo.lock | 1020 ++++++++++++---------- Cargo.toml | 5 +- examples/app/src-tauri/Cargo.toml | 1 + examples/app/src-tauri/src/main.rs | 16 +- examples/app/src/bindings-jsdoc.js | 176 ++++ examples/app/src/bindings.ts | 8 +- examples/app/src/main.ts | 1 + examples/app/tsconfig.json | 1 + examples/custom-plugin/plugin/src/lib.rs | 12 +- src/builder.rs | 208 +++-- src/event.rs | 133 +-- src/internal.rs | 51 -- src/js.rs | 144 --- src/lang.rs | 8 + src/{ => lang}/globals.js | 0 src/{ => lang}/globals.ts | 0 src/lang/js.rs | 107 +++ src/{ => lang}/js_ts.rs | 105 +-- src/{ => lang}/ts.rs | 7 +- src/lib.rs | 112 ++- src/macros.rs | 21 +- 21 files changed, 1189 insertions(+), 947 deletions(-) create mode 100644 examples/app/src/bindings-jsdoc.js delete mode 100644 src/internal.rs delete mode 100644 src/js.rs create mode 100644 src/lang.rs rename src/{ => lang}/globals.js (100%) rename src/{ => lang}/globals.ts (100%) create mode 100644 src/lang/js.rs rename src/{ => lang}/js_ts.rs (69%) rename src/{ => lang}/ts.rs (95%) diff --git a/Cargo.lock b/Cargo.lock index 60c131a..a0d04b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,9 @@ checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -25,9 +25,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.1.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -64,9 +64,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "atk" @@ -93,15 +93,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -114,15 +114,15 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.4" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" @@ -132,9 +132,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "serde", ] @@ -154,11 +154,20 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2", +] + [[package]] name = "brotli" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" +checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -167,9 +176,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.5.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da74e2b81409b1b743f8f0c62cc6254afefb8b8e50bbfe3735550f7aeefa3448" +checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -177,27 +186,27 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.14.0" +version = "1.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +checksum = "102087e286b4677862ea56cf8fc58bb2cdfa8725c40ffb80fe3a008eb7f2fc83" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "fca2be1d5c43812bae364ee3f30b3afcb7877cf59f4aeb94c66f313a41d2fac9" dependencies = [ "serde", ] @@ -208,7 +217,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "cairo-sys-rs", "glib", "libc", @@ -229,9 +238,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" dependencies = [ "serde", ] @@ -271,12 +280,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" [[package]] name = "cesu8" @@ -297,9 +303,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.15.5" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03915af431787e6ffdcc74c645077518c6b6e01f80b761e0fbbfa288536311b3" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" dependencies = [ "smallvec", "target-lexicon", @@ -313,21 +319,21 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e53693616d3075149f4ead59bdeecd204ac6b8192d8969757601b74bddf00f" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", "serde", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -362,9 +368,9 @@ dependencies = [ [[package]] name = "combine" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ "bytes", "memchr", @@ -418,40 +424,36 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-common" @@ -502,9 +504,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -512,9 +514,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", @@ -526,9 +528,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", @@ -537,24 +539,25 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ + "powerfmt", "serde", ] [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "convert_case", "proc-macro2", "quote", "rustc_version", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] @@ -594,15 +597,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" -[[package]] -name = "dlib" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" -dependencies = [ - "libloading 0.8.3", -] - [[package]] name = "dlopen2" version = "0.7.0" @@ -643,9 +637,9 @@ checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" [[package]] name = "dtoa-short" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" dependencies = [ "dtoa", ] @@ -664,15 +658,16 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "embed-resource" -version = "2.3.0" +version = "2.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd0a2c9b742a980060d22545a7a83b573acd6b73045b9de6370c9530ce652f27" +checksum = "4edcacde9351c33139a41e3c97eb2334351a81a2791bebb0b243df837128f602" dependencies = [ "cc", + "memchr", "rustc_version", - "toml 0.7.8", + "toml 0.8.2", "vswhom", - "winreg 0.51.0", + "winreg", ] [[package]] @@ -699,9 +694,9 @@ dependencies = [ [[package]] name = "fdeflate" -version = "0.3.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" dependencies = [ "simd-adler32", ] @@ -718,9 +713,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.27" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", @@ -761,9 +756,9 @@ checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -780,24 +775,24 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -806,15 +801,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", @@ -823,21 +818,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", "futures-io", @@ -1004,9 +999,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -1015,9 +1010,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "gio" @@ -1057,7 +1052,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "futures-channel", "futures-core", "futures-executor", @@ -1175,9 +1170,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.1" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" @@ -1193,9 +1188,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -1225,14 +1220,14 @@ checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", - "itoa 1.0.9", + "itoa 1.0.11", ] [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http", @@ -1240,12 +1235,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", - "futures-core", + "futures-util", "http", "http-body", "pin-project-lite", @@ -1253,15 +1248,15 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "hyper" -version = "1.3.1" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ "bytes", "futures-channel", @@ -1269,7 +1264,7 @@ dependencies = [ "http", "http-body", "httparse", - "itoa 1.0.9", + "itoa 1.0.11", "pin-project-lite", "smallvec", "tokio", @@ -1278,9 +1273,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" dependencies = [ "bytes", "futures-channel", @@ -1298,16 +1293,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.57" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows 0.48.0", + "windows-core 0.52.0", ] [[package]] @@ -1337,9 +1332,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1358,12 +1353,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.2" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" dependencies = [ "equivalent", - "hashbrown 0.14.1", + "hashbrown 0.14.5", "serde", ] @@ -1384,18 +1379,18 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itoa" @@ -1405,9 +1400,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "javascriptcore-rs" @@ -1456,23 +1451,22 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] [[package]] name = "json-patch" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ff1e1486799e3f64129f8ccad108b38290df9cd7015cd31bed17239f0789d6" +checksum = "ec9ad60d674508f3ca8f380a928cfe7b096bc729c4e2dbfe3852bc45da3ab30b" dependencies = [ "serde", "serde_json", "thiserror", - "treediff", ] [[package]] @@ -1481,7 +1475,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "serde", "unicode-segmentation", ] @@ -1501,9 +1495,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libappindicator" @@ -1525,15 +1519,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" dependencies = [ "gtk-sys", - "libloading 0.7.4", + "libloading", "once_cell", ] [[package]] name = "libc" -version = "0.2.148" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libloading" @@ -1546,29 +1540,20 @@ dependencies = [ ] [[package]] -name = "libloading" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" -dependencies = [ - "cfg-if", - "windows-targets 0.52.5", -] - -[[package]] -name = "line-wrap" -version = "0.1.1" +name = "libredox" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "safemem", + "bitflags 2.6.0", + "libc", ] [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -1576,9 +1561,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "loom" @@ -1641,15 +1626,15 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoffset" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] @@ -1662,9 +1647,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", "simd-adler32", @@ -1672,13 +1657,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" dependencies = [ + "hermit-abi", "libc", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1731,9 +1717,9 @@ dependencies = [ [[package]] name = "new_debug_unreachable" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nodrop" @@ -1752,22 +1738,18 @@ dependencies = [ ] [[package]] -name = "num-traits" -version = "0.2.16" +name = "num-conv" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" -dependencies = [ - "autocfg", -] +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] -name = "num_cpus" -version = "1.16.0" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "hermit-abi", - "libc", + "autocfg", ] [[package]] @@ -1801,6 +1783,106 @@ dependencies = [ "objc_exception", ] +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.6.0", + "block2", + "libc", + "objc2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-encode" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.6.0", + "block2", + "dispatch", + "libc", + "objc2", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + [[package]] name = "objc_exception" version = "0.1.2" @@ -1821,18 +1903,18 @@ dependencies = [ [[package]] name = "object" -version = "0.32.1" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "option-ext" @@ -1842,13 +1924,13 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "os_info" -version = "3.7.0" +version = "3.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006e42d5b888366f1880eda20371fedde764ed2213dc8496f49622fa0c99cd5e" +checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" dependencies = [ "log", "serde", - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -1884,9 +1966,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -1894,28 +1976,28 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", + "redox_syscall", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "phf" @@ -2073,9 +2155,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -2085,19 +2167,18 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plist" -version = "1.5.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdc0001cfea3db57a2e24bc0d818e9e20e554b5f97fabb9bc231dc240269ae06" +checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ - "base64 0.21.4", - "indexmap 1.9.3", - "line-wrap", + "base64 0.22.1", + "indexmap 2.3.0", "quick-xml", "serde", "time", @@ -2105,9 +2186,9 @@ dependencies = [ [[package]] name = "png" -version = "0.17.10" +version = "0.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" +checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" dependencies = [ "bitflags 1.3.2", "crc32fast", @@ -2116,11 +2197,20 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "dee4364d9f3b902ef14fab8a1ddffb783a1cb6b4bba3bfc1fa3922732c7de97f" +dependencies = [ + "zerocopy", +] [[package]] name = "precomputed-hash" @@ -2189,9 +2279,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.29.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b9228215d82c7b61490fec1de287136b5de6f5700f6e58ea9ad61a7964ca51" +checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" dependencies = [ "memchr", ] @@ -2265,7 +2355,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.15", ] [[package]] @@ -2294,58 +2384,40 @@ checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" [[package]] name = "raw-window-handle" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cc3bcbdb1ddfc11e700e62968e6b4cc9c75bb466464ad28fb61c5b2c964418b" - -[[package]] -name = "redox_syscall" -version = "0.2.16" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ - "getrandom 0.2.10", - "redox_syscall 0.2.16", + "getrandom 0.2.15", + "libredox", "thiserror", ] [[package]] name = "regex" -version = "1.9.6" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.9", - "regex-syntax 0.7.5", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -2359,13 +2431,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.9" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.5", + "regex-syntax 0.8.4", ] [[package]] @@ -2376,17 +2448,17 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "reqwest" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "bytes", "futures-core", "futures-util", @@ -2414,14 +2486,14 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "winreg 0.52.0", + "winreg", ] [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc_version" @@ -2434,21 +2506,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -2461,9 +2527,9 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.19" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6e7ed6919cb46507fb01ff1654309219f62b4d603822501b0b80d42f6f21ef" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" dependencies = [ "dyn-clone", "indexmap 1.9.3", @@ -2475,9 +2541,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.19" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185f2b7aa7e02d418e453790dde16890256bbd2bcd04b7dc5348811052b53f49" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" dependencies = [ "proc-macro2", "quote", @@ -2519,9 +2585,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.19" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" dependencies = [ "serde", ] @@ -2559,9 +2625,9 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.29.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", @@ -2570,20 +2636,21 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" dependencies = [ - "itoa 1.0.9", + "itoa 1.0.11", + "memchr", "ryu", "serde", ] [[package]] name = "serde_repr" -version = "0.1.16" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", @@ -2592,9 +2659,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] @@ -2606,23 +2673,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.9", + "itoa 1.0.11", "ryu", "serde", ] [[package]] name = "serde_with" -version = "3.3.0" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca3b16a3d82c4088f343b7480a93550b3eabe1a358569c2dfe38bbcead07237" +checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" dependencies = [ - "base64 0.21.4", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.0.2", + "indexmap 2.3.0", "serde", + "serde_derive", "serde_json", "serde_with_macros", "time", @@ -2630,9 +2698,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.3.0" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e6be15c453eb305019bfa438b1593c731f36a289a7853f7707ee29e870b3b3c" +checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" dependencies = [ "darling", "proc-macro2", @@ -2685,9 +2753,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b21f559e07218024e7e9f90f96f601825397de0e25420135f7f952453fed0b" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -2721,32 +2789,33 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "softbuffer" -version = "0.4.2" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61d5d17f23326fe0d9b0af282f73f3af666699420fd5f42629efd9c6e7dc166f" +checksum = "d623bff5d06f60d738990980d782c8c866997d9194cfe79ecad00aa2f76826dd" dependencies = [ "bytemuck", "cfg_aliases", - "cocoa", "core-graphics", "foreign-types", "js-sys", "log", - "objc", - "raw-window-handle 0.6.1", - "redox_syscall 0.5.1", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-quartz-core", + "raw-window-handle 0.6.2", + "redox_syscall", "wasm-bindgen", - "wayland-sys", "web-sys", "windows-sys 0.52.0", ] @@ -2786,6 +2855,15 @@ dependencies = [ "thiserror", ] +[[package]] +name = "specta-jsdoc" +version = "0.0.3" +dependencies = [ + "specta", + "specta-serde", + "specta-typescript", +] + [[package]] name = "specta-macros" version = "2.0.0-rc.16" @@ -2864,9 +2942,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "swift-rs" @@ -2874,7 +2952,7 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bbdb58577b6301f8d17ae2561f32002a5bae056d444e0f69e611e504a276204" dependencies = [ - "base64 0.21.4", + "base64 0.21.7", "serde", "serde_json", ] @@ -2903,9 +2981,9 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "0.1.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" [[package]] name = "sys-locale" @@ -2918,14 +2996,14 @@ dependencies = [ [[package]] name = "system-deps" -version = "6.1.1" +version = "6.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30c2de8a4d8f4b823d634affc9cd2a74ec98c53a756f317e529a48046cbf71f3" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" dependencies = [ "cfg-expr", - "heck 0.4.1", + "heck 0.5.0", "pkg-config", - "toml 0.7.8", + "toml 0.8.2", "version-compare", ] @@ -2935,7 +3013,7 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea538df05fbc2dcbbd740ba0cfe8607688535f4798d213cbbfa13ce494f3451f" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "cocoa", "core-foundation", "core-graphics", @@ -2957,13 +3035,13 @@ dependencies = [ "objc", "once_cell", "parking_lot", - "raw-window-handle 0.6.1", + "raw-window-handle 0.6.2", "scopeguard", "tao-macros", "unicode-segmentation", "url", "windows 0.57.0", - "windows-core", + "windows-core 0.57.0", "windows-version", "x11-dl", ] @@ -2981,9 +3059,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.11" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" @@ -2998,7 +3076,7 @@ dependencies = [ "dunce", "embed_plist", "futures-util", - "getrandom 0.2.10", + "getrandom 0.2.15", "glob", "gtk", "heck 0.5.0", @@ -3010,7 +3088,7 @@ dependencies = [ "muda", "objc", "percent-encoding", - "raw-window-handle 0.6.1", + "raw-window-handle 0.6.2", "reqwest", "serde", "serde_json", @@ -3063,7 +3141,7 @@ version = "2.0.0-beta.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43bbc731067e319ef60601bf5716d1e706ee9ae28e38c0587f7165c7d6824cdf" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "brotli", "ico", "json-patch", @@ -3117,9 +3195,9 @@ dependencies = [ [[package]] name = "tauri-plugin-os" -version = "2.0.0-beta.3" +version = "2.0.0-beta.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dc0a2037ef113d9d9db85edceab6f95f83ae111e4d989d6bc1df79c8ab4cf" +checksum = "acc9d9dfe0946d5f9343ba248603a4139d73457ae0095acb1cb281c24cb1666e" dependencies = [ "gethostname", "log", @@ -3156,7 +3234,7 @@ dependencies = [ "gtk", "http", "jni", - "raw-window-handle 0.6.1", + "raw-window-handle 0.6.2", "serde", "serde_json", "tauri-utils", @@ -3177,7 +3255,7 @@ dependencies = [ "jni", "log", "percent-encoding", - "raw-window-handle 0.6.1", + "raw-window-handle 0.6.2", "softbuffer", "tao", "tauri-runtime", @@ -3198,6 +3276,7 @@ dependencies = [ "serde", "serde_json", "specta", + "specta-jsdoc", "specta-typescript", "specta-util", "tauri", @@ -3212,6 +3291,7 @@ dependencies = [ "serde", "serde_json", "specta", + "specta-jsdoc", "specta-typescript", "tauri", "tauri-build", @@ -3325,9 +3405,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", @@ -3335,12 +3415,14 @@ dependencies = [ [[package]] name = "time" -version = "0.3.29" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", - "itoa 1.0.9", + "itoa 1.0.11", + "num-conv", + "powerfmt", "serde", "time-core", "time-macros", @@ -3354,18 +3436,19 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -3378,32 +3461,30 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.32.0" +version = "1.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "pin-project-lite", "socket2", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-util" -version = "0.7.9" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -3445,7 +3526,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.3.0", "serde", "serde_spanned", "toml_datetime", @@ -3458,7 +3539,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.3.0", "serde", "serde_spanned", "toml_datetime", @@ -3478,7 +3559,6 @@ dependencies = [ "tokio", "tower-layer", "tower-service", - "tracing", ] [[package]] @@ -3495,12 +3575,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", - "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -3508,9 +3586,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", @@ -3519,9 +3597,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -3529,20 +3607,20 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -3558,9 +3636,9 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b27516dfcfa22a9faaf192283a122bfbede38c1e59ef194e3c4db6549b419c0" +checksum = "3ad8319cca93189ea9ab1b290de0595960529750b6b8b501a399ed1ec3775d60" dependencies = [ "cocoa", "core-graphics", @@ -3576,20 +3654,11 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "treediff" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52984d277bdf2a751072b5df30ec0377febdb02f7696d64c2d7d54630bac4303" -dependencies = [ - "serde_json", -] - [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typeid" @@ -3646,9 +3715,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -3658,9 +3727,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] @@ -3673,9 +3742,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "url" -version = "2.4.1" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -3704,11 +3773,11 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "uuid" -version = "1.4.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.15", ] [[package]] @@ -3719,15 +3788,15 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "version-compare" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vswhom" @@ -3751,9 +3820,9 @@ dependencies = [ [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -3782,9 +3851,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3792,9 +3861,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", @@ -3807,9 +3876,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -3819,9 +3888,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3829,9 +3898,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", @@ -3842,9 +3911,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-streams" @@ -3859,22 +3928,11 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wayland-sys" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af" -dependencies = [ - "dlib", - "log", - "pkg-config", -] - [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -3933,7 +3991,7 @@ dependencies = [ "webview2-com-macros", "webview2-com-sys", "windows 0.57.0", - "windows-core", + "windows-core 0.57.0", "windows-implement", "windows-interface", ] @@ -3957,7 +4015,7 @@ checksum = "c76d5b77320ff155660be1df3e6588bc85c75f1a9feef938cc4dc4dd60d1d7cf" dependencies = [ "thiserror", "windows 0.57.0", - "windows-core", + "windows-core 0.57.0", ] [[package]] @@ -3978,11 +4036,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -3999,7 +4057,7 @@ checksum = "33082acd404763b315866e14a0d5193f3422c81086657583937a750cdd3ec340" dependencies = [ "cocoa", "objc", - "raw-window-handle 0.6.1", + "raw-window-handle 0.6.2", "windows-sys 0.52.0", "windows-version", ] @@ -4019,8 +4077,17 @@ version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" dependencies = [ - "windows-core", - "windows-targets 0.52.5", + "windows-core 0.57.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -4032,7 +4099,7 @@ dependencies = [ "windows-implement", "windows-interface", "windows-result", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -4059,11 +4126,11 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "749f0da9cc72d82e600d8d2e44cadd0b9eedb9038f71a1c58556ac1c5791813b" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -4090,7 +4157,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -4125,18 +4192,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -4145,7 +4212,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6998aa457c9ba8ff2fb9f13e9d2a930dabcea28f1d0ab94d687d8b3654844515" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -4162,9 +4229,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -4180,9 +4247,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -4198,15 +4265,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -4222,9 +4289,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -4240,9 +4307,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -4258,9 +4325,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -4276,29 +4343,19 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.15" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "937f3df7948156640f46aacef17a70db0de5917bda9c92b0f751f3a955b588fc" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "winreg" version = "0.52.0" @@ -4315,7 +4372,7 @@ version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b00c945786b02d7805d09a969fa36d0eee4e0bd4fb3ec2a79d2bf45a1b44cd" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "block", "cocoa", "core-graphics", @@ -4337,7 +4394,7 @@ dependencies = [ "objc_id", "once_cell", "percent-encoding", - "raw-window-handle 0.6.1", + "raw-window-handle 0.6.2", "sha2", "soup3", "tao-macros", @@ -4346,7 +4403,7 @@ dependencies = [ "webkit2gtk-sys", "webview2-com", "windows 0.57.0", - "windows-core", + "windows-core 0.57.0", "windows-version", "x11-dl", ] @@ -4371,3 +4428,24 @@ dependencies = [ "once_cell", "pkg-config", ] + +[[package]] +name = "zerocopy" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] diff --git a/Cargo.toml b/Cargo.toml index beeeabf..0a8f34d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ rustdoc-args = ["--cfg", "docsrs"] [features] default = [] derive = ["dep:tauri-specta-macros"] -javascript = ["dep:specta-typescript"] +javascript = ["dep:specta-jsdoc"] typescript = ["dep:specta-typescript"] # TODO: https://github.com/tauri-apps/tauri/pull/10435 @@ -33,6 +33,7 @@ workspace = true # Public specta = { workspace = true, features = ["function"] } specta-typescript = { workspace = true, optional = true } +specta-jsdoc = { workspace = true, optional = true } specta-util = { workspace = true } tauri-specta-macros = { version = "=2.0.0-rc.5", optional = true, path = "./macros" } serde = "1" @@ -69,6 +70,7 @@ tauri = { version = "=2.0.0-beta.25" } specta = { version = "=2.0.0-rc.16" } specta-util = { version = "0.0.3" } specta-typescript = { version = "0.0.3" } +specta-jsdoc = { version = "0.0.3" } [patch.crates-io] # tauri = { git = "https://github.com/oscartbeaumont/tauri.git", rev = "ddc64b706a7f2db271d40e9b216187b1aa153efa" } @@ -81,3 +83,4 @@ specta-typescript = { version = "0.0.3" } specta = { path = "../specta/specta" } specta-util = { path = "../specta/specta-util" } specta-typescript = { path = "../specta/specta-typescript" } +specta-jsdoc = { path = "../specta/specta-jsdoc" } \ No newline at end of file diff --git a/examples/app/src-tauri/Cargo.toml b/examples/app/src-tauri/Cargo.toml index bcf94e7..a856e18 100644 --- a/examples/app/src-tauri/Cargo.toml +++ b/examples/app/src-tauri/Cargo.toml @@ -19,6 +19,7 @@ serde = { version = "1.0", features = ["derive"] } tauri = { workspace = true, features = [] } tauri-specta = { path = "../../../", features = ["derive", "typescript", "javascript"] } specta-typescript = { workspace = true } +specta-jsdoc = { workspace = true } tauri-plugin-os = "^2.0.0-beta.3" thiserror = "1" diff --git a/examples/app/src-tauri/src/main.rs b/examples/app/src-tauri/src/main.rs index 072f07f..c6cc4bb 100644 --- a/examples/app/src-tauri/src/main.rs +++ b/examples/app/src-tauri/src/main.rs @@ -133,11 +133,21 @@ fn main() { #[cfg(debug_assertions)] builder - .export_ts( + .export( Typescript::default() .formatter(specta_typescript::formatter::prettier) - .header("/* These are my Tauri Specta Bindings! */") - .path("../src/bindings.ts"), + .header("/* eslint-disable */"), + "../src/bindings.ts", + ) + .expect("Failed to export typescript bindings"); + + #[cfg(debug_assertions)] + builder + .export( + specta_jsdoc::JSDoc::default() + .formatter(specta_typescript::formatter::prettier) + .header("/* eslint-disable */"), + "../src/bindings-jsdoc.js", ) .expect("Failed to export typescript bindings"); diff --git a/examples/app/src/bindings-jsdoc.js b/examples/app/src/bindings-jsdoc.js new file mode 100644 index 0000000..81b2b9e --- /dev/null +++ b/examples/app/src/bindings-jsdoc.js @@ -0,0 +1,176 @@ + /* eslint-disable */ + // This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually. + + /** user-defined commands **/ + + export const commands = { +/** + * HELLO + * WORLD + * !!!! + * @param { string } myName + * @returns { Promise } + */ +async helloWorld(myName) { +return await TAURI_INVOKE("hello_world", { myName }); +}, +/** + * @returns { Promise } + */ +async goodbyeWorld() { +return await TAURI_INVOKE("goodbye_world"); +}, +/** + * @returns { Promise> } + */ +async hasError() { +try { + return { status: "ok", data: await TAURI_INVOKE("has_error") }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e }; +} +}, +/** + * @deprecated This is a deprecated function + * @returns { Promise } + */ +async deprecated() { +await TAURI_INVOKE("deprecated"); +}, +/** + * @returns { Promise> } + */ +async typesafeErrorsUsingThiserror() { +try { + return { status: "ok", data: await TAURI_INVOKE("typesafe_errors_using_thiserror") }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e }; +} +}, +/** + * @returns { Promise> } + */ +async typesafeErrorsUsingThiserrorWithValue() { +try { + return { status: "ok", data: await TAURI_INVOKE("typesafe_errors_using_thiserror_with_value") }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e }; +} +} +} + + /** user-defined events **/ + + /** + * @type {typeof __makeEvents__<{ + * demoEvent: DemoEvent + * emptyEvent: EmptyEvent + * }>} + */ + + const __typedMakeEvents__ = __makeEvents__; + +export const events = __typedMakeEvents__({ +demoEvent: "demo-event", +emptyEvent: "empty-event" +}) + + /** user-defined constants **/ + + export const universalConstant = 42; + +/** user-defined types **/ + +/** + * @typedef { string } Custom + */ + +/** + * @typedef { string } DemoEvent + */ + +/** + * @typedef { null } EmptyEvent + */ + +/** + * @typedef { { type: "IoError" } | { type: "AnotherError"; data: string } } MyError + */ + +/** + * @typedef { { type: "IoError"; data: string } } MyError2 + */ + + +/** tauri-specta globals **/ + + import { + invoke as TAURI_INVOKE, + Channel as TAURI_CHANNEL, +} from "@tauri-apps/api/core"; +import * as TAURI_API_EVENT from "@tauri-apps/api/event"; + +/** @typedef {typeof import("@tauri-apps/api/window").WebviewWindowHandle} __WebviewWindowHandle__ */ + +/** + * @template T + * @typedef {{ + * listen: ( + * cb: TAURI_API_EVENT.EventCallback + * ) => ReturnType>; + * once: ( + * cb: TAURI_API_EVENT.EventCallback + * ) => ReturnType>; + * emit: T extends null + * ? (payload?: T) => ReturnType + * : (payload: T) => ReturnType; + * }} __EventObj__ + */ + +/** + * @template T,E + * @typedef { { status: "ok", data: T } | { status: "error", error: E } } Result + */ + +/** + * @template {Record} T + * @param {Record} mappings + * @returns {{ + * [K in keyof T]: __EventObj__ & { + * (handle: __WebviewWindowHandle__): __EventObj__; + * }; + * }} + */ +function __makeEvents__(mappings) { + return new Proxy( + {}, + { + get: (_, event) => { + const name = mappings[event]; + + return new Proxy(() => {}, { + apply: (_, __, [window]) => ({ + listen: (arg) => window.listen(name, arg), + once: (arg) => window.once(name, arg), + emit: (arg) => window.emit(name, arg), + }), + get: (_, command) => { + switch (command) { + case "listen": + return (arg) => TAURI_API_EVENT.listen(name, arg); + case "once": + return (arg) => TAURI_API_EVENT.once(name, arg); + case "emit": + return (arg) => TAURI_API_EVENT.emit(name, arg); + } + }, + }); + }, + }, + ); +} + + \ No newline at end of file diff --git a/examples/app/src/bindings.ts b/examples/app/src/bindings.ts index 9fe4f7f..8e189c8 100644 --- a/examples/app/src/bindings.ts +++ b/examples/app/src/bindings.ts @@ -1,4 +1,4 @@ -/* These are my Tauri Specta Bindings! */ + /* eslint-disable */ // This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually. /** user-defined commands **/ @@ -57,13 +57,15 @@ demoEvent: "demo-event", emptyEvent: "empty-event" }) - /** user-defined statics **/ + /** user-defined constants **/ - + export const universalConstant = 42 as const; /** user-defined types **/ export type Custom = string +export type DemoEvent = string +export type EmptyEvent = null export type MyError = { type: "IoError" } | { type: "AnotherError"; data: string } export type MyError2 = { type: "IoError"; data: string } diff --git a/examples/app/src/main.ts b/examples/app/src/main.ts index 8123537..eecaaf8 100644 --- a/examples/app/src/main.ts +++ b/examples/app/src/main.ts @@ -1,5 +1,6 @@ import { getCurrentWebview } from "@tauri-apps/api/webview"; import { commands, events } from "./bindings"; +// import { commands, events } from "./bindings-jsdoc.js"; const appWindow = getCurrentWebview(); diff --git a/examples/app/tsconfig.json b/examples/app/tsconfig.json index 43d4bc7..3063e37 100644 --- a/examples/app/tsconfig.json +++ b/examples/app/tsconfig.json @@ -10,6 +10,7 @@ "esModuleInterop": true, "types": ["vite/client"], "noEmit": true, + "allowJs": true, "noUnusedLocals": true, "noUnusedParameters": true, "noImplicitReturns": true diff --git a/examples/custom-plugin/plugin/src/lib.rs b/examples/custom-plugin/plugin/src/lib.rs index 560bf35..3b13ed4 100644 --- a/examples/custom-plugin/plugin/src/lib.rs +++ b/examples/custom-plugin/plugin/src/lib.rs @@ -16,8 +16,8 @@ struct RandomNumber(i32); const PLUGIN_NAME: &str = "specta-example"; -fn builder() -> tauri_specta::Builder2 { - tauri_specta::Builder2::new() +fn builder() -> tauri_specta::Builder { + tauri_specta::Builder::new() .plugin_name(PLUGIN_NAME) .commands(collect_commands![add_numbers]) .events(collect_events![RandomNumber]) @@ -48,11 +48,11 @@ mod test { #[test] fn export_types() { - builder() - .export_ts( + builder::() + .export( specta_typescript::Typescript::default() - .formatter(specta_typescript::formatter::prettier) - .path("./bindings.ts"), + .formatter(specta_typescript::formatter::prettier), + "./bindings.ts", ) .expect("failed to export specta types"); } diff --git a/src/builder.rs b/src/builder.rs index 47ce622..f3e84ac 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,26 +1,63 @@ use std::{ borrow::Cow, - collections::HashMap, + collections::{BTreeMap, BTreeSet, HashMap}, fs::{self, File}, io::Write, + path::Path, }; use serde::Serialize; -use specta::{datatype::DataType, NamedType, Type, TypeMap}; -use specta_typescript::Typescript; -use tauri::{ipc::Invoke, App, Runtime}; - -use crate::{ - internal::{Commands, Events}, - EventRegistry, +use specta::{ + datatype::{DataType, Function}, + NamedType, SpectaID, Type, TypeMap, }; - -pub struct Builder { +use tauri::{ipc::Invoke, Manager, Runtime}; + +use crate::{Commands, EventRegistry, Events, LanguageExt}; + +/// Builder for configuring Tauri Specta in your application. +/// +/// # Example +/// +/// You can copy the following code into your `main.rs` file to get started with Tauri Specta. +/// +/// This will automatically export a [Typescript](https://www.typescriptlang.org) file containing bindings for all of your commands and events. +/// +/// You can extend this example by calling other methods on the builder to configure your application further. +/// +/// ```rust +/// let mut builder = ::new() +/// .commands(tauri_specta::collect_commands![]); +/// +/// #[cfg(debug_assertions)] +/// builder +/// .export(Typescript::default().path("../src/bindings.ts")) +/// .expect("Failed to export typescript bindings"); +/// +/// tauri::Builder::default() +/// .invoke_handler(builder.invoke_handler()) // < Required for commands to work +/// .setup(move |app| { +/// builder.mount_events(app); // < Required for events to work +/// +/// Ok(()) +/// }) +/// .run(tauri::generate_context!()) +/// .expect("error while running tauri application"); +/// ``` +/// +/// # Exporting using JSDoc +/// +/// ```rs +/// # TODO +/// ``` +pub struct Builder { plugin_name: Option<&'static str>, commands: Commands, - events: Events, + command_types: Vec, + events: BTreeMap<&'static str, DataType>, + event_sids: BTreeSet, types: TypeMap, - constants: HashMap, (DataType, serde_json::Value)>, + constants: HashMap, serde_json::Value>, } impl Default for Builder { @@ -28,7 +65,9 @@ impl Default for Builder { Self { plugin_name: None, commands: Commands::default(), - events: Events::default(), + command_types: Default::default(), + events: Default::default(), + event_sids: Default::default(), types: TypeMap::default(), constants: HashMap::default(), } @@ -54,15 +93,39 @@ impl Builder { /// Register commands with the builder. /// /// WARNING: This method will overwrite any previously registered commands. - pub fn commands(self, commands: Commands) -> Self { - Self { commands, ..self } + pub fn commands(mut self, commands: Commands) -> Self { + Self { + command_types: (commands.1)(&mut self.types), + commands, + ..self + } } /// Register events with the builder. /// /// WARNING: This method will overwrite any previously registered events. - pub fn events(self, events: Events) -> Self { - Self { events, ..self } + pub fn events(mut self, events: Events) -> Self { + let mut event_sids = BTreeSet::new(); + let events = events + .0 + .iter() + .map(|(k, build)| { + let (sid, dt) = build(&mut self.types); + event_sids.insert(sid); + (*k, dt) + }) + .collect(); + + // TODO: This must remain feature gated until this PR is merged and released: https://github.com/tauri-apps/tauri/pull/10435 + #[cfg(feature = "UNSTABLE_channels")] + self.types + .remove( as specta::NamedType>::sid()); + + Self { + events, + event_sids, + ..self + } } /// Export a new type with the frontend. /// @@ -78,9 +141,10 @@ impl Builder { /// This is useful to share application-wide constants or expose data which is generated by Rust. #[track_caller] pub fn constant(mut self, k: impl Into>, v: T) -> Self { - let v = serde_json::to_value(v).expect("Tauri Specta failed to serialize constant"); - self.constants - .insert(k.into(), (T::reference(&mut self.types, &[]).inner, v)); + self.constants.insert( + k.into(), + serde_json::to_value(v).expect("Tauri Specta failed to serialize constant"), + ); self } @@ -95,69 +159,55 @@ impl Builder { } /// Mount all of the events in the builder onto a Tauri app. - pub fn mount_events(&self, app: &mut App) { - let registry = EventRegistry::get_or_manage(app); - registry.register_collection(self.events.0.clone(), None); + pub fn mount_events(&self, handle: &impl Manager) { + if !handle.manage(EventRegistry { + plugin_name: self.plugin_name, + events: self.event_sids.clone(), + }) { + panic!("Attempted to mount Tauri Specta EventRegistry more than once. Did you call `Builder::mount_events` more than once?"); + } + } + + /// Export the bindings to a string. + /// + /// # Example + /// ```rust + /// # TODO + /// ``` + pub fn export_str(&self, language: L) -> Result { + // TODO: Handle duplicate type names + // TODO: Serde checking + + language.render(&crate::Configuration { + // TODO: Don't clone stuff + commands: self.command_types.clone(), + events: self.events.clone(), + type_map: self.types.clone(), + constants: self.constants.clone(), + plugin_name: self.plugin_name, + }) } - // TODO: Restructure to use a `LanguageExt` trait system - - // TODO: Make this not-mutable - pub fn export_ts( - &mut self, - language: Typescript, - ) -> Result<(), specta_typescript::ExportError> { - if let Some(path) = &language.path { - if let Some(export_dir) = path.parent() { - fs::create_dir_all(export_dir)?; - } - - let mut file = File::create(&path)?; - - // TODO: Maybe do this in the `commands` to make sure this method can take `&self` - let commands = (self.commands.1)(&mut self.types); - - // TODO: This is required for channels to work correctly. - // This should be unfeature gated once the upstream fix is merged: https://github.com/tauri-apps/tauri/pull/10435 - // #[cfg(feature = "UNSTABLE_channels")] - // self.types - // .remove( as specta::NamedType>::sid()); - - let dependant_types = self - .types - .iter() - .map({ - let language = &language; - |(_sid, ndt)| { - specta_typescript::export_named_datatype(language, ndt, &self.types) - } - }) - .collect::, _>>() - .map(|v| v.join("\n"))?; - - let rendered = crate::js_ts::render_all_parts::( - &language, - &crate::Configuration { - commands, - // TODO: Don't clone stuff - events: self.events.1.clone(), - type_map: self.types.clone(), - constants: (), - plugin_name: self.plugin_name, - }, - &dependant_types, - crate::ts::GLOBALS, - )?; - - write!(file, "{}", format!("{}\n{rendered}", language.header))?; - - language.run_format(path.clone()).ok(); + /// Export the bindings to a file. + /// + /// # Example + /// ```rust + /// # TODO + /// ``` + pub fn export( + &self, + language: L, + path: impl AsRef, + ) -> Result<(), L::Error> { + let path = path.as_ref(); + if let Some(export_dir) = path.parent() { + fs::create_dir_all(export_dir)?; } - Ok(()) - } + let mut file = File::create(&path)?; + write!(file, "{}", self.export_str(&language)?)?; + language.format(path).ok(); // TODO: Error handling - pub fn export_js_doc(&self, language: Typescript) { - todo!(); + Ok(()) } } diff --git a/src/event.rs b/src/event.rs index 967311e..a67a175 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,69 +1,34 @@ -use std::{ - collections::{BTreeMap, BTreeSet}, - sync::RwLock, -}; +use std::{borrow::Cow, collections::BTreeSet}; use serde::{de::DeserializeOwned, Serialize}; -use specta::{DataType, NamedType, SpectaID}; +use specta::{NamedType, SpectaID}; use tauri::{Emitter, EventId, EventTarget, Listener, Manager, Runtime}; -use crate::apply_as_prefix; +use crate::{apply_as_prefix, ItemType}; -#[derive(Clone, Copy)] -pub struct EventRegistryMeta { - plugin_name: Option<&'static str>, +/// A struct for managing events that is put into Tauri's state. +pub(crate) struct EventRegistry { + pub(crate) plugin_name: Option<&'static str>, + pub(crate) events: BTreeSet, } -impl EventRegistryMeta { - fn wrap_with_plugin(&self, input: &str) -> String { - self.plugin_name - .as_ref() - .map(|n| apply_as_prefix(n, input, crate::ItemType::Event)) - .unwrap_or_else(|| input.to_string()) - } -} - -#[derive(Default, Clone)] -pub struct EventCollection(pub(crate) BTreeSet, BTreeSet<&'static str>); - -impl EventCollection { - pub fn register(&mut self) { - if !self.0.insert(E::sid()) { - panic!("Event {} registered twice!", E::NAME) - } - - if !self.1.insert(E::NAME) { - panic!("Another event with name {} is already registered!", E::NAME) - } - } -} - -// TODO: Should this be pub -#[derive(Default)] -pub(crate) struct EventRegistry(pub(crate) RwLock>); - impl EventRegistry { - pub fn register_collection( - &self, - collection: EventCollection, - plugin_name: Option<&'static str>, - ) { - let mut registry = self.0.write().expect("Failed to write EventRegistry"); - - registry.extend( - collection - .0 - .into_iter() - .map(|sid| (sid, EventRegistryMeta { plugin_name })), - ); - } - - pub fn get_or_manage(handle: &impl Manager) -> tauri::State<'_, Self> { - if handle.try_state::().is_none() { - handle.manage(Self::default()); - } - - handle.state::() + /// gets the name of the event (taking into account plugin prefixes) and ensuring it was correctly mounted to the current app. + pub fn get_event_name( + handle: &impl Manager, + name: &'static str, + ) -> Cow<'static, str> { + let this = handle.try_state::().expect( + "EventRegistry not found in Tauri state - Did you forget to call Builder::mount_events?", + ).inner(); + + this.events + .get(&E::sid()) + .unwrap_or_else(|| panic!("Event {name} not found in registry!")); + + this.plugin_name + .map(|n| apply_as_prefix(n, name, ItemType::Event).into()) + .unwrap_or_else(|| name.into()) } } @@ -72,22 +37,6 @@ pub struct TypedEvent { pub payload: T, } -fn get_meta_from_registry( - sid: SpectaID, - name: &str, - handle: &impl Manager, -) -> EventRegistryMeta { - handle.try_state::().expect( - "EventRegistry not found in Tauri state - Did you forget to call Exporter::with_events?", - ) - .0 - .read() - .expect("Failed to read EventRegistry") - .get(&sid) - .copied() - .unwrap_or_else(|| panic!("Event {name} not found in registry!")) -} - macro_rules! make_handler { ($handler:ident) => { move |event| { @@ -100,12 +49,6 @@ macro_rules! make_handler { }; } -macro_rules! get_meta { - ($handle:ident) => { - get_meta_from_registry(Self::sid(), Self::NAME, $handle) - }; -} - pub trait Event: NamedType { const NAME: &'static str; @@ -115,7 +58,7 @@ pub trait Event: NamedType { Self: DeserializeOwned, { handle.listen( - get_meta!(handle).wrap_with_plugin(Self::NAME), + EventRegistry::get_event_name::(handle, Self::NAME), make_handler!(handler), ) } @@ -126,7 +69,7 @@ pub trait Event: NamedType { Self: DeserializeOwned, { handle.listen_any( - get_meta!(handle).wrap_with_plugin(Self::NAME), + EventRegistry::get_event_name::(handle, Self::NAME), make_handler!(handler), ) } @@ -137,7 +80,7 @@ pub trait Event: NamedType { Self: DeserializeOwned, { handle.once( - get_meta!(handle).wrap_with_plugin(Self::NAME), + EventRegistry::get_event_name::(handle, Self::NAME), make_handler!(handler), ) } @@ -148,7 +91,7 @@ pub trait Event: NamedType { Self: DeserializeOwned, { handle.once_any( - get_meta!(handle).wrap_with_plugin(Self::NAME), + EventRegistry::get_event_name::(handle, Self::NAME), make_handler!(handler), ) } @@ -157,7 +100,10 @@ pub trait Event: NamedType { where Self: Serialize + Clone, { - handle.emit(&get_meta!(handle).wrap_with_plugin(Self::NAME), self) + handle.emit( + &EventRegistry::get_event_name::(handle, Self::NAME), + self, + ) } fn emit_to + Manager>( @@ -168,7 +114,11 @@ pub trait Event: NamedType { where Self: Serialize + Clone, { - handle.emit_to(label, &get_meta!(handle).wrap_with_plugin(Self::NAME), self) + handle.emit_to( + label, + &EventRegistry::get_event_name::(handle, Self::NAME), + self, + ) } fn emit_filter + Manager>( @@ -181,18 +131,9 @@ pub trait Event: NamedType { Self: Serialize + Clone, { handle.emit_filter( - &get_meta!(handle).wrap_with_plugin(Self::NAME), + &EventRegistry::get_event_name::(handle, Self::NAME), self, filter, ) } } - -#[derive(Debug, Clone)] -pub struct EventDataType { - pub name: &'static str, - pub typ: DataType, -} - -#[doc(hidden)] -pub type CollectEventsTuple = (EventCollection, Vec, specta::TypeMap); diff --git a/src/internal.rs b/src/internal.rs deleted file mode 100644 index 7c646b7..0000000 --- a/src/internal.rs +++ /dev/null @@ -1,51 +0,0 @@ -//! Internal logic for Tauri Specta. -//! Nothing in this module has to conform to semver so it should not be used outside of this crate. -//! It has to be public so macro's can access it. - -use std::sync::Arc; - -use specta::{datatype, TypeMap}; -use tauri::{ipc::Invoke, Runtime}; - -use crate::{EventCollection, EventDataType}; - -type SpectaCollectTypes = fn(&mut TypeMap) -> Vec; - -/// A wrapper around the output of the `collect_commands` macro. -/// This acts to seal the implementation details of the macro. -pub struct Commands( - // Bounds copied from `tauri::Builder::invoke_handler` - pub(crate) Arc) -> bool + Send + Sync + 'static>, - pub(crate) SpectaCollectTypes, -); - -impl Default for Commands { - fn default() -> Self { - Self( - Arc::new(tauri::generate_handler![]), - ::specta::function::collect_functions![], - ) - } -} - -/// A wrapper around the output of the `collect_commands` macro. -/// This acts to seal the implementation details of the macro. -#[derive(Default)] -pub struct Events( - pub(crate) EventCollection, - pub(crate) Vec, - pub(crate) TypeMap, -); - -/// called by `collect_commands` to construct `Commands` -pub fn command(f: F, types: SpectaCollectTypes) -> Commands -where - F: Fn(Invoke) -> bool + Send + Sync + 'static, -{ - Commands(Arc::new(f), types) -} - -/// called by `collect_events` to construct `Events` -pub fn events(a: EventCollection, b: Vec, c: TypeMap) -> Events { - Events(a, b, c) -} diff --git a/src/js.rs b/src/js.rs deleted file mode 100644 index 9c67140..0000000 --- a/src/js.rs +++ /dev/null @@ -1,144 +0,0 @@ -// use crate::*; -// use heck::ToLowerCamelCase; -// use indoc::formatdoc; -// use specta::{datatype, datatype::FunctionResultVariant}; -// use specta_typescript as ts; -// use specta_typescript::js_doc; -// use tauri::Runtime; - -// /// Implements [`ExportLanguage`] for JS exporting -// pub struct Language; - -// pub fn builder() -> Builder, NoEvents> { -// Builder::default() -// } - -// pub const GLOBALS: &str = include_str!("./globals.js"); - -// type Config = specta_typescript::Typescript; - -// pub type ExportConfig = crate::ExportConfig; - -// impl ExportLanguage for Language { -// type Config = Config; -// type Error = ts::ExportError; - -// fn run_format(path: PathBuf, cfg: &ExportConfig) { -// cfg.inner.run_format(path).ok(); -// } - -// /// Renders a collection of [`FunctionDataType`] into a JavaScript string. -// fn render_commands( -// commands: &[datatype::Function], -// type_map: &TypeMap, -// cfg: &ExportConfig, -// ) -> Result { -// let commands = commands -// .iter() -// .map(|function| { -// let jsdoc = { -// let ret_type = js_ts::handle_result(function, type_map, cfg)?; - -// let mut builder = js_doc::Builder::default(); - -// if let Some(d) = function.deprecated() { -// builder.push_deprecated(d); -// } - -// if !function.docs().is_empty() { -// builder.extend(function.docs().split("\n")); -// } - -// builder.extend(function.args().flat_map(|(name, typ)| { -// ts::datatype( -// &cfg.inner, -// &FunctionResultVariant::Value(typ.clone()), -// type_map, -// ) -// .map(|typ| { -// let name = name.to_lower_camel_case(); - -// format!("@param {{ {typ} }} {name}") -// }) -// })); -// builder.push(&format!("@returns {{ Promise<{ret_type}> }}")); - -// builder.build() -// }; - -// Ok(js_ts::function( -// &jsdoc, -// &function.name().to_lower_camel_case(), -// // TODO: Don't `collect` the whole thing -// &js_ts::arg_names(&function.args().cloned().collect::>()), -// None, -// &js_ts::command_body(cfg, function, false), -// )) -// }) -// .collect::, Self::Error>>()? -// .join(",\n"); - -// Ok(formatdoc! { -// r#" -// export const commands = {{ -// {commands} -// }}"# -// }) -// } - -// fn render_events( -// events: &[EventDataType], -// type_map: &TypeMap, -// cfg: &ExportConfig, -// ) -> Result { -// if events.is_empty() { -// return Ok(Default::default()); -// } - -// let (events_types, events_map) = js_ts::events_data(events, cfg, type_map)?; - -// let events = { -// let mut builder = js_doc::Builder::default(); - -// builder.push("@type {typeof __makeEvents__<{"); -// builder.extend(events_types); -// builder.push("}>}"); - -// builder.build() -// }; - -// Ok(formatdoc! { -// r#" -// {events} -// const __typedMakeEvents__ = __makeEvents__; - -// export const events = __typedMakeEvents__({{ -// {events_map} -// }})"# -// }) -// } - -// fn render( -// commands: &[datatype::Function], -// events: &[EventDataType], -// type_map: &TypeMap, -// statics: &StaticCollection, -// cfg: &ExportConfig, -// ) -> Result { -// let dependant_types = type_map -// .iter() -// .map(|(_sid, ndt)| js_doc::typedef_named_datatype(&cfg.inner, ndt, type_map)) -// .collect::, _>>() -// .map(|v| v.join("\n"))?; - -// js_ts::render_all_parts::( -// commands, -// events, -// type_map, -// statics, -// cfg, -// &dependant_types, -// GLOBALS, -// ) -// } -// } diff --git a/src/lang.rs b/src/lang.rs new file mode 100644 index 0000000..cd2cba6 --- /dev/null +++ b/src/lang.rs @@ -0,0 +1,8 @@ +#[cfg(feature = "javascript")] +mod js; + +#[cfg(feature = "typescript")] +mod ts; + +#[cfg(any(feature = "javascript", feature = "typescript"))] +pub(crate) mod js_ts; diff --git a/src/globals.js b/src/lang/globals.js similarity index 100% rename from src/globals.js rename to src/lang/globals.js diff --git a/src/globals.ts b/src/lang/globals.ts similarity index 100% rename from src/globals.ts rename to src/lang/globals.ts diff --git a/src/lang/js.rs b/src/lang/js.rs new file mode 100644 index 0000000..8569753 --- /dev/null +++ b/src/lang/js.rs @@ -0,0 +1,107 @@ +use heck::ToLowerCamelCase; +use indoc::formatdoc; +use specta::datatype::FunctionResultVariant; +use specta_typescript::js_doc; + +use crate::{Configuration, LanguageExt}; + +use super::js_ts; + +const GLOBALS: &str = include_str!("./globals.js"); + +impl LanguageExt for specta_jsdoc::JSDoc { + fn render_commands(&self, cfg: &Configuration) -> Result { + let commands = cfg + .commands + .iter() + .map(|function| { + let jsdoc = { + let ret_type = js_ts::handle_result(function, &cfg.type_map, &self.0)?; + + let mut builder = js_doc::Builder::default(); + + if let Some(d) = function.deprecated() { + builder.push_deprecated(d); + } + + if !function.docs().is_empty() { + builder.extend(function.docs().split("\n")); + } + + builder.extend(function.args().flat_map(|(name, typ)| { + specta_typescript::datatype( + &self.0, + &FunctionResultVariant::Value(typ.clone()), + &cfg.type_map, + ) + .map(|typ| { + let name = name.to_lower_camel_case(); + + format!("@param {{ {typ} }} {name}") + }) + })); + builder.push(&format!("@returns {{ Promise<{ret_type}> }}")); + + builder.build() + }; + + Ok(js_ts::function( + &jsdoc, + &function.name().to_lower_camel_case(), + // TODO: Don't `collect` the whole thing + &js_ts::arg_names(&function.args().cloned().collect::>()), + None, + &js_ts::command_body(&cfg.plugin_name, function, false), + )) + }) + .collect::, Self::Error>>()? + .join(",\n"); + + Ok(formatdoc! { + r#" + export const commands = {{ + {commands} + }}"# + }) + } + + fn render_events(&self, cfg: &Configuration) -> Result { + if cfg.events.is_empty() { + return Ok(Default::default()); + } + + let (events_types, events_map) = + js_ts::events_data(&cfg.events, &self.0, &cfg.plugin_name, &cfg.type_map)?; + + let events = { + let mut builder = js_doc::Builder::default(); + + builder.push("@type {typeof __makeEvents__<{"); + builder.extend(events_types); + builder.push("}>}"); + + builder.build() + }; + + Ok(formatdoc! { + r#" + {events} + const __typedMakeEvents__ = __makeEvents__; + + export const events = __typedMakeEvents__({{ + {events_map} + }})"# + }) + } + + fn render(&self, cfg: &Configuration) -> Result { + let dependant_types = cfg + .type_map + .iter() + .map(|(_sid, ndt)| js_doc::typedef_named_datatype(&self.0, ndt, &cfg.type_map)) + .collect::, _>>() + .map(|v| v.join("\n"))?; + + js_ts::render_all_parts::(self, cfg, &dependant_types, GLOBALS, &self.0.header) + } +} diff --git a/src/js_ts.rs b/src/lang/js_ts.rs similarity index 69% rename from src/js_ts.rs rename to src/lang/js_ts.rs index fef976b..1cfb3c7 100644 --- a/src/js_ts.rs +++ b/src/lang/js_ts.rs @@ -1,4 +1,8 @@ -use std::borrow::Cow; +//! Core utilities for the JS & TS language exporters. +//! +//! Typescript is a superset of Javascript so they share a lot of logic. + +use std::{any::TypeId, borrow::Cow, collections::BTreeMap}; use heck::ToLowerCamelCase; use indoc::formatdoc; @@ -6,56 +10,56 @@ use specta::{ datatype::{self, DataType, FunctionResultVariant}, TypeMap, }; +use specta_jsdoc::JSDoc; use specta_typescript::{self as ts}; use specta_typescript::{ExportError, Typescript}; -use crate::{apply_as_prefix, Configuration, EventDataType, ItemType, LanguageExt}; +use crate::{apply_as_prefix, Configuration, ItemType, LanguageExt}; const DO_NOT_EDIT: &str = "// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually."; -// TODO: Remove this -const CRINGE_ESLINT_DISABLE: &str = "/* eslint-disable */ -"; - -// TODO: Can we avoid hardcoding error type??? -pub fn render_all_parts>( - language: &T, +pub fn render_all_parts( + language: &L, cfg: &Configuration, dependant_types: &str, globals: &str, -) -> Result { + header: &str, +) -> Result { let commands = language.render_commands(&cfg)?; let events = language.render_events(&cfg)?; // TODO: Bring this back - // let statics = statics - // .statics - // .iter() - // .map(|(name, value)| { - // let mut as_const = None; - // match &value { - // serde_json::Value::Null => {} - // serde_json::Value::Bool(_) - // | serde_json::Value::Number(_) - // | serde_json::Value::String(_) - // | serde_json::Value::Array(_) - // | serde_json::Value::Object(_) => as_const = Some(" as const"), - // } - - // format!( - // "export const {name} = {}{};", - // serde_json::to_string(&value) - // .expect("failed to serialize from `serde_json::Value`"), - // as_const.unwrap_or("") - // ) - // }) - // .collect::>() - // .join("\n"); - - let statics = ""; // TODO + let constants = cfg + .constants + .iter() + .map(|(name, value)| { + let mut as_const = None; + match &value { + serde_json::Value::Null => {} + serde_json::Value::Bool(_) + | serde_json::Value::Number(_) + | serde_json::Value::String(_) + | serde_json::Value::Array(_) + | serde_json::Value::Object(_) => as_const = Some(" as const"), + } + + if TypeId::of::() == TypeId::of::() { + as_const = None; + } + + format!( + "export const {name} = {}{};", + serde_json::to_string(&value) + .expect("failed to serialize from `serde_json::Value`"), + as_const.unwrap_or("") + ) + }) + .collect::>() + .join("\n"); Ok(formatdoc! { r#" + {header} {DO_NOT_EDIT} /** user-defined commands **/ @@ -66,9 +70,9 @@ pub fn render_all_parts>( {events} - /** user-defined statics **/ + /** user-defined constants **/ - {statics} + {constants} /** user-defined types **/ @@ -186,15 +190,18 @@ pub fn command_body( ) } -pub fn events_map(events: &[EventDataType], plugin_name: &Option<&'static str>) -> String { +pub fn events_map( + events: &BTreeMap<&'static str, DataType>, + plugin_name: &Option<&'static str>, +) -> String { events .iter() - .map(|event| { + .map(|(name, ty)| { let name_str = plugin_name .as_ref() - .map(|n| apply_as_prefix(n, event.name, ItemType::Event)) - .unwrap_or_else(|| event.name.to_string()); - let name_camel = event.name.to_lower_camel_case(); + .map(|n| apply_as_prefix(n, name, ItemType::Event)) + .unwrap_or_else(|| name.to_string()); + let name_camel = name.to_lower_camel_case(); format!(r#"{name_camel}: "{name_str}""#) }) @@ -203,20 +210,16 @@ pub fn events_map(events: &[EventDataType], plugin_name: &Option<&'static str>) } pub fn events_types( - events: &[EventDataType], + events: &BTreeMap<&'static str, DataType>, cfg: &Typescript, type_map: &TypeMap, ) -> Result, ExportError> { events .iter() - .map(|event| { - let name_camel = event.name.to_lower_camel_case(); + .map(|(name, typ)| { + let name_camel = name.to_lower_camel_case(); - let typ = ts::datatype( - cfg, - &FunctionResultVariant::Value(event.typ.clone()), - type_map, - )?; + let typ = ts::datatype(cfg, &FunctionResultVariant::Value(typ.clone()), type_map)?; Ok(format!(r#"{name_camel}: {typ}"#)) }) @@ -224,7 +227,7 @@ pub fn events_types( } pub fn events_data( - events: &[EventDataType], + events: &BTreeMap<&'static str, DataType>, cfg: &Typescript, plugin_name: &Option<&'static str>, type_map: &TypeMap, diff --git a/src/ts.rs b/src/lang/ts.rs similarity index 95% rename from src/ts.rs rename to src/lang/ts.rs index 51ab21e..de331e3 100644 --- a/src/ts.rs +++ b/src/lang/ts.rs @@ -1,12 +1,11 @@ -use crate::{js_ts, Configuration, LanguageExt}; +use crate::{lang::js_ts, Configuration, LanguageExt}; use heck::ToLowerCamelCase; use indoc::formatdoc; use specta::datatype::FunctionResultVariant; use specta_typescript as ts; use specta_typescript::{js_doc, ExportError}; -// TODO: Make private -pub(crate) const GLOBALS: &str = include_str!("./globals.ts"); +const GLOBALS: &str = include_str!("./globals.ts"); impl LanguageExt for specta_typescript::Typescript { fn render_commands(&self, cfg: &Configuration) -> Result { @@ -88,6 +87,6 @@ impl LanguageExt for specta_typescript::Typescript { .collect::, _>>() .map(|v| v.join("\n"))?; - js_ts::render_all_parts::(self, cfg, &dependant_types, GLOBALS) + js_ts::render_all_parts::(self, cfg, &dependant_types, GLOBALS, &self.header) } } diff --git a/src/lib.rs b/src/lib.rs index 161e72e..f18d5fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,59 +114,97 @@ html_favicon_url = "https://github.com/oscartbeaumont/specta/raw/main/.github/logo-128.png" )] -use specta::{datatype, Language, TypeMap}; +use std::{ + borrow::Cow, + collections::{BTreeMap, HashMap}, + sync::Arc, +}; +use specta::{ + datatype::{self, DataType}, + Language, SpectaID, TypeMap, +}; + +use tauri::{ipc::Invoke, Runtime}; #[cfg(feature = "derive")] #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] pub use tauri_specta_macros::Event; mod builder; -#[doc(hidden)] -pub mod internal; +mod event; +mod lang; mod macros; pub use builder::Builder; +#[allow(unused)] +pub use lang::*; -/// The exporter for [Javascript](https://www.javascript.com). -#[cfg(feature = "javascript")] -#[cfg_attr(docsrs, doc(cfg(feature = "javascript")))] -pub mod js; - -/// The exporter for [TypeScript](https://www.typescriptlang.org). -#[cfg(feature = "typescript")] -#[cfg_attr(docsrs, doc(cfg(feature = "typescript")))] -pub mod ts; +// TODO: Probs drop +pub use event::*; -#[cfg(any(feature = "javascript", feature = "typescript"))] -mod js_ts; +/// A wrapper around the output of the `collect_commands` macro. +/// +/// This acts to seal the implementation details of the macro. +pub struct Commands( + // Bounds copied from `tauri::Builder::invoke_handler` + pub(crate) Arc) -> bool + Send + Sync + 'static>, + pub(crate) fn(&mut TypeMap) -> Vec, +); -mod event; +impl Default for Commands { + fn default() -> Self { + Self( + Arc::new(tauri::generate_handler![]), + ::specta::function::collect_functions![], + ) + } +} -// TODO: Probs drop -pub use event::*; +/// A wrapper around the output of the `collect_commands` macro. +/// +/// This acts to seal the implementation details of the macro. +#[derive(Default)] +pub struct Events(BTreeMap<&'static str, fn(&mut TypeMap) -> (SpectaID, DataType)>); #[derive(Debug, Clone)] #[non_exhaustive] pub struct Configuration { + plugin_name: Option<&'static str>, commands: Vec, - events: Vec, + events: BTreeMap<&'static str, DataType>, type_map: TypeMap, - constants: (), // TODO - plugin_name: Option<&'static str>, + constants: HashMap, serde_json::Value>, } +impl Configuration {} + pub trait LanguageExt: Language { fn render_commands(&self, cfg: &Configuration) -> Result; fn render_events(&self, cfg: &Configuration) -> Result; fn render(&self, cfg: &Configuration) -> Result; } +impl LanguageExt for &L { + fn render_commands(&self, cfg: &Configuration) -> Result { + (*self).render_commands(cfg) + } + + fn render_events(&self, cfg: &Configuration) -> Result { + (*self).render_events(cfg) + } + + fn render(&self, cfg: &Configuration) -> Result { + (*self).render(cfg) + } +} + // TODO: Remove this pub(crate) enum ItemType { Event, Command, } +// TODO: Move onto `Configuration` pub(crate) fn apply_as_prefix(plugin_name: &str, s: &str, item_type: ItemType) -> String { format!( "plugin:{}{}{}", @@ -178,3 +216,37 @@ pub(crate) fn apply_as_prefix(plugin_name: &str, s: &str, item_type: ItemType) - s, ) } + +#[doc(hidden)] +pub mod internal { + //! Internal logic for Tauri Specta. + //! Nothing in this module has to conform to semver so it should not be used outside of this crate. + //! It has to be public so macro's can access it. + + use specta::NamedType; + + use super::*; + + /// called by `collect_commands` to construct `Commands` + pub fn command( + f: F, + types: fn(&mut TypeMap) -> Vec, + ) -> Commands + where + F: Fn(Invoke) -> bool + Send + Sync + 'static, + { + Commands(Arc::new(f), types) + } + + /// called by `collect_events` to register events to an `Events` + pub fn register_event(Events(events): &mut Events) { + if events + .insert(E::NAME, |type_map| { + (E::sid(), E::reference(type_map, &[]).inner) + }) + .is_some() + { + panic!("Another event with name {} is already registered!", E::NAME) + } + } +} diff --git a/src/macros.rs b/src/macros.rs index eeff2b7..d2638a3 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -38,23 +38,8 @@ macro_rules! collect_commands { #[macro_export] macro_rules! collect_events { ($($event:path),* $(,)?) => {{ - // TODO: Cleanup the internals of this - - let mut collection: $crate::EventCollection = ::core::default::Default::default(); - - $(collection.register::<$event>();)* - - let mut type_map = Default::default(); - - let event_data_types = [$( - $crate::EventDataType { - name: <$event as $crate::Event>::NAME, - typ: <$event as ::specta::Type>::reference(&mut type_map, &[]).inner - } - ),*] - .into_iter() - .collect::>(); - - $crate::internal::events(collection, event_data_types, type_map) + let mut events: $crate::Events = ::core::default::Default::default(); + $($crate::internal::register_event::<$event>(&mut events);)* + events }}; } From 1693610dbc2e9d0a5f77a56728f5b3ecab6e2b39 Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Thu, 1 Aug 2024 15:44:43 +0800 Subject: [PATCH 8/9] Drop `indoc` & `specta-util` deps --- Cargo.lock | 16 --------- Cargo.toml | 4 --- examples/app/src/bindings-jsdoc.js | 39 +++++++++++---------- examples/app/src/bindings.ts | 32 ++++++++--------- src/lang/js.rs | 24 ++++++------- src/lang/js_ts.rs | 55 ++++++++++++++---------------- src/lang/ts.rs | 21 ++++++------ 7 files changed, 81 insertions(+), 110 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a0d04b1..71f2ff6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1362,12 +1362,6 @@ dependencies = [ "serde", ] -[[package]] -name = "indoc" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" - [[package]] name = "infer" version = "0.15.0" @@ -2891,14 +2885,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "specta-util" -version = "0.0.3" -dependencies = [ - "serde", - "specta", -] - [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -3272,13 +3258,11 @@ name = "tauri-specta" version = "2.0.0-rc.11" dependencies = [ "heck 0.5.0", - "indoc", "serde", "serde_json", "specta", "specta-jsdoc", "specta-typescript", - "specta-util", "tauri", "tauri-specta-macros", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index 0a8f34d..d73ba18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,6 @@ workspace = true specta = { workspace = true, features = ["function"] } specta-typescript = { workspace = true, optional = true } specta-jsdoc = { workspace = true, optional = true } -specta-util = { workspace = true } tauri-specta-macros = { version = "=2.0.0-rc.5", optional = true, path = "./macros" } serde = "1" serde_json = "1" @@ -43,7 +42,6 @@ tauri = { workspace = true, default-features = false, features = ["specta"] } # Private heck = "0.5.0" -indoc = "2.0.5" [workspace] members = [ @@ -68,7 +66,6 @@ panic_in_result_fn = { level = "warn", priority = -1 } [workspace.dependencies] tauri = { version = "=2.0.0-beta.25" } specta = { version = "=2.0.0-rc.16" } -specta-util = { version = "0.0.3" } specta-typescript = { version = "0.0.3" } specta-jsdoc = { version = "0.0.3" } @@ -81,6 +78,5 @@ specta-jsdoc = { version = "0.0.3" } # specta-typescript = { git = "https://github.com/oscartbeaumont/specta.git", rev = "cfa98fa10484e55923497f3cc21edf7418667c76" } specta = { path = "../specta/specta" } -specta-util = { path = "../specta/specta-util" } specta-typescript = { path = "../specta/specta-typescript" } specta-jsdoc = { path = "../specta/specta-jsdoc" } \ No newline at end of file diff --git a/examples/app/src/bindings-jsdoc.js b/examples/app/src/bindings-jsdoc.js index 81b2b9e..5569a9b 100644 --- a/examples/app/src/bindings-jsdoc.js +++ b/examples/app/src/bindings-jsdoc.js @@ -1,10 +1,10 @@ - /* eslint-disable */ - // This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually. +/* eslint-disable */ +// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually. - /** user-defined commands **/ +/** user-defined commands **/ - export const commands = { -/** +export const commands = { + /** * HELLO * WORLD * !!!! @@ -12,19 +12,19 @@ * @returns { Promise } */ async helloWorld(myName) { -return await TAURI_INVOKE("hello_world", { myName }); + return await TAURI_INVOKE("hello_world", { myName }); }, /** * @returns { Promise } */ async goodbyeWorld() { -return await TAURI_INVOKE("goodbye_world"); + return await TAURI_INVOKE("goodbye_world"); }, /** * @returns { Promise> } */ async hasError() { -try { + try { return { status: "ok", data: await TAURI_INVOKE("has_error") }; } catch (e) { if(e instanceof Error) throw e; @@ -36,13 +36,13 @@ try { * @returns { Promise } */ async deprecated() { -await TAURI_INVOKE("deprecated"); + await TAURI_INVOKE("deprecated"); }, /** * @returns { Promise> } */ async typesafeErrorsUsingThiserror() { -try { + try { return { status: "ok", data: await TAURI_INVOKE("typesafe_errors_using_thiserror") }; } catch (e) { if(e instanceof Error) throw e; @@ -53,7 +53,7 @@ try { * @returns { Promise> } */ async typesafeErrorsUsingThiserrorWithValue() { -try { + try { return { status: "ok", data: await TAURI_INVOKE("typesafe_errors_using_thiserror_with_value") }; } catch (e) { if(e instanceof Error) throw e; @@ -62,25 +62,26 @@ try { } } - /** user-defined events **/ +/** user-defined events **/ + - /** +/** * @type {typeof __makeEvents__<{ * demoEvent: DemoEvent * emptyEvent: EmptyEvent * }>} */ - const __typedMakeEvents__ = __makeEvents__; +const __typedMakeEvents__ = __makeEvents__; export const events = __typedMakeEvents__({ demoEvent: "demo-event", emptyEvent: "empty-event" }) - /** user-defined constants **/ +/** user-defined constants **/ - export const universalConstant = 42; +export const universalConstant = 42; /** user-defined types **/ @@ -107,7 +108,7 @@ emptyEvent: "empty-event" /** tauri-specta globals **/ - import { +import { invoke as TAURI_INVOKE, Channel as TAURI_CHANNEL, } from "@tauri-apps/api/core"; @@ -151,7 +152,7 @@ function __makeEvents__(mappings) { get: (_, event) => { const name = mappings[event]; - return new Proxy(() => {}, { + new Proxy(() => {}, { apply: (_, __, [window]) => ({ listen: (arg) => window.listen(name, arg), once: (arg) => window.once(name, arg), @@ -172,5 +173,3 @@ function __makeEvents__(mappings) { }, ); } - - \ No newline at end of file diff --git a/examples/app/src/bindings.ts b/examples/app/src/bindings.ts index 8e189c8..5fad21f 100644 --- a/examples/app/src/bindings.ts +++ b/examples/app/src/bindings.ts @@ -1,22 +1,23 @@ - /* eslint-disable */ - // This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually. +/* eslint-disable */ +// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually. - /** user-defined commands **/ +/** user-defined commands **/ - export const commands = { + +export const commands = { /** * HELLO * WORLD * !!!! */ async helloWorld(myName: string) : Promise { -return await TAURI_INVOKE("hello_world", { myName }); + return await TAURI_INVOKE("hello_world", { myName }); }, async goodbyeWorld() : Promise { -return await TAURI_INVOKE("goodbye_world"); + return await TAURI_INVOKE("goodbye_world"); }, async hasError() : Promise> { -try { + try { return { status: "ok", data: await TAURI_INVOKE("has_error") }; } catch (e) { if(e instanceof Error) throw e; @@ -27,10 +28,10 @@ try { * @deprecated This is a deprecated function */ async deprecated() : Promise { -await TAURI_INVOKE("deprecated"); + await TAURI_INVOKE("deprecated"); }, async typesafeErrorsUsingThiserror() : Promise> { -try { + try { return { status: "ok", data: await TAURI_INVOKE("typesafe_errors_using_thiserror") }; } catch (e) { if(e instanceof Error) throw e; @@ -38,7 +39,7 @@ try { } }, async typesafeErrorsUsingThiserrorWithValue() : Promise> { -try { + try { return { status: "ok", data: await TAURI_INVOKE("typesafe_errors_using_thiserror_with_value") }; } catch (e) { if(e instanceof Error) throw e; @@ -47,7 +48,8 @@ try { } } - /** user-defined events **/ +/** user-defined events **/ + export const events = __makeEvents__<{ demoEvent: DemoEvent, @@ -57,9 +59,9 @@ demoEvent: "demo-event", emptyEvent: "empty-event" }) - /** user-defined constants **/ +/** user-defined constants **/ - export const universalConstant = 42 as const; +export const universalConstant = 42 as const; /** user-defined types **/ @@ -71,7 +73,7 @@ export type MyError2 = { type: "IoError"; data: string } /** tauri-specta globals **/ - import { +import { invoke as TAURI_INVOKE, Channel as TAURI_CHANNEL, } from "@tauri-apps/api/core"; @@ -128,5 +130,3 @@ function __makeEvents__>( }, ); } - - \ No newline at end of file diff --git a/src/lang/js.rs b/src/lang/js.rs index 8569753..0e09775 100644 --- a/src/lang/js.rs +++ b/src/lang/js.rs @@ -1,5 +1,4 @@ use heck::ToLowerCamelCase; -use indoc::formatdoc; use specta::datatype::FunctionResultVariant; use specta_typescript::js_doc; @@ -57,12 +56,11 @@ impl LanguageExt for specta_jsdoc::JSDoc { .collect::, Self::Error>>()? .join(",\n"); - Ok(formatdoc! { - r#" - export const commands = {{ - {commands} - }}"# - }) + Ok(format!( + r#"export const commands = {{ + {commands} +}}"# + )) } fn render_events(&self, cfg: &Configuration) -> Result { @@ -83,14 +81,14 @@ impl LanguageExt for specta_jsdoc::JSDoc { builder.build() }; - Ok(formatdoc! { + Ok(format! { r#" - {events} - const __typedMakeEvents__ = __makeEvents__; +{events} +const __typedMakeEvents__ = __makeEvents__; - export const events = __typedMakeEvents__({{ - {events_map} - }})"# +export const events = __typedMakeEvents__({{ +{events_map} +}})"# }) } diff --git a/src/lang/js_ts.rs b/src/lang/js_ts.rs index 1cfb3c7..a65007c 100644 --- a/src/lang/js_ts.rs +++ b/src/lang/js_ts.rs @@ -5,7 +5,6 @@ use std::{any::TypeId, borrow::Cow, collections::BTreeMap}; use heck::ToLowerCamelCase; -use indoc::formatdoc; use specta::{ datatype::{self, DataType, FunctionResultVariant}, TypeMap, @@ -57,31 +56,29 @@ pub fn render_all_parts( .collect::>() .join("\n"); - Ok(formatdoc! { - r#" - {header} - {DO_NOT_EDIT} + Ok(format! { + r#"{header} +{DO_NOT_EDIT} - /** user-defined commands **/ +/** user-defined commands **/ - {commands} +{commands} - /** user-defined events **/ +/** user-defined events **/ - {events} +{events} - /** user-defined constants **/ +/** user-defined constants **/ - {constants} +{constants} - /** user-defined types **/ +/** user-defined types **/ - {dependant_types} +{dependant_types} - /** tauri-specta globals **/ +/** tauri-specta globals **/ - {globals} - "# +{globals}"# }) } @@ -98,14 +95,13 @@ pub fn arg_usages(args: &[String]) -> Option { fn return_as_result_tuple(expr: &str, as_any: bool) -> String { let as_any = as_any.then_some(" as any").unwrap_or_default(); - formatdoc!( - r#" - try {{ - return {{ status: "ok", data: {expr} }}; - }} catch (e) {{ - if(e instanceof Error) throw e; - else return {{ status: "error", error: e {as_any} }}; - }}"# + format!( + r#"try {{ + return {{ status: "ok", data: {expr} }}; +}} catch (e) {{ + if(e instanceof Error) throw e; + else return {{ status: "error", error: e {as_any} }}; +}}"# ) } @@ -133,12 +129,11 @@ pub fn function( .map(|t| format!(": Promise<{}>", t)) .unwrap_or_default(); - formatdoc! { - r#" - {docs}async {name}({args}) {return_type} {{ - {body} - }}"# - } + format!( + r#"{docs}async {name}({args}) {return_type} {{ + {body} +}}"# + ) } fn tauri_invoke(name: &str, arg_usages: Option) -> String { diff --git a/src/lang/ts.rs b/src/lang/ts.rs index de331e3..9b24d0a 100644 --- a/src/lang/ts.rs +++ b/src/lang/ts.rs @@ -1,6 +1,5 @@ use crate::{lang::js_ts, Configuration, LanguageExt}; use heck::ToLowerCamelCase; -use indoc::formatdoc; use specta::datatype::FunctionResultVariant; use specta_typescript as ts; use specta_typescript::{js_doc, ExportError}; @@ -51,11 +50,11 @@ impl LanguageExt for specta_typescript::Typescript { .collect::, ExportError>>()? .join(",\n"); - Ok(formatdoc! { + Ok(format! { r#" - export const commands = {{ - {commands} - }}"# +export const commands = {{ +{commands} +}}"# }) } @@ -69,13 +68,13 @@ impl LanguageExt for specta_typescript::Typescript { let events_types = events_types.join(",\n"); - Ok(formatdoc! { + Ok(format! { r#" - export const events = __makeEvents__<{{ - {events_types} - }}>({{ - {events_map} - }})"# +export const events = __makeEvents__<{{ +{events_types} +}}>({{ +{events_map} +}})"# }) } From f3c8273e5a0adbabac32e3bdba80ad47de8ed160 Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Thu, 1 Aug 2024 16:18:55 +0800 Subject: [PATCH 9/9] Docs --- src/builder.rs | 7 +++--- src/event.rs | 25 +++++++++++++++++++++ src/lang/js.rs | 8 +++---- src/lang/js_ts.rs | 4 ++-- src/lang/ts.rs | 8 +++---- src/lib.rs | 55 +++++++++++++++++++++++++++-------------------- src/macros.rs | 24 +++++++++++++++++++++ 7 files changed, 95 insertions(+), 36 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index f3e84ac..16309f4 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -51,6 +51,7 @@ use crate::{Commands, EventRegistry, Events, LanguageExt}; /// # TODO /// ``` pub struct Builder { + // TODO: Can we just hold a `ExportContext` here to make it a bit neater??? plugin_name: Option<&'static str>, commands: Commands, command_types: Vec, @@ -92,7 +93,7 @@ impl Builder { /// Register commands with the builder. /// - /// WARNING: This method will overwrite any previously registered commands. + /// **WARNING:** This method will overwrite any previously registered commands. pub fn commands(mut self, commands: Commands) -> Self { Self { command_types: (commands.1)(&mut self.types), @@ -103,7 +104,7 @@ impl Builder { /// Register events with the builder. /// - /// WARNING: This method will overwrite any previously registered events. + /// **WARNING:** This method will overwrite any previously registered events. pub fn events(mut self, events: Events) -> Self { let mut event_sids = BTreeSet::new(); let events = events @@ -178,7 +179,7 @@ impl Builder { // TODO: Handle duplicate type names // TODO: Serde checking - language.render(&crate::Configuration { + language.render(&crate::ExportContext { // TODO: Don't clone stuff commands: self.command_types.clone(), events: self.events.clone(), diff --git a/src/event.rs b/src/event.rs index a67a175..57d65cf 100644 --- a/src/event.rs +++ b/src/event.rs @@ -32,8 +32,11 @@ impl EventRegistry { } } +/// A typed event that was emitted. pub struct TypedEvent { + /// The [`EventId`] of the handler that was triggered. pub id: EventId, + /// The event payload. pub payload: T, } @@ -49,6 +52,28 @@ macro_rules! make_handler { }; } +/// Extends your event type with typesafe methods for listening to and emitting events. +/// +/// You should rely on the [`Event`](macro@crate::Event) derive macro to implement this for you. +/// +/// # Example +/// ```rust +/// use serde::{Serialize, Deserialize}; +/// use specta::Type; +/// use tauri_specta::Event; +/// use tauri::AppHandle +/// +/// #[derive(Debug, Clone, Serialize, Deserialize, Type, Event)] +/// pub struct MyEvent(String); +/// +/// fn use_event(app: AppHandle) { +/// DemoEvent::listen(handle, |event| { +/// dbg!(event.payload); +/// }); +/// +/// DemoEvent("Test".to_string()).emit(handle).ok(); +/// } +/// ``` pub trait Event: NamedType { const NAME: &'static str; diff --git a/src/lang/js.rs b/src/lang/js.rs index 0e09775..6277ed7 100644 --- a/src/lang/js.rs +++ b/src/lang/js.rs @@ -2,14 +2,14 @@ use heck::ToLowerCamelCase; use specta::datatype::FunctionResultVariant; use specta_typescript::js_doc; -use crate::{Configuration, LanguageExt}; +use crate::{ExportContext, LanguageExt}; use super::js_ts; const GLOBALS: &str = include_str!("./globals.js"); impl LanguageExt for specta_jsdoc::JSDoc { - fn render_commands(&self, cfg: &Configuration) -> Result { + fn render_commands(&self, cfg: &ExportContext) -> Result { let commands = cfg .commands .iter() @@ -63,7 +63,7 @@ impl LanguageExt for specta_jsdoc::JSDoc { )) } - fn render_events(&self, cfg: &Configuration) -> Result { + fn render_events(&self, cfg: &ExportContext) -> Result { if cfg.events.is_empty() { return Ok(Default::default()); } @@ -92,7 +92,7 @@ export const events = __typedMakeEvents__({{ }) } - fn render(&self, cfg: &Configuration) -> Result { + fn render(&self, cfg: &ExportContext) -> Result { let dependant_types = cfg .type_map .iter() diff --git a/src/lang/js_ts.rs b/src/lang/js_ts.rs index a65007c..af86f90 100644 --- a/src/lang/js_ts.rs +++ b/src/lang/js_ts.rs @@ -13,13 +13,13 @@ use specta_jsdoc::JSDoc; use specta_typescript::{self as ts}; use specta_typescript::{ExportError, Typescript}; -use crate::{apply_as_prefix, Configuration, ItemType, LanguageExt}; +use crate::{apply_as_prefix, ExportContext, ItemType, LanguageExt}; const DO_NOT_EDIT: &str = "// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually."; pub fn render_all_parts( language: &L, - cfg: &Configuration, + cfg: &ExportContext, dependant_types: &str, globals: &str, header: &str, diff --git a/src/lang/ts.rs b/src/lang/ts.rs index 9b24d0a..0b15024 100644 --- a/src/lang/ts.rs +++ b/src/lang/ts.rs @@ -1,4 +1,4 @@ -use crate::{lang::js_ts, Configuration, LanguageExt}; +use crate::{lang::js_ts, ExportContext, LanguageExt}; use heck::ToLowerCamelCase; use specta::datatype::FunctionResultVariant; use specta_typescript as ts; @@ -7,7 +7,7 @@ use specta_typescript::{js_doc, ExportError}; const GLOBALS: &str = include_str!("./globals.ts"); impl LanguageExt for specta_typescript::Typescript { - fn render_commands(&self, cfg: &Configuration) -> Result { + fn render_commands(&self, cfg: &ExportContext) -> Result { let commands = cfg .commands .iter() @@ -58,7 +58,7 @@ export const commands = {{ }) } - fn render_events(&self, cfg: &Configuration) -> Result { + fn render_events(&self, cfg: &ExportContext) -> Result { if cfg.events.is_empty() { return Ok(Default::default()); } @@ -78,7 +78,7 @@ export const events = __makeEvents__<{{ }) } - fn render(&self, cfg: &Configuration) -> Result { + fn render(&self, cfg: &ExportContext) -> Result { let dependant_types = cfg .type_map .iter() diff --git a/src/lib.rs b/src/lib.rs index f18d5fb..182f190 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,6 +114,7 @@ html_favicon_url = "https://github.com/oscartbeaumont/specta/raw/main/.github/logo-128.png" )] +use core::fmt; use std::{ borrow::Cow, collections::{BTreeMap, HashMap}, @@ -126,6 +127,10 @@ use specta::{ }; use tauri::{ipc::Invoke, Runtime}; +/// Implements the [`Event`](trait@crate::Event) trait for a struct. +/// +/// Refer to the [`Event`](trait@crate::Event) trait for more information. +/// #[cfg(feature = "derive")] #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] pub use tauri_specta_macros::Event; @@ -136,21 +141,25 @@ mod lang; mod macros; pub use builder::Builder; -#[allow(unused)] -pub use lang::*; - -// TODO: Probs drop -pub use event::*; +pub(crate) use event::EventRegistry; +pub use event::{Event, TypedEvent}; /// A wrapper around the output of the `collect_commands` macro. /// /// This acts to seal the implementation details of the macro. +#[derive(Clone)] pub struct Commands( // Bounds copied from `tauri::Builder::invoke_handler` pub(crate) Arc) -> bool + Send + Sync + 'static>, pub(crate) fn(&mut TypeMap) -> Vec, ); +impl fmt::Debug for Commands { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Commands").finish() + } +} + impl Default for Commands { fn default() -> Self { Self( @@ -166,45 +175,47 @@ impl Default for Commands { #[derive(Default)] pub struct Events(BTreeMap<&'static str, fn(&mut TypeMap) -> (SpectaID, DataType)>); +/// The context of what needs to be exported. Used when implementing [`LanguageExt`]. #[derive(Debug, Clone)] #[non_exhaustive] -pub struct Configuration { - plugin_name: Option<&'static str>, - commands: Vec, - events: BTreeMap<&'static str, DataType>, - type_map: TypeMap, - constants: HashMap, serde_json::Value>, +pub struct ExportContext { + pub plugin_name: Option<&'static str>, + pub commands: Vec, + pub events: BTreeMap<&'static str, DataType>, + pub type_map: TypeMap, + pub constants: HashMap, serde_json::Value>, } -impl Configuration {} - +/// Implemented for all languages which Tauri Specta supports exporting to. +/// +/// Currently implemented for: +/// - [`specta_typescript::Typescript`] +/// - [`specta_jsdoc::JSDoc`] pub trait LanguageExt: Language { - fn render_commands(&self, cfg: &Configuration) -> Result; - fn render_events(&self, cfg: &Configuration) -> Result; - fn render(&self, cfg: &Configuration) -> Result; + fn render_commands(&self, cfg: &ExportContext) -> Result; + fn render_events(&self, cfg: &ExportContext) -> Result; + fn render(&self, cfg: &ExportContext) -> Result; } impl LanguageExt for &L { - fn render_commands(&self, cfg: &Configuration) -> Result { + fn render_commands(&self, cfg: &ExportContext) -> Result { (*self).render_commands(cfg) } - fn render_events(&self, cfg: &Configuration) -> Result { + fn render_events(&self, cfg: &ExportContext) -> Result { (*self).render_events(cfg) } - fn render(&self, cfg: &Configuration) -> Result { + fn render(&self, cfg: &ExportContext) -> Result { (*self).render(cfg) } } -// TODO: Remove this pub(crate) enum ItemType { Event, Command, } -// TODO: Move onto `Configuration` pub(crate) fn apply_as_prefix(plugin_name: &str, s: &str, item_type: ItemType) -> String { format!( "plugin:{}{}{}", @@ -223,8 +234,6 @@ pub mod internal { //! Nothing in this module has to conform to semver so it should not be used outside of this crate. //! It has to be public so macro's can access it. - use specta::NamedType; - use super::*; /// called by `collect_commands` to construct `Commands` diff --git a/src/macros.rs b/src/macros.rs index d2638a3..037e4b3 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,3 +1,16 @@ +/// Collect commands and their types. +/// +/// This is a combination of Tauri's [`generate_handler`](tauri::generate_handler) and Specta's [`collect_functions`](specta::function::collect_functions). +/// +/// This returns a [`Commands`](crate::Commands) struct that can be passed to [`Builder::commands`](crate::Builder::commands). +/// +/// # Usage +/// ```rust +/// collect_commands![]; +/// collect_commands![hello_world]; +/// collect_commands![hello_world, some::path::function, generic_fn::]; +/// ``` +/// // TODO: Hide it's implementation details from the generated rustdoc. #[macro_export] macro_rules! collect_commands { @@ -34,6 +47,17 @@ macro_rules! collect_commands { }; } +/// Collect events and their types. +/// +/// This returns a [`Events`](crate::Events) struct that can be passed to [`Builder::events`](crate::Builder::events). +/// +/// # Usage +/// ```rust +/// collect_events![]; +/// collect_events![MyEvent]; +/// collect_events![MyEvent, module::MyOtherEvent]; +/// ``` +/// // TODO: Hide it's implementation details from the generated rustdoc. #[macro_export] macro_rules! collect_events {