├── .gitignore ├── tests ├── variables │ └── color.scss ├── use_default_settings │ ├── src │ │ ├── mystyle.scss │ │ └── lib.rs │ └── Cargo.toml ├── load_settings_from_cargo_manifest │ ├── src │ │ ├── mystyle.scss │ │ └── lib.rs │ └── Cargo.toml ├── Cargo.toml ├── define_inline_style_sheet │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── Cargo.lock ├── turf_internals ├── README.md ├── src │ ├── hashing.rs │ ├── manifest.rs │ ├── path_utils.rs │ ├── css_compilation.rs │ ├── file_output.rs │ ├── lib.rs │ ├── settings.rs │ └── transformer.rs └── Cargo.toml ├── turf_macros ├── README.md ├── Cargo.toml └── src │ └── lib.rs ├── examples ├── yew-example │ ├── variables │ │ └── color.scss │ ├── index.html │ ├── src │ │ ├── counter_component.scss │ │ ├── hello_yew.scss │ │ ├── main.rs │ │ ├── hello_yew.rs │ │ └── counter_component.rs │ ├── README.md │ └── Cargo.toml ├── axum-askama-htmx │ ├── variables │ │ └── color.scss │ ├── README.md │ ├── templates │ │ ├── counter_component.scss │ │ ├── hello_askama.scss │ │ ├── base.html │ │ ├── counter_component.html │ │ └── index.html │ ├── Cargo.toml │ ├── src │ │ └── main.rs │ └── Cargo.lock ├── dioxus-example │ ├── variables │ │ └── color.scss │ ├── index.html │ ├── src │ │ ├── counter_component.scss │ │ ├── hello_dioxus.scss │ │ ├── main.rs │ │ ├── hello_dioxus.rs │ │ └── counter_component.rs │ ├── README.md │ └── Cargo.toml ├── leptos-example │ ├── variables │ │ └── color.scss │ ├── index.html │ ├── src │ │ ├── counter_component.scss │ │ ├── hello_leptos.scss │ │ ├── main.rs │ │ ├── hello_leptos.rs │ │ └── counter_component.rs │ ├── README.md │ └── Cargo.toml └── leptos-hash-example │ ├── variables │ └── color.scss │ ├── index.html │ ├── src │ ├── counter_component.scss │ ├── hello_leptos.scss │ ├── main.rs │ ├── hello_leptos.rs │ └── counter_component.rs │ ├── README.md │ └── Cargo.toml ├── Makefile ├── Cargo.toml ├── .github └── workflows │ └── rust-ci.yml ├── LICENSE ├── CHANGELOG.md ├── README.md ├── src └── lib.rs └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | dist 3 | -------------------------------------------------------------------------------- /tests/variables/color.scss: -------------------------------------------------------------------------------- 1 | $some-color: #69e69d; 2 | -------------------------------------------------------------------------------- /turf_internals/README.md: -------------------------------------------------------------------------------- 1 | You're probably looking for `turf` instead. 2 | -------------------------------------------------------------------------------- /turf_macros/README.md: -------------------------------------------------------------------------------- 1 | You're probably looking for `turf` instead. 2 | -------------------------------------------------------------------------------- /tests/use_default_settings/src/mystyle.scss: -------------------------------------------------------------------------------- 1 | .test { 2 | color: #333; 3 | } 4 | -------------------------------------------------------------------------------- /examples/yew-example/variables/color.scss: -------------------------------------------------------------------------------- 1 | $headline-color: hotpink; 2 | $button-text-color: green; 3 | -------------------------------------------------------------------------------- /examples/axum-askama-htmx/variables/color.scss: -------------------------------------------------------------------------------- 1 | $headline-color: hotpink; 2 | $button-text-color: green; 3 | -------------------------------------------------------------------------------- /examples/dioxus-example/variables/color.scss: -------------------------------------------------------------------------------- 1 | $headline-color: hotpink; 2 | $button-text-color: green; 3 | -------------------------------------------------------------------------------- /examples/leptos-example/variables/color.scss: -------------------------------------------------------------------------------- 1 | $headline-color: hotpink; 2 | $button-text-color: green; 3 | -------------------------------------------------------------------------------- /examples/leptos-hash-example/variables/color.scss: -------------------------------------------------------------------------------- 1 | $headline-color: hotpink; 2 | $button-text-color: green; 3 | -------------------------------------------------------------------------------- /examples/leptos-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/yew-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/leptos-hash-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/dioxus-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/load_settings_from_cargo_manifest/src/mystyle.scss: -------------------------------------------------------------------------------- 1 | @import "color"; 2 | 3 | .test { 4 | color: $some-color; 5 | } 6 | -------------------------------------------------------------------------------- /examples/axum-askama-htmx/README.md: -------------------------------------------------------------------------------- 1 | # Askama example 2 | 3 | This example shows how to use `turf` in conjunction with `askama`. 4 | 5 | Run `cargo run` 6 | -------------------------------------------------------------------------------- /examples/yew-example/src/counter_component.scss: -------------------------------------------------------------------------------- 1 | @import "color"; 2 | 3 | .counter-button { 4 | button { 5 | color: $button-text-color; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/dioxus-example/src/counter_component.scss: -------------------------------------------------------------------------------- 1 | @import "color"; 2 | 3 | .counter-button { 4 | button { 5 | color: $button-text-color; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/leptos-example/src/counter_component.scss: -------------------------------------------------------------------------------- 1 | @import "color"; 2 | 3 | .counter-button { 4 | button { 5 | color: $button-text-color; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/axum-askama-htmx/templates/counter_component.scss: -------------------------------------------------------------------------------- 1 | @import "color"; 2 | 3 | .counter-button { 4 | button { 5 | color: $button-text-color; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/leptos-hash-example/src/counter_component.scss: -------------------------------------------------------------------------------- 1 | @import "color"; 2 | 3 | .counter-button { 4 | button { 5 | color: $button-text-color; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ "define_inline_style_sheet", 3 | "load_settings_from_cargo_manifest", 4 | "use_default_settings", 5 | "define_inline_style_sheet", 6 | ] 7 | -------------------------------------------------------------------------------- /examples/yew-example/README.md: -------------------------------------------------------------------------------- 1 | # Yew example 2 | 3 | This example shows how to use `turf` in conjunction with `yew`. 4 | 5 | 1. Install [trunk](https://trunkrs.dev/) 6 | 7 | 2. Run `trunk serve` 8 | -------------------------------------------------------------------------------- /examples/dioxus-example/README.md: -------------------------------------------------------------------------------- 1 | # Dioxus example 2 | 3 | This example shows how to use `turf` in conjunction with `dioxus`. 4 | 5 | 1. Install [trunk](https://trunkrs.dev/) 6 | 7 | 2. Run `trunk serve` 8 | -------------------------------------------------------------------------------- /examples/leptos-example/README.md: -------------------------------------------------------------------------------- 1 | # Leptos example 2 | 3 | This example shows how to use `turf` in conjunction with `leptos`. 4 | 5 | 1. Install [trunk](https://trunkrs.dev/) 6 | 7 | 2. Run `trunk serve` 8 | -------------------------------------------------------------------------------- /examples/leptos-hash-example/README.md: -------------------------------------------------------------------------------- 1 | # Leptos example 2 | 3 | This example shows how to use `turf` in conjunction with `leptos`. 4 | 5 | 1. Install [trunk](https://trunkrs.dev/) 6 | 7 | 2. Run `trunk serve` 8 | -------------------------------------------------------------------------------- /examples/yew-example/src/hello_yew.scss: -------------------------------------------------------------------------------- 1 | @import "color"; 2 | 3 | .hello-yew { 4 | h1 { 5 | color: $headline-color; 6 | } 7 | 8 | .hello-world { 9 | color: blue; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/dioxus-example/src/hello_dioxus.scss: -------------------------------------------------------------------------------- 1 | @import "color"; 2 | 3 | .hello-dioxus { 4 | h1 { 5 | color: $headline-color; 6 | } 7 | 8 | .hello-world { 9 | color: blue; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/leptos-example/src/hello_leptos.scss: -------------------------------------------------------------------------------- 1 | @import "color"; 2 | 3 | .hello-leptos { 4 | h1 { 5 | color: $headline-color; 6 | } 7 | 8 | .hello-world { 9 | color: blue; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/leptos-hash-example/src/hello_leptos.scss: -------------------------------------------------------------------------------- 1 | @import "color"; 2 | 3 | .hello-leptos { 4 | h1 { 5 | color: $headline-color; 6 | } 7 | 8 | .hello-world { 9 | color: blue; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/axum-askama-htmx/templates/hello_askama.scss: -------------------------------------------------------------------------------- 1 | @import "color"; 2 | 3 | .hello-askama { 4 | h1 { 5 | color: $headline-color; 6 | } 7 | 8 | .hello-world { 9 | color: blue; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/use_default_settings/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn use_default_settings() { 3 | turf::style_sheet!("src/mystyle.scss"); 4 | assert!(STYLE_SHEET.ends_with("{color:#333}")); 5 | assert!(STYLE_SHEET.starts_with(".class-")); 6 | assert!(STYLE_SHEET.starts_with(&format!(".{}", ClassName::TEST))); 7 | } 8 | -------------------------------------------------------------------------------- /tests/define_inline_style_sheet/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "define_inline_style_sheet" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies.turf] 7 | path = "../../" 8 | [dependencies.turf_internals] 9 | path = "../../turf_internals" 10 | 11 | [package.metadata.turf] 12 | load_paths = ["../variables"] 13 | minify = false 14 | -------------------------------------------------------------------------------- /tests/load_settings_from_cargo_manifest/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn load_paths_from_cargo_manifest() { 3 | turf::style_sheet!("src/mystyle.scss"); 4 | assert!(STYLE_SHEET.starts_with(".class-")); 5 | assert!(STYLE_SHEET.ends_with(" {\n color: #69e69d;\n}\n")); 6 | assert!(STYLE_SHEET.starts_with(&format!(".{}", ClassName::TEST))); 7 | } 8 | -------------------------------------------------------------------------------- /examples/leptos-example/src/main.rs: -------------------------------------------------------------------------------- 1 | use leptos::prelude::*; 2 | 3 | mod counter_component; 4 | mod hello_leptos; 5 | 6 | use counter_component::*; 7 | use hello_leptos::*; 8 | 9 | fn main() { 10 | mount_to_body(|| { 11 | view! { 12 | 13 | 14 | } 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /tests/use_default_settings/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "use_default_settings" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies.turf] 9 | path = "../../" 10 | [dependencies.turf_internals] 11 | path = "../../turf_internals" 12 | -------------------------------------------------------------------------------- /examples/leptos-hash-example/src/main.rs: -------------------------------------------------------------------------------- 1 | use leptos::prelude::*; 2 | 3 | mod counter_component; 4 | mod hello_leptos; 5 | 6 | use counter_component::*; 7 | use hello_leptos::*; 8 | 9 | fn main() { 10 | mount_to_body(|| { 11 | view! { 12 | 13 | 14 | } 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /examples/dioxus-example/src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use dioxus::prelude::*; 3 | 4 | mod counter_component; 5 | mod hello_dioxus; 6 | 7 | fn main() { 8 | dioxus::launch(App); 9 | } 10 | 11 | fn App() -> Element { 12 | rsx! { 13 | hello_dioxus::HelloDioxus {} 14 | counter_component::CounterComponent {} 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/yew-example/src/main.rs: -------------------------------------------------------------------------------- 1 | use yew::prelude::*; 2 | 3 | mod counter_component; 4 | mod hello_yew; 5 | 6 | use counter_component::*; 7 | use hello_yew::*; 8 | 9 | #[function_component] 10 | fn App() -> Html { 11 | html! { 12 | <> 13 | 14 | 15 | 16 | } 17 | } 18 | 19 | fn main() { 20 | yew::Renderer::::new().render(); 21 | } 22 | -------------------------------------------------------------------------------- /examples/axum-askama-htmx/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | {% block content %}{% endblock %} 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/yew-example/src/hello_yew.rs: -------------------------------------------------------------------------------- 1 | use yew::prelude::*; 2 | 3 | turf::style_sheet!("src/hello_yew.scss"); 4 | 5 | #[function_component] 6 | pub fn HelloYew() -> Html { 7 | html! { 8 |
9 | 10 |

{"Hello, Yew!"}

11 |

{"Hello, World!"}

12 |
13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/define_inline_style_sheet/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn inline_scss_style() { 3 | turf::inline_style_sheet! { 4 | @import "color"; 5 | 6 | .test { 7 | color: $some-color; 8 | } 9 | }; 10 | assert!(STYLE_SHEET.starts_with(".class-")); 11 | assert!(STYLE_SHEET.ends_with(" {\n color: #69e69d;\n}\n")); 12 | assert!(STYLE_SHEET.starts_with(&format!(".{}", ClassName::TEST))); 13 | } 14 | -------------------------------------------------------------------------------- /examples/leptos-example/src/hello_leptos.rs: -------------------------------------------------------------------------------- 1 | use leptos::prelude::*; 2 | 3 | turf::style_sheet!("src/hello_leptos.scss"); 4 | 5 | #[component] 6 | pub fn HelloLeptos() -> impl IntoView { 7 | view! { 8 | 9 |
10 |

"Hello, Leptos!"

11 |

"Hello, World!"

12 |
13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/leptos-hash-example/src/hello_leptos.rs: -------------------------------------------------------------------------------- 1 | use leptos::prelude::*; 2 | 3 | turf::style_sheet!("src/hello_leptos.scss"); 4 | 5 | #[component] 6 | pub fn HelloLeptos() -> impl IntoView { 7 | view! { 8 | 9 |
10 |

"Hello, Leptos!"

11 |

"Hello, World!"

12 |
13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/axum-askama-htmx/templates/counter_component.html: -------------------------------------------------------------------------------- 1 | {% let (style_sheet, class_name) = turf::style_sheet_values!("templates/counter_component.scss") %} 2 | 3 |
9 | 10 | 14 |
15 | -------------------------------------------------------------------------------- /tests/load_settings_from_cargo_manifest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "load_settings_from_cargo_manifest" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies.turf] 9 | path = "../../" 10 | [dependencies.turf_internals] 11 | path = "../../turf_internals" 12 | 13 | [package.metadata.turf] 14 | load_paths = ["../variables"] 15 | minify = false 16 | -------------------------------------------------------------------------------- /examples/dioxus-example/src/hello_dioxus.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | turf::style_sheet!("src/hello_dioxus.scss"); 4 | 5 | pub fn HelloDioxus() -> Element { 6 | rsx! { 7 | style { "{STYLE_SHEET}" } 8 | div { 9 | class: ClassName::HELLO_DIOXUS, 10 | h1 { "Hello, Dioxus!" } 11 | h2 { 12 | class: ClassName::HELLO_WORLD, 13 | "Hello, World!" 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/axum-askama-htmx/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 | {% let (style_sheet, class_name) = turf::style_sheet_values!("templates/hello_askama.scss") %} 5 | 6 | 9 | 10 |
11 |

Hello, Askama!

12 |

Hello, World!

13 |
14 | 15 | {% include "counter_component.html" %} 16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /examples/dioxus-example/src/counter_component.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | turf::style_sheet!("src/counter_component.scss"); 4 | 5 | pub fn CounterComponent() -> Element { 6 | let mut counter = use_signal(|| 0); 7 | 8 | rsx! { 9 | style { "{STYLE_SHEET}" } 10 | div { 11 | class: ClassName::COUNTER_BUTTON, 12 | button { 13 | onclick: move |_| *counter.write() += 1, 14 | "Click me: {counter}", 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /turf_macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "turf_macros" 3 | description = "Macros used by turf." 4 | version.workspace = true 5 | edition.workspace = true 6 | authors.workspace = true 7 | license.workspace = true 8 | repository.workspace = true 9 | publish.workspace = true 10 | readme = "README.md" 11 | 12 | [lib] 13 | proc-macro = true 14 | 15 | [dependencies] 16 | quote = "1.0" 17 | proc-macro2 = { version = "1.0" } 18 | convert_case = "0.6.0" 19 | 20 | [dependencies.turf_internals] 21 | path = "../turf_internals" 22 | version = "0.10.1" 23 | -------------------------------------------------------------------------------- /examples/leptos-example/src/counter_component.rs: -------------------------------------------------------------------------------- 1 | use leptos::prelude::*; 2 | 3 | turf::style_sheet!("src/counter_component.scss"); 4 | 5 | #[component] 6 | pub fn CounterComponent() -> impl IntoView { 7 | let (count, set_count) = signal(0); 8 | 9 | view! { 10 | 11 |
12 | 16 |
17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/leptos-hash-example/src/counter_component.rs: -------------------------------------------------------------------------------- 1 | use leptos::prelude::*; 2 | 3 | turf::style_sheet!("src/counter_component.scss"); 4 | 5 | #[component] 6 | pub fn CounterComponent() -> impl IntoView { 7 | let (count, set_count) = signal(0); 8 | 9 | view! { 10 | 11 |
12 | 16 |
17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/yew-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "yew-example" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies.yew] 9 | version = "0.21" 10 | features = ["csr"] 11 | 12 | [dependencies.turf] 13 | path = "../../" 14 | 15 | [package.metadata.turf] 16 | load_paths = ["variables"] 17 | minify = true 18 | browser_targets = [ 19 | "firefox 65", 20 | "chrome 80", 21 | "safari 10", 22 | ] 23 | 24 | [package.metadata.turf.class_names] 25 | template = "yew-example__" 26 | -------------------------------------------------------------------------------- /examples/yew-example/src/counter_component.rs: -------------------------------------------------------------------------------- 1 | use yew::prelude::*; 2 | 3 | turf::style_sheet!("src/counter_component.scss"); 4 | 5 | #[function_component] 6 | pub fn CounterComponent() -> Html { 7 | let state = use_state(|| 0); 8 | 9 | let incr_counter = { 10 | let state = state.clone(); 11 | Callback::from(move |_| state.set(*state + 1)) 12 | }; 13 | 14 | html! { 15 |
16 | 17 | 18 |
19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/dioxus-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-example" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | dioxus = { version = "0.6.3", features = ["web"] } 10 | 11 | [dependencies.turf] 12 | path = "../../" 13 | 14 | [package.metadata.turf] 15 | load_paths = ["variables"] 16 | minify = true 17 | browser_targets = [ 18 | "firefox 65", 19 | "chrome 80", 20 | "safari 10", 21 | ] 22 | 23 | [package.metadata.turf.class_names] 24 | template = "dioxus-example__" 25 | -------------------------------------------------------------------------------- /examples/leptos-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "leptos-example" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies.leptos] 9 | version = "0.7.8" 10 | features = ["csr"] 11 | 12 | [dependencies.turf] 13 | path = "../.." 14 | 15 | [package.metadata.turf] 16 | load_paths = ["variables"] 17 | minify = true 18 | browser_targets = [ 19 | "firefox 65", 20 | "chrome 80", 21 | "safari 10", 22 | ] 23 | 24 | [package.metadata.turf.class_names] 25 | template = "leptos-example__" 26 | -------------------------------------------------------------------------------- /examples/leptos-hash-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "leptos-hash-example" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies.leptos] 9 | version = "0.7.8" 10 | features = ["csr"] 11 | 12 | [dependencies.turf] 13 | path = "../../" 14 | 15 | [package.metadata.turf] 16 | load_paths = ["variables"] 17 | minify = true 18 | browser_targets = [ 19 | "firefox 65", 20 | "chrome 80", 21 | "safari 10", 22 | ] 23 | 24 | [package.metadata.turf.class_names] 25 | template = "leptos-hash-example__" 26 | -------------------------------------------------------------------------------- /turf_internals/src/hashing.rs: -------------------------------------------------------------------------------- 1 | use crate::StyleSheetKind; 2 | 3 | #[derive(thiserror::Error, Debug)] 4 | #[error("Failed to hash style sheet")] 5 | pub enum StyleSheetHashingError { 6 | FileRead(#[from] std::io::Error), 7 | } 8 | 9 | pub fn hash_style_sheet(style_sheet: &StyleSheetKind) -> Result { 10 | let hash = match style_sheet { 11 | StyleSheetKind::File(ref path) => xxhash_rust::xxh3::xxh3_128(&std::fs::read(path)?), 12 | StyleSheetKind::Inline(ref style_sheet) => { 13 | xxhash_rust::xxh3::xxh3_128(style_sheet.as_bytes()) 14 | } 15 | }; 16 | 17 | Ok(format!("{hash:x}")) 18 | } 19 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: * 2 | 3 | test-lib: 4 | cargo test --verbose --workspace 5 | cd tests && cargo test --verbose --workspace 6 | 7 | test-build-examples: 8 | cd examples/leptos-example && trunk build 9 | cd examples/leptos-example && trunk build --release 10 | cd examples/yew-example && trunk build 11 | cd examples/yew-example && trunk build --release 12 | cd examples/dioxus-example && trunk build 13 | cd examples/dioxus-example && trunk build --release 14 | cd examples/axum-askama-htmx && cargo build 15 | cd examples/axum-askama-htmx && cargo build --release 16 | cd examples/leptos-hash-example && trunk build 17 | cd examples/leptos-hash-example && trunk build --release 18 | 19 | test: test-lib test-build-examples 20 | -------------------------------------------------------------------------------- /examples/axum-askama-htmx/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "axum-askama-htmx" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | askama = { version = "0.12.1", features = ["with-axum"] } 10 | askama_axum = "0.4.0" 11 | axum = "0.7.4" 12 | tokio = { version = "1.33.0", features = ["full"] } 13 | tower = { version = "0.4", features = ["util"] } 14 | 15 | [dependencies.turf] 16 | path = "../../" 17 | 18 | [package.metadata.turf] 19 | load_paths = ["variables"] 20 | minify = false 21 | browser_targets = [ 22 | "firefox 65", 23 | "chrome 80", 24 | "safari 10", 25 | ] 26 | 27 | [package.metadata.turf.class_names] 28 | template = "askama-example__" 29 | -------------------------------------------------------------------------------- /examples/axum-askama-htmx/src/main.rs: -------------------------------------------------------------------------------- 1 | use askama::*; 2 | 3 | #[derive(Template)] 4 | #[template(path = "index.html")] 5 | struct HelloTemplate { 6 | count: u64, 7 | } 8 | 9 | #[derive(Template)] 10 | #[template(path = "counter_component.html")] 11 | struct CounterTemplate { 12 | count: u64, 13 | } 14 | 15 | use axum::{extract::Path, routing::get, Router}; 16 | 17 | #[tokio::main] 18 | async fn main() { 19 | let app = Router::new() 20 | .route("/", get(|| async { HelloTemplate { count: 0 } })) 21 | .route( 22 | "/counter/:count", 23 | get(|Path(count): Path| async move { CounterTemplate { count } }), 24 | ); 25 | 26 | let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await.unwrap(); 27 | axum::serve(listener, app).await.unwrap(); 28 | } 29 | -------------------------------------------------------------------------------- /turf_internals/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "turf_internals" 3 | description = "The inner workings of turf." 4 | version.workspace = true 5 | edition.workspace = true 6 | authors.workspace = true 7 | license.workspace = true 8 | repository.workspace = true 9 | publish.workspace = true 10 | readme = "README.md" 11 | 12 | [dependencies] 13 | toml = "0.8.0" 14 | thiserror = "1.0" 15 | oorandom = "11.1.3" 16 | getrandom = { version = "0.2.9", features = ["std"] } 17 | regex = "1.10.2" 18 | xxhash-rust = { version = "0.8.10", features = ["xxh3"] } 19 | 20 | [dependencies.serde] 21 | version = "1.0" 22 | features = ["derive"] 23 | 24 | [dependencies.lightningcss] 25 | # the alpha version matches newer versions as well if not pinned 26 | version = "=1.0.0-alpha.65" 27 | default-features = false 28 | features = ["grid", "visitor", "browserslist"] 29 | 30 | [dependencies.grass] 31 | version = "0.13.0" 32 | default-features = false 33 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "turf_macros", 4 | "turf_internals", 5 | ] 6 | exclude = [ 7 | "examples", 8 | "tests", 9 | ] 10 | 11 | [workspace.package] 12 | version = "0.10.1" 13 | edition = "2021" 14 | authors = ["myFavShrimp "] 15 | license = "MIT" 16 | repository = "https://github.com/myFavShrimp/turf" 17 | publish = true 18 | 19 | [package] 20 | name = "turf" 21 | description = "Build SCSS to CSS during compile time and inject those styles into your binary." 22 | documentation = "https://docs.rs/turf" 23 | keywords = ["web", "CSS", "SCSS", "macro"] 24 | categories = ["wasm", "web-programming"] 25 | readme = "README.md" 26 | version.workspace = true 27 | edition.workspace = true 28 | authors.workspace = true 29 | license.workspace = true 30 | repository.workspace = true 31 | publish.workspace = true 32 | 33 | [dependencies] 34 | 35 | [dependencies.turf_macros] 36 | path = "turf_macros" 37 | version = "0.10.1" 38 | -------------------------------------------------------------------------------- /.github/workflows/rust-ci.yml: -------------------------------------------------------------------------------- 1 | name: Rust-CI 2 | 3 | on: 4 | push: {} 5 | pull_request: {} 6 | workflow_dispatch: {} 7 | 8 | env: 9 | CARGO_TERM_COLOR: always 10 | 11 | jobs: 12 | build-debug: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - uses: hecrj/setup-rust-action@v1 17 | with: 18 | rust-version: stable 19 | - name: Debug Build 20 | run: cargo build --verbose 21 | build-release: 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@v3 25 | - uses: hecrj/setup-rust-action@v1 26 | with: 27 | rust-version: stable 28 | - name: Release Build 29 | run: cargo build --release --verbose 30 | test: 31 | runs-on: ubuntu-latest 32 | steps: 33 | - uses: actions/checkout@v3 34 | - uses: hecrj/setup-rust-action@v1 35 | with: 36 | rust-version: stable 37 | - name: Install wasm32 38 | run: rustup target add wasm32-unknown-unknown 39 | - name: Install trunk 40 | run: cargo install --locked trunk 41 | - name: Run tests 42 | run: make test 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 myFavSrimp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /turf_internals/src/manifest.rs: -------------------------------------------------------------------------------- 1 | use std::fs::read_to_string; 2 | 3 | use serde::Deserialize; 4 | 5 | #[derive(Debug, thiserror::Error)] 6 | pub enum ManifestError { 7 | #[error("Could not find the Cargo manifest")] 8 | Path(#[from] std::env::VarError), 9 | #[error("Could not read the Cargo manifest file")] 10 | ReadFile(#[from] std::io::Error), 11 | #[error("Could not read the Cargo manifest's toml")] 12 | ReadToml(#[from] toml::de::Error), 13 | } 14 | 15 | pub fn cargo_manifest() -> Result { 16 | let manifest_path = format!("{}/Cargo.toml", std::env::var("CARGO_MANIFEST_DIR")?); 17 | Ok(toml::de::from_str(&read_to_string(manifest_path)?)?) 18 | } 19 | 20 | #[derive(Deserialize, Debug)] 21 | pub struct ManifestWithPackage { 22 | pub package: Option, 23 | } 24 | 25 | #[derive(Deserialize, Debug)] 26 | pub struct PackageWithMetadata { 27 | pub metadata: Option, 28 | } 29 | 30 | #[derive(Deserialize, Debug)] 31 | pub struct MetadataWithTurfSettings { 32 | pub turf: Option, 33 | #[serde(rename = "turf-dev")] 34 | pub turf_dev: Option, 35 | } 36 | -------------------------------------------------------------------------------- /turf_internals/src/path_utils.rs: -------------------------------------------------------------------------------- 1 | use std::path::{Path, PathBuf}; 2 | 3 | #[derive(thiserror::Error, Debug)] 4 | #[error("error resolving path '{path}' - {source}")] 5 | pub struct PathResolutionError { 6 | pub(crate) path: PathBuf, 7 | pub(crate) source: std::io::Error, 8 | } 9 | 10 | impl From<(PathBuf, std::io::Error)> for PathResolutionError { 11 | fn from(value: (PathBuf, std::io::Error)) -> Self { 12 | Self { 13 | path: value.0, 14 | source: value.1, 15 | } 16 | } 17 | } 18 | 19 | pub fn canonicalize

(path: P) -> Result 20 | where 21 | P: AsRef, 22 | { 23 | let mut canonicalized_path = PathBuf::from( 24 | std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR environment variable"), 25 | ); 26 | canonicalized_path.push(path.as_ref()); 27 | 28 | std::fs::canonicalize(canonicalized_path.clone()).map_err(|e| (canonicalized_path, e).into()) 29 | } 30 | 31 | pub fn get_file_paths_recusively(path: PathBuf) -> Result, PathResolutionError> { 32 | use std::fs::read_dir; 33 | 34 | let path = canonicalize(path)?; 35 | let mut result = Vec::new(); 36 | 37 | for item in read_dir(path.clone()).map_err(|e| (path.clone(), e))? { 38 | let item_path = item.map_err(|e| (path.clone(), e))?.path(); 39 | 40 | if item_path.is_file() { 41 | result.push(canonicalize(item_path)?); 42 | } else if item_path.is_dir() { 43 | result.extend(get_file_paths_recusively(item_path)?); 44 | } 45 | } 46 | 47 | Ok(result) 48 | } 49 | -------------------------------------------------------------------------------- /turf_internals/src/css_compilation.rs: -------------------------------------------------------------------------------- 1 | use std::path::{Path, PathBuf}; 2 | 3 | use crate::{path_utils, Settings, StyleSheetKind}; 4 | 5 | #[derive(thiserror::Error, Debug)] 6 | pub enum CssCompilationError { 7 | #[error("error compiling scss file '{1}' - {0}")] 8 | File(Box, PathBuf), 9 | #[error("error compiling inline scss '{0}'")] 10 | Inline(#[from] Box), 11 | #[error(transparent)] 12 | PathResolutionError(#[from] path_utils::PathResolutionError), 13 | } 14 | 15 | impl

From<(Box, P)> for CssCompilationError 16 | where 17 | P: AsRef + std::fmt::Debug, 18 | { 19 | fn from(value: (Box, P)) -> Self { 20 | let canonicalized_path = value.1.as_ref().canonicalize(); 21 | 22 | match canonicalized_path { 23 | Ok(path) => CssCompilationError::File(value.0, path), 24 | Err(e) => path_utils::PathResolutionError { 25 | path: value.1.as_ref().to_path_buf(), 26 | source: e, 27 | } 28 | .into(), 29 | } 30 | } 31 | } 32 | 33 | pub fn compile_style_sheet( 34 | style_sheet: &StyleSheetKind, 35 | settings: &Settings, 36 | ) -> Result { 37 | Ok(match style_sheet { 38 | StyleSheetKind::File(ref path) => grass::from_path(path, &settings.clone().try_into()?) 39 | .map_err(|e| CssCompilationError::from((e, path.clone())))?, 40 | StyleSheetKind::Inline(ref style_sheet) => { 41 | grass::from_string(style_sheet, &settings.clone().try_into()?)? 42 | } 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /turf_internals/src/file_output.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | fs::{create_dir_all, File}, 3 | io::Write, 4 | path::PathBuf, 5 | }; 6 | 7 | use crate::{settings::FileOutput, StyleSheetKind}; 8 | 9 | static DIRS_RESET: std::sync::OnceLock<()> = std::sync::OnceLock::new(); 10 | 11 | #[derive(Debug, thiserror::Error)] 12 | #[error("error writing css file '{0}' - {1}")] 13 | pub struct CssFileWriteError(PathBuf, std::io::Error); 14 | 15 | fn reset_file_output(output_paths: &FileOutput) -> Result<(), CssFileWriteError> { 16 | if let Some(path) = &output_paths.global_css_file_path { 17 | if let Err(error) = std::fs::remove_file(path) { 18 | match error.kind() { 19 | std::io::ErrorKind::NotFound => {} 20 | _ => Err(CssFileWriteError(path.clone(), error))?, 21 | } 22 | }; 23 | 24 | create_dir_all(path.parent().expect("global css file path has parent dir")) 25 | .map_err(|error| CssFileWriteError(path.clone(), error))?; 26 | } 27 | if let Some(path) = &output_paths.separate_css_files_path { 28 | if let Err(error) = std::fs::remove_dir_all(path) { 29 | match error.kind() { 30 | std::io::ErrorKind::NotFound => {} 31 | _ => Err(CssFileWriteError(path.clone(), error))?, 32 | } 33 | }; 34 | 35 | create_dir_all(path).map_err(|error| CssFileWriteError(path.clone(), error))?; 36 | } 37 | 38 | Ok(()) 39 | } 40 | 41 | fn append_to_separate_file( 42 | style: &str, 43 | mut separate_files_dir: PathBuf, 44 | style_sheet: &StyleSheetKind, 45 | ) -> Result<(), CssFileWriteError> { 46 | match style_sheet { 47 | StyleSheetKind::File(path) => { 48 | separate_files_dir.push(path.file_name().expect("current css file exists")); 49 | separate_files_dir.set_extension("css"); 50 | } 51 | StyleSheetKind::Inline(style_sheet) => { 52 | let hash = xxhash_rust::xxh3::xxh3_64(style_sheet.as_bytes()); 53 | separate_files_dir.push(&format!("{hash:x?}.css")); 54 | } 55 | }; 56 | 57 | let mut output_file = File::options() 58 | .create(true) 59 | .append(true) 60 | .open(&separate_files_dir) 61 | .map_err(|error| CssFileWriteError(separate_files_dir.clone(), error))?; 62 | 63 | output_file 64 | .write_all(style.as_bytes()) 65 | .map_err(|error| CssFileWriteError(separate_files_dir, error))?; 66 | 67 | Ok(()) 68 | } 69 | 70 | fn append_to_global_file(style: &str, global_file_path: &PathBuf) -> Result<(), CssFileWriteError> { 71 | let mut global_css_file = File::options() 72 | .create(true) 73 | .append(true) 74 | .open(global_file_path) 75 | .map_err(|error| CssFileWriteError(global_file_path.clone(), error))?; 76 | 77 | global_css_file 78 | .write_all(style.as_bytes()) 79 | .map_err(|error| CssFileWriteError(global_file_path.clone(), error))?; 80 | 81 | Ok(()) 82 | } 83 | 84 | pub fn perform_css_file_output( 85 | output_paths: FileOutput, 86 | style: &str, 87 | style_sheet_kind: &StyleSheetKind, 88 | ) -> Result<(), CssFileWriteError> { 89 | if DIRS_RESET.get().is_none() { 90 | reset_file_output(&output_paths)?; 91 | 92 | DIRS_RESET 93 | .set(()) 94 | .expect("internal turf state has already been set, but should be empty"); 95 | } 96 | 97 | if let Some(output_path) = output_paths.separate_css_files_path { 98 | append_to_separate_file(style, output_path, style_sheet_kind)?; 99 | } 100 | 101 | if let Some(output_path) = output_paths.global_css_file_path { 102 | append_to_global_file(style, &output_path)?; 103 | } 104 | 105 | Ok(()) 106 | } 107 | -------------------------------------------------------------------------------- /turf_internals/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! You're probably looking for `turf` instead. 2 | 3 | mod css_compilation; 4 | mod file_output; 5 | mod hashing; 6 | mod manifest; 7 | mod path_utils; 8 | mod settings; 9 | mod transformer; 10 | 11 | use std::{collections::HashMap, path::PathBuf, sync::Mutex}; 12 | 13 | pub use settings::Settings; 14 | 15 | #[derive(thiserror::Error, Debug)] 16 | pub enum Error { 17 | #[error(transparent)] 18 | CssCompilation(#[from] css_compilation::CssCompilationError), 19 | #[error(transparent)] 20 | Hashing(#[from] hashing::StyleSheetHashingError), 21 | #[error("error transforming css - {0}")] 22 | CssTransformation(#[from] transformer::TransformationError), 23 | #[error("no input file was specified")] 24 | NoInputFile, 25 | #[error(transparent)] 26 | PathResolution(#[from] path_utils::PathResolutionError), 27 | 28 | #[error(transparent)] 29 | CssFileWrite(#[from] file_output::CssFileWriteError), 30 | #[error(transparent)] 31 | Settings(#[from] settings::SettingsError), 32 | } 33 | 34 | fn compile_message(message: &str) { 35 | println!("🌱 turf [INFO]: {message}"); 36 | } 37 | 38 | #[derive(Debug)] 39 | pub enum StyleSheetKind { 40 | File(PathBuf), 41 | Inline(String), 42 | } 43 | 44 | #[derive(Debug)] 45 | pub struct CompiledStyleSheet { 46 | pub css: String, 47 | pub class_names: HashMap, 48 | pub original_style_sheet: StyleSheetKind, 49 | } 50 | 51 | fn style_sheet_with_compile_options( 52 | style_sheet_input: StyleSheetKind, 53 | settings: Settings, 54 | ) -> Result { 55 | let hash = hashing::hash_style_sheet(&style_sheet_input)?; 56 | let css = css_compilation::compile_style_sheet(&style_sheet_input, &settings)?; 57 | 58 | let (style_sheet_css, class_names) = 59 | transformer::transform_stylesheet(&css, &hash, settings.clone())?; 60 | 61 | if let Some(file_output) = settings.file_output { 62 | file_output::perform_css_file_output(file_output, &style_sheet_css, &style_sheet_input)?; 63 | } 64 | 65 | Ok(CompiledStyleSheet { 66 | css: style_sheet_css, 67 | class_names, 68 | original_style_sheet: style_sheet_input, 69 | }) 70 | } 71 | 72 | pub fn style_sheet(style_sheet: StyleSheetKind) -> Result { 73 | let settings = Settings::get()?; 74 | 75 | let style_sheet = match style_sheet { 76 | StyleSheetKind::File(path) => { 77 | if path == PathBuf::from("") { 78 | return Err(crate::Error::NoInputFile); 79 | }; 80 | let canonicalized_path = path_utils::canonicalize(path)?; 81 | StyleSheetKind::File(canonicalized_path) 82 | } 83 | StyleSheetKind::Inline(inline_style_sheet) => StyleSheetKind::Inline(inline_style_sheet), 84 | }; 85 | 86 | style_sheet_with_compile_options(style_sheet, settings) 87 | } 88 | 89 | static LOAD_PATHS_TRACKED: Mutex = Mutex::new(false); 90 | 91 | #[derive(Debug, thiserror::Error)] 92 | pub enum LoadPathTrackingError { 93 | #[error("Could not read internal state")] 94 | Mutex, 95 | #[error(transparent)] 96 | Settings(#[from] settings::SettingsError), 97 | #[error(transparent)] 98 | PathResolution(#[from] path_utils::PathResolutionError), 99 | } 100 | 101 | pub fn get_untracked_load_paths() -> Result, LoadPathTrackingError> { 102 | let mut load_paths_tracked = match LOAD_PATHS_TRACKED.lock() { 103 | Err(_) => return Err(LoadPathTrackingError::Mutex), 104 | Ok(val) => val, 105 | }; 106 | 107 | if *load_paths_tracked { 108 | Ok(Vec::new()) 109 | } else { 110 | let settings = Settings::get()?; 111 | *load_paths_tracked = true; 112 | 113 | let mut result = Vec::new(); 114 | 115 | for path in settings.load_paths { 116 | result.extend(path_utils::get_file_paths_recusively(path)?); 117 | } 118 | 119 | Ok(result) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.10.1 2 | 3 | - Changed default class name template to a deterministic hash (thank you @TimTom2016 for creating a pr) 4 | 5 | # 0.10.0 6 | 7 | - Replaced object-based browser targets configuration with browserslist format 8 | 9 | # 0.9.6 10 | 11 | - Fixed vendor prefixing 12 | 13 | # 0.9.5 14 | 15 | - Fixed build on windows 16 | 17 | # 0.9.4 18 | 19 | - Add ``, ``, ``, and `` placeholders into `package.metadata.turf.class_names.template` configuration option (thank you @lukidoescode for creating a pr) 20 | 21 | # 0.9.3 22 | 23 | - Updated lightningcss 24 | 25 | # 0.9.2 26 | 27 | - Fixed settings parsing of browser version target arrays with a single major version specification (thank you @emnul for reporting the issue) 28 | 29 | # 0.9.1 30 | 31 | - Added error source information to error messages 32 | 33 | # 0.9.0 34 | 35 | - Updated dependencies 36 | - Renamed the `inline_style_sheet` macro to `style_sheet_values` to avoid confusion 37 | - Added the `inline_style_sheet` and `inline_style_sheet_values` macros to allow inline SCSS style definitions 38 | - Changed `randomized_class_name` to use base64 ids rather than numeric ids for randomizing class ids (thank you @BToersche) 39 | - Added support for `any`, `has`, `host`, `is`, `not`, `slotted` and `where` CSS pseudo classes. (thank you @BToersche) 40 | 41 | # 0.8.0 42 | 43 | - Updated dependencies 44 | - Removed `once_cell` feature flag 45 | - Removed support for Rust 1.65 46 | 47 | # 0.7.1 48 | - Fixed compilation on minimum supported Rust version by pinning dependency versions 49 | - Restructured project to allow specifying dependency from git repo 50 | 51 | # 0.7.0 52 | - Added optional configurable file output of the resulting CSS 53 | - Added the alternative `inline_style_sheet` macro which directly returns the CSS style sheet and a class names struct 54 | - The class name configuration is now located under the `class_names` key 55 | - Added the `excludes` configuration option for excluding class names from the uniquification process using regex 56 | - The minimum supported Rust version has been bumped to 1.65.0 57 | 58 | # 0.6.2 59 | - Fixed failing builds due to a badly specified dependency in one of turf's dependencies (thank you @xeho91 for offering a quick fix) 60 | - Updated lightningcss 61 | 62 | # 0.6.1 63 | - Fixed an error with the new path resolution which resulted in incorrect paths being used for the file tracking 64 | 65 | # 0.6.0 66 | - Added tracking of style sheets and files in `load_paths` (SCSS recompilation on file changes) 67 | - `load_paths` are now relative to the project directory they are specified in when using workspaces 68 | 69 | # 0.5.0 70 | - Updated grass to `0.13` (see [here](https://github.com/connorskees/grass/blob/master/CHANGELOG.md)) 71 | - Added instructions to trigger recompilation on SCSS style changes 72 | - `ClassName` is now `pub` (thank you @xeho91 for creating a pull request) 73 | - `STYLE_SHEET` is now `pub` 74 | 75 | # 0.4.1 76 | - Improved messages of errors with the SCCS input file path 77 | - Fixed a misleading file path in error messages when using Cargo workspaces 78 | 79 | # 0.4.0 80 | - Minimum supported Rust version is now 1.70.0 81 | - New `once_cell` feature flag for backward compatibility down to Rust version 1.64.0 82 | - Added `[package.metadata.turf-dev]` profile for separate development and production build settings 83 | - The configuration is now cached to avoid reading it repeatedly from the config for every macro invocation 84 | - Added a `debug` configuration setting for debug output 85 | - Improved the SCSS compilation error message by providing the file path to the SCSS file that caused the error 86 | 87 | # 0.3.2 88 | - pinned version of `lightningcss` and `lightningcss-derive` to prevent incompatible releases from being used 89 | 90 | # 0.3.1 91 | - fixed an issue that resulted in a compile error (thank you @xeho91 for reporting the issue and creating a pr!) #1 #2 92 | 93 | # 0.3.0 94 | - [lightningcss](https://github.com/parcel-bundler/lightningcss) integration for minifying and optimizing CSS 95 | - configurable class name generation with unique and dynamic names 96 | - support for specifying browser targets and versions for CSS compatibility 97 | - improved documentation and examples 98 | 99 | # 0.2.1 100 | - Updated description / README 101 | 102 | # 0.2.0 103 | - removed configured_style_sheet 104 | - the style_sheet macro now reads the configuration from Cargo.toml like configured_style_sheet did and uses default settings as fallback 105 | 106 | # 0.1.1 107 | 108 | # 0.1.0 109 | -------------------------------------------------------------------------------- /turf_macros/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! You're probably looking for `turf` instead. 2 | 3 | use convert_case::{Case, Casing}; 4 | use std::{collections::HashMap, path::PathBuf}; 5 | use turf_internals::{CompiledStyleSheet, StyleSheetKind}; 6 | 7 | use proc_macro::TokenStream; 8 | use quote::quote; 9 | 10 | #[proc_macro] 11 | pub fn style_sheet(input: TokenStream) -> TokenStream { 12 | let input = input.to_string(); 13 | let sanitized_path = PathBuf::from(input.trim_matches('"')); 14 | 15 | let ProcessedStyleSheet { 16 | untracked_load_paths, 17 | css, 18 | class_names, 19 | } = match handle_style_sheet(StyleSheetKind::File(sanitized_path)) { 20 | Ok(result) => result, 21 | Err(e) => { 22 | return match e { 23 | Error::Turf(e) => to_compile_error(e), 24 | Error::LoadPathTracking(e) => to_compile_error(e), 25 | } 26 | } 27 | }; 28 | 29 | let mut out = quote! { 30 | pub static STYLE_SHEET: &'static str = #css; 31 | }; 32 | out.extend(create_classes_structure(class_names)); 33 | out.extend(create_include_bytes(untracked_load_paths)); 34 | 35 | out.into() 36 | } 37 | 38 | #[proc_macro] 39 | pub fn style_sheet_values(input: TokenStream) -> TokenStream { 40 | let input = input.to_string(); 41 | let sanitized_path = PathBuf::from(input.trim_matches('"')); 42 | 43 | let ProcessedStyleSheet { 44 | untracked_load_paths, 45 | css, 46 | class_names, 47 | } = match handle_style_sheet(StyleSheetKind::File(sanitized_path)) { 48 | Ok(result) => result, 49 | Err(e) => { 50 | return match e { 51 | Error::Turf(e) => to_compile_error(e), 52 | Error::LoadPathTracking(e) => to_compile_error(e), 53 | } 54 | } 55 | }; 56 | 57 | let includes = create_include_bytes(untracked_load_paths); 58 | let inlines = create_inline_classes_instance(class_names); 59 | let out = quote! {{ 60 | pub static STYLE_SHEET: &'static str = #css; 61 | #includes 62 | #inlines 63 | }}; 64 | 65 | out.into() 66 | } 67 | 68 | #[proc_macro] 69 | pub fn inline_style_sheet(input: TokenStream) -> TokenStream { 70 | let input = input.to_string(); 71 | 72 | let ProcessedStyleSheet { 73 | untracked_load_paths, 74 | css, 75 | class_names, 76 | } = match handle_style_sheet(StyleSheetKind::Inline(input)) { 77 | Ok(result) => result, 78 | Err(e) => { 79 | return match e { 80 | Error::Turf(e) => to_compile_error(e), 81 | Error::LoadPathTracking(e) => to_compile_error(e), 82 | } 83 | } 84 | }; 85 | 86 | let mut out = quote! { 87 | pub static STYLE_SHEET: &'static str = #css; 88 | }; 89 | out.extend(create_classes_structure(class_names)); 90 | out.extend(create_include_bytes(untracked_load_paths)); 91 | 92 | out.into() 93 | } 94 | 95 | #[proc_macro] 96 | pub fn inline_style_sheet_values(input: TokenStream) -> TokenStream { 97 | let input = input.to_string(); 98 | 99 | let ProcessedStyleSheet { 100 | untracked_load_paths, 101 | css, 102 | class_names, 103 | } = match handle_style_sheet(StyleSheetKind::Inline(input)) { 104 | Ok(result) => result, 105 | Err(e) => { 106 | return match e { 107 | Error::Turf(e) => to_compile_error(e), 108 | Error::LoadPathTracking(e) => to_compile_error(e), 109 | } 110 | } 111 | }; 112 | 113 | let includes = create_include_bytes(untracked_load_paths); 114 | let inlines = create_inline_classes_instance(class_names); 115 | let out = quote! {{ 116 | pub static STYLE_SHEET: &'static str = #css; 117 | #includes 118 | #inlines 119 | }}; 120 | 121 | out.into() 122 | } 123 | 124 | fn to_compile_error(e: E) -> TokenStream 125 | where 126 | E: std::error::Error, 127 | { 128 | let mut message = format!("Error: {}", e); 129 | let mut curr_err = e.source(); 130 | 131 | if curr_err.is_some() { 132 | message.push_str("\nCaused by:"); 133 | } 134 | 135 | while let Some(current_error) = curr_err { 136 | message.push_str(&format!("\n {}", current_error)); 137 | curr_err = current_error.source(); 138 | } 139 | 140 | quote! { 141 | compile_error!(#message); 142 | } 143 | .into() 144 | } 145 | 146 | fn create_classes_structure(classes: HashMap) -> proc_macro2::TokenStream { 147 | let original_class_names: Vec = classes 148 | .keys() 149 | .map(|class| class.to_case(Case::ScreamingSnake)) 150 | .map(|class| quote::format_ident!("{}", class.as_str().to_uppercase())) 151 | .collect(); 152 | 153 | let randomized_class_names: Vec<&String> = classes.values().collect(); 154 | 155 | let doc = original_class_names 156 | .iter() 157 | .zip(randomized_class_names.iter()) 158 | .fold(String::new(), |mut doc, (variable, class_name)| { 159 | doc.push_str(&format!("{} = \"{}\"\n", variable, class_name)); 160 | doc 161 | }); 162 | 163 | quote::quote! { 164 | #[doc=#doc] 165 | pub struct ClassName; 166 | impl ClassName { 167 | #(pub const #original_class_names: &'static str = #randomized_class_names;)* 168 | } 169 | } 170 | } 171 | 172 | fn create_inline_classes_instance(classes: HashMap) -> proc_macro2::TokenStream { 173 | let original_class_names: Vec = classes 174 | .keys() 175 | .map(|class| class.to_case(Case::Snake)) 176 | .map(|class| quote::format_ident!("{}", class.as_str())) 177 | .collect(); 178 | 179 | let randomized_class_names: Vec<&String> = classes.values().collect(); 180 | 181 | let doc = original_class_names 182 | .iter() 183 | .zip(randomized_class_names.iter()) 184 | .fold(String::new(), |mut doc, (variable, class_name)| { 185 | doc.push_str(&format!("{} = \"{}\"\n", variable, class_name)); 186 | doc 187 | }); 188 | 189 | quote::quote! { 190 | #[doc=#doc] 191 | pub struct ClassNames { 192 | #(pub #original_class_names: &'static str,)* 193 | } 194 | impl ClassNames { 195 | pub fn new() -> Self { 196 | Self { 197 | #(#original_class_names: #randomized_class_names,)* 198 | } 199 | } 200 | } 201 | 202 | (STYLE_SHEET, ClassNames::new()) 203 | } 204 | } 205 | 206 | fn create_include_bytes(untracked_load_paths: Vec) -> proc_macro2::TokenStream { 207 | let untracked_load_path_values: Vec = untracked_load_paths 208 | .into_iter() 209 | .map(|item| format!("{}", item.as_path().display())) 210 | .collect(); 211 | 212 | quote::quote! { 213 | #(const _: &[u8] = include_bytes!(#untracked_load_path_values);)* 214 | } 215 | } 216 | 217 | enum Error { 218 | Turf(turf_internals::Error), 219 | LoadPathTracking(turf_internals::LoadPathTrackingError), 220 | } 221 | 222 | struct ProcessedStyleSheet { 223 | untracked_load_paths: Vec, 224 | css: String, 225 | class_names: HashMap, 226 | } 227 | 228 | fn handle_style_sheet(style_sheet: StyleSheetKind) -> Result { 229 | let CompiledStyleSheet { 230 | css, 231 | class_names, 232 | original_style_sheet, 233 | } = turf_internals::style_sheet(style_sheet).map_err(Error::Turf)?; 234 | 235 | let untracked_load_paths = { 236 | let mut values = 237 | turf_internals::get_untracked_load_paths().map_err(Error::LoadPathTracking)?; 238 | 239 | if let StyleSheetKind::File(current_file_path) = original_style_sheet { 240 | values.push(current_file_path); 241 | } 242 | 243 | values 244 | }; 245 | 246 | Ok(ProcessedStyleSheet { 247 | untracked_load_paths, 248 | css, 249 | class_names, 250 | }) 251 | } 252 | 253 | #[cfg(test)] 254 | mod tests { 255 | use std::collections::HashMap; 256 | 257 | use super::create_classes_structure; 258 | 259 | #[test] 260 | fn test() { 261 | let mut class_names = HashMap::new(); 262 | class_names.insert(String::from("test-class"), String::from("abc-123")); 263 | 264 | let out = create_classes_structure(class_names); 265 | 266 | assert_eq!( 267 | out.to_string(), 268 | quote::quote! { 269 | #[doc="TEST_CLASS = \"abc-123\"\n"] 270 | pub struct ClassName; 271 | impl ClassName { 272 | pub const TEST_CLASS: &'static str = "abc-123"; 273 | } 274 | } 275 | .to_string() 276 | ) 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # turf 🌱 2 | 3 | > **Warning** | The repository reflects the current development state, which may differ from the released version. 4 | 5 | `turf` allows you to build SCSS to CSS during compile time and inject those styles into your binary. 6 | 7 | [![Crates.io][crates-badge]][crates-url] 8 | [![Docs.rs][docs-badge]][docs-url] 9 | [![Build Status][actions-badge]][actions-url] 10 | [![MIT licensed][lic-badge]][lic-url] 11 | 12 | [crates-badge]: https://img.shields.io/crates/v/turf.svg 13 | [crates-url]: https://crates.io/crates/turf 14 | [docs-badge]: https://img.shields.io/docsrs/turf/latest.svg?logo=docsdotrs&label=docs.rs 15 | [docs-url]: https://docs.rs/turf 16 | [actions-badge]: https://github.com/myFavShrimp/turf/actions/workflows/rust-ci.yml/badge.svg 17 | [actions-url]: https://github.com/myFavShrimp/turf/actions/workflows/rust-ci.yml 18 | [lic-url]: https://github.com/myFavShrimp/turf/blob/master/LICENSE 19 | [lic-badge]: https://img.shields.io/badge/license-MIT-blue.svg 20 | 21 | **turf will:** 22 | 23 | - 🌿 transform your SCSS files into CSS with [grass](https://github.com/connorskees/grass/), right at compilation time 24 | - 🪴 generate unique and dynamic class names for your CSS during compilation 25 | - 🔬 minify and optimize your CSS using [lightningcss](https://github.com/parcel-bundler/lightningcss), ensuring compatibility with various browser targets 26 | - 🎨 inject the generated CSS into your binary, guaranteeing quick access to your styles whenever you need them 27 | 28 | ## Usage 29 | 30 | For a complete runnable example project, you can check out one of the examples: 31 | 32 | | [leptos-example](https://github.com/myFavShrimp/turf/tree/main/examples/leptos-example) | [yew-example](https://github.com/myFavShrimp/turf/tree/main/examples/yew-example) | [dioxus-example](https://github.com/myFavShrimp/turf/tree/main/examples/dioxus-example) | [axum-askama-htmx](https://github.com/myFavShrimp/turf/tree/main/examples/axum-askama-htmx) | 33 | | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | 34 | 35 | **1. Create SCSS styles for your application** 36 | 37 | ```scss 38 | // file at scss/file/path.scss 39 | 40 | .TopLevelClass { 41 | color: red; 42 | 43 | .SomeClass { 44 | color: blue; 45 | } 46 | } 47 | ``` 48 | 49 | **2. Use the `style_sheet` macro to include the resulting CSS in your code** 50 | 51 | ```rust,ignore 52 | turf::style_sheet!("scss/file/path.scss"); 53 | ``` 54 | 55 | The macro from the above example will expand to the following code: 56 | 57 | ```rust 58 | static STYLE_SHEET: &'static str = ""; 59 | struct ClassName; 60 | impl ClassName { 61 | pub const TOP_LEVEL_CLASS: &'static str = ""; 62 | pub const SOME_CLASS: &'static str = ""; 63 | } 64 | ``` 65 | 66 | **3. Use the `ClassName` struct and its associated constants to access the generated class names** 67 | 68 | ```rust,ignore 69 | let top_level_class_name = ClassName::TOP_LEVEL_CLASS; 70 | let some_class_name = ClassName::SOME_CLASS; 71 | ``` 72 | 73 | ### Configuration 74 | 75 | The configuration for turf can be specified in the Cargo.toml file using the `[package.metadata.turf]` and `[package.metadata.turf-dev]` keys. This allows you to conveniently manage your SCSS compilation settings for both development and production builds within your project's manifest. 76 | 77 | Both profiles offer the exact same configuration options. However, if you haven't specified a `[package.metadata.turf-dev]` profile, the `[package.metadata.turf]` settings will also be applied to debug builds. This ensures consistency in the compilation process across different build types unless you explicitly define a separate configuration for the development profile. 78 | 79 | Example configuration: 80 | 81 | ```toml 82 | [package.metadata.turf] 83 | minify = true 84 | load_paths = ["path/to/shared/scss/files", "path/to/other/shared/scss/files"] 85 | browser_targets = [ 86 | "defaults", 87 | "> 5%", 88 | "safari 12", 89 | ] 90 | 91 | [package.metadata.turf.class_names] 92 | template = "-with-custom-" 93 | excludes = ["exclude-this-class-please", "^abc-[123]{4}"] 94 | 95 | [package.metadata.turf.file_output] 96 | global_css_file_path = "path/to/global.css" 97 | separate_css_files_path = "dir/for/separate/css/" 98 | ``` 99 | 100 | The following configuration options are available: 101 | 102 | - `minify` (default: `true`): Specifies whether the generated CSS should be minified or not. If set to true, the CSS output will be compressed and optimized for reduced file size. If set to false, the CSS output will be formatted with indentation and line breaks for improved readability. 103 | 104 | - `load_paths`: Specifies additional paths to search for SCSS files to include during compilation. It accepts a list of string values, where each value represents a directory path to be included. This option allows you to import SCSS files from multiple directories. 105 | 106 | - `browser_targets`: Defines the target browser versions for compatibility when generating CSS. It accepts an array of strings in [browserslist](https://browsersl.ist/) format (e.g., "defaults", "> 5%", "safari 12"). This ensures the generated CSS is compatible with the specified browser versions. 107 | 108 | - `class_names`: Allows configuration of the CSS class name generation. It expects a structure that contains two values for generating CSS class names and excluding class names from the uniquification process. 109 | 110 | - `debug` (default: `false`): When set to true, this option will enable debug output of the read configuration and the generated CSS class names. This can be helpful for troubleshooting and understanding how the CSS is being generated. 111 | 112 | - `file_output`: Enables output of compiled CSS. It expects a structure that contains two values for a single global CSS file or separate CSS files for each compiled SCSS file. 113 | 114 | #### The `class_names` Key 115 | 116 | - `template` (default: `"class-"`): Specifies the template for generating randomized CSS class names. The template can include placeholders to customize the output: 117 | - `` will be replaced with a unique identifier for each CSS class name 118 | - `` will be replaced with the original class name from the SCSS file 119 | - `` will be replaced with the hash of the original class name from the SCSS file 120 | - `` will be replaced with the first 5 characters of the hash of the original class name from the SCSS file 121 | - `` will be replaced with the hash of the SCSS file 122 | - `` will be replaced with the first 8 characters of the hash of the SCSS file 123 | 124 | - `excludes`: An array of regex patterns that exclude class names in your SCSS files from the class name uniquification process. 125 | 126 | #### The `file_output` Key 127 | 128 | - `global_css_file_path`: Specifies the file path for a global CSS file. If set, a CSS file will be created at the provided path, and all compiled styles will be written to this file. This allows you to have a single CSS file containing all the compiled styles. 129 | 130 | - `separate_css_files_path`: Specifies the directory path for separate CSS files. If set, all compiled CSS files will be saved in the specified directory. Each compiled SCSS file will have its corresponding CSS file in this directory, allowing for modular CSS management. The file name for inline SCSS style definitions will be a 64 bit hash that is computed from the original SCSS style. 131 | 132 | ### Additional Macros 133 | 134 | turf provides a few additional macros for other use cases. 135 | 136 | #### The `style_sheet_values` Macro 137 | 138 | In some cases, it may be necessary to have a struct's instance to access the class names (for example when using turf in [askama](https://github.com/djc/askama) templates). 139 | The `turf::style_sheet_values` macro provides an alternative to directly including the resulting CSS and obtaining the associated class names. It returns a tuple of `(style_sheet: &'static str, class_names: struct)`. 140 | 141 | **Usage:** 142 | 143 | ```rust,ignore 144 | let (style_sheet, class_names) = turf::style_sheet_values!("path/to/style.scss"); 145 | let some_class_name = class_names.some_class; 146 | ``` 147 | 148 | #### The `inline_style_sheet` Macro 149 | 150 | If you don't want your style sheet to live in another file, you can use the `turf::inline_style_sheet` macro. It allows you to write inline SCSS which will then be compiled to CSS. 151 | 152 | **Usage:** 153 | 154 | ```rust,ignore 155 | turf::inline_style_sheet! { 156 | .TopLevelClass { 157 | color: red; 158 | 159 | .SomeClass { 160 | color: blue; 161 | } 162 | } 163 | } 164 | 165 | // ... 166 | 167 | let some_class_name = ClassName::SOME_CLASS; 168 | ``` 169 | 170 | #### The `inline_style_sheet_values` Macro 171 | 172 | This macro combines the functionality of both the `style_sheet_values` and `inline_style_sheet` macros. It allows you to write inline SCSS and returns an tuple of `(style_sheet: &'static str, class_names: struct)`. 173 | 174 | **Usage:** 175 | 176 | ```rust,ignore 177 | let (style_sheet, class_names) = turf::inline_style_sheet_values! { 178 | .TopLevelClass { 179 | color: red; 180 | 181 | .SomeClass { 182 | color: blue; 183 | } 184 | } 185 | }; 186 | let some_class_name = class_names.some_class; 187 | ``` 188 | 189 | ## Contributions 190 | 191 | Contributions to turf are always welcome! Whether you have ideas for new features or improvements, don't hesitate to open an issue or submit a pull request. 🤝 192 | 193 | ## License 194 | 195 | turf is licensed under the MIT license. For more details, please refer to the LICENSE file. 📄 196 | -------------------------------------------------------------------------------- /turf_internals/src/settings.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | use serde::Deserialize; 4 | 5 | use crate::{ 6 | manifest::ManifestError, 7 | path_utils::{canonicalize, PathResolutionError}, 8 | }; 9 | 10 | #[derive(Deserialize, Debug, Default, Clone)] 11 | pub struct FileOutput { 12 | pub(crate) global_css_file_path: Option, 13 | pub(crate) separate_css_files_path: Option, 14 | } 15 | 16 | pub(crate) static DEFAULT_CLASS_NAME_TEMPLATE: &str = 17 | "class-"; 18 | 19 | #[derive(Deserialize, Debug, Clone, PartialEq)] 20 | pub struct ClassNameGeneration { 21 | pub(crate) template: String, 22 | #[serde(default)] 23 | pub(crate) excludes: Vec, 24 | } 25 | 26 | impl Default for ClassNameGeneration { 27 | fn default() -> Self { 28 | Self { 29 | template: DEFAULT_CLASS_NAME_TEMPLATE.to_owned(), 30 | excludes: vec![], 31 | } 32 | } 33 | } 34 | 35 | pub(crate) static DEFAULT_MINIFY: bool = true; 36 | 37 | fn default_minify() -> bool { 38 | DEFAULT_MINIFY 39 | } 40 | 41 | #[derive(Deserialize, Debug, Clone)] 42 | pub struct Settings { 43 | #[serde(default)] 44 | pub(crate) debug: bool, 45 | #[serde(default = "default_minify")] 46 | pub(crate) minify: bool, 47 | #[serde(default)] 48 | pub(crate) load_paths: Vec, 49 | #[serde(default)] 50 | pub(crate) browser_targets: BrowserTargets, 51 | #[serde(default)] 52 | pub(crate) class_names: ClassNameGeneration, 53 | pub(crate) file_output: Option, 54 | } 55 | 56 | impl Default for Settings { 57 | fn default() -> Self { 58 | Self { 59 | debug: false, 60 | minify: DEFAULT_MINIFY, 61 | load_paths: Vec::new(), 62 | browser_targets: BrowserTargets(None), 63 | class_names: ClassNameGeneration::default(), 64 | file_output: None, 65 | } 66 | } 67 | } 68 | 69 | impl Settings { 70 | pub fn canonicalized_load_paths(&self) -> Result, PathResolutionError> { 71 | self.load_paths 72 | .clone() 73 | .into_iter() 74 | .map(canonicalize) 75 | .collect() 76 | } 77 | } 78 | 79 | impl<'a> TryFrom for grass::Options<'a> { 80 | type Error = PathResolutionError; 81 | 82 | fn try_from(val: Settings) -> Result { 83 | Ok(grass::Options::default() 84 | .style(grass::OutputStyle::Expanded) 85 | .load_paths(&val.canonicalized_load_paths()?)) 86 | } 87 | } 88 | 89 | impl<'a> From for lightningcss::printer::PrinterOptions<'a> { 90 | fn from(val: Settings) -> Self { 91 | lightningcss::printer::PrinterOptions { 92 | minify: val.minify, 93 | project_root: None, 94 | targets: val.browser_targets.0.into(), 95 | analyze_dependencies: None, 96 | pseudo_classes: None, 97 | } 98 | } 99 | } 100 | 101 | #[derive(Deserialize, Debug, Default, Clone)] 102 | #[serde(try_from = "RawBrowserTargets")] 103 | pub struct BrowserTargets(pub Option); 104 | 105 | #[derive(Deserialize, Debug, Default, Clone)] 106 | pub struct RawBrowserTargets(Vec); 107 | 108 | #[derive(Debug, thiserror::Error)] 109 | #[error("Error reading browser_targets: {0:#?}")] 110 | pub struct FromRawTargetsErrorCollection(Vec); 111 | 112 | #[derive(thiserror::Error)] 113 | #[error("Failed to read browser target: {target:?} - {error}")] 114 | pub struct FromRawTargetsError { 115 | target: String, 116 | error: String, 117 | } 118 | 119 | impl std::fmt::Debug for FromRawTargetsError { 120 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 121 | f.write_str(&self.to_string()) 122 | } 123 | } 124 | 125 | impl TryFrom for BrowserTargets { 126 | type Error = FromRawTargetsErrorCollection; 127 | 128 | fn try_from(value: RawBrowserTargets) -> Result { 129 | let errors = value 130 | .0 131 | .iter() 132 | .filter_map(|target| { 133 | match lightningcss::targets::Browsers::from_browserslist([target]) { 134 | Ok(_) => None, 135 | Err(e) => Some(FromRawTargetsError { 136 | error: e.to_string(), 137 | target: target.clone(), 138 | }), 139 | } 140 | }) 141 | .collect::>(); 142 | 143 | if !errors.is_empty() { 144 | return Err(FromRawTargetsErrorCollection(errors)); 145 | } 146 | 147 | Ok( 148 | lightningcss::targets::Browsers::from_browserslist(value.0.clone()) 149 | .map(BrowserTargets) 150 | .unwrap(), 151 | ) 152 | } 153 | } 154 | 155 | static TURF_SETTINGS: std::sync::OnceLock = std::sync::OnceLock::new(); 156 | static TURF_DEV_SETTINGS: std::sync::OnceLock = std::sync::OnceLock::new(); 157 | 158 | #[derive(Debug, thiserror::Error)] 159 | #[error("Could not obtain turf settings from the Cargo manifest")] 160 | pub struct SettingsError(#[from] ManifestError); 161 | 162 | impl Settings { 163 | pub fn get() -> Result { 164 | let dev_settings = Self::dev_profile_settings()?; 165 | let prod_settings = Self::prod_profile_settings()?; 166 | 167 | Ok(Self::choose_settings( 168 | dev_settings, 169 | prod_settings, 170 | cfg!(debug_assertions), 171 | )) 172 | } 173 | 174 | fn choose_settings( 175 | dev: Option, 176 | prod: Option, 177 | is_debug_build: bool, 178 | ) -> Self { 179 | if let (Some(cfg), true) = (dev.or(prod.clone()), is_debug_build) { 180 | cfg 181 | } else if let (Some(cfg), false) = (prod, is_debug_build) { 182 | cfg 183 | } else { 184 | Settings::default() 185 | } 186 | } 187 | 188 | fn dev_profile_settings() -> Result, SettingsError> { 189 | if let Some(turf_dev_settings) = TURF_DEV_SETTINGS.get() { 190 | return Ok(Some(turf_dev_settings.clone())); 191 | } 192 | 193 | let dev_settings_maybe = crate::manifest::cargo_manifest()? 194 | .package 195 | .and_then(|package| package.metadata) 196 | .and_then(|metadata| metadata.turf_dev); 197 | 198 | if let Some(turf_dev_settings) = dev_settings_maybe.clone() { 199 | TURF_DEV_SETTINGS 200 | .set(turf_dev_settings) 201 | .expect("internal turf-dev settings have already been set, but should be empty"); 202 | } 203 | 204 | Ok(dev_settings_maybe) 205 | } 206 | 207 | fn prod_profile_settings() -> Result, SettingsError> { 208 | if let Some(turf_prod_settings) = TURF_SETTINGS.get() { 209 | return Ok(Some(turf_prod_settings.clone())); 210 | } 211 | 212 | let prod_settings_maybe = crate::manifest::cargo_manifest()? 213 | .package 214 | .and_then(|package| package.metadata) 215 | .and_then(|metadata| metadata.turf); 216 | 217 | if let Some(turf_prod_settings) = prod_settings_maybe.clone() { 218 | TURF_SETTINGS 219 | .set(turf_prod_settings) 220 | .expect("internal turf settings have already been set, but should be empty"); 221 | } 222 | 223 | Ok(prod_settings_maybe) 224 | } 225 | } 226 | 227 | #[cfg(test)] 228 | mod debug_tests { 229 | use crate::settings::ClassNameGeneration; 230 | 231 | use super::Settings; 232 | 233 | #[test] 234 | fn use_dev_settings_for_debug_build() { 235 | let mut dev_settings = Settings::default(); 236 | let class_name_generation = ClassNameGeneration { 237 | template: String::from("abc"), 238 | ..Default::default() 239 | }; 240 | dev_settings.class_names = class_name_generation; 241 | 242 | let mut prod_settings = Settings::default(); 243 | let class_name_generation = ClassNameGeneration { 244 | template: String::from("def"), 245 | ..Default::default() 246 | }; 247 | prod_settings.class_names = class_name_generation; 248 | 249 | let selected_settings = 250 | Settings::choose_settings(Some(dev_settings.clone()), Some(prod_settings), true); 251 | 252 | assert_eq!(selected_settings.class_names, dev_settings.class_names); 253 | } 254 | 255 | #[test] 256 | fn use_prod_settings_for_debug_build_when_no_dev_settings_where_given() { 257 | let mut prod_settings = Settings::default(); 258 | let class_name_generation = ClassNameGeneration { 259 | template: String::from("def"), 260 | ..Default::default() 261 | }; 262 | prod_settings.class_names = class_name_generation; 263 | 264 | let selected_settings = Settings::choose_settings(None, Some(prod_settings.clone()), true); 265 | 266 | assert_eq!(selected_settings.class_names, prod_settings.class_names); 267 | } 268 | 269 | #[test] 270 | fn use_prod_settings_for_release_build() { 271 | let mut dev_settings = Settings::default(); 272 | let class_name_generation = ClassNameGeneration { 273 | template: String::from("abc"), 274 | ..Default::default() 275 | }; 276 | dev_settings.class_names = class_name_generation; 277 | 278 | let mut prod_settings = Settings::default(); 279 | let class_name_generation = ClassNameGeneration { 280 | template: String::from("def"), 281 | ..Default::default() 282 | }; 283 | prod_settings.class_names = class_name_generation; 284 | 285 | let selected_settings = 286 | Settings::choose_settings(Some(dev_settings), Some(prod_settings.clone()), false); 287 | 288 | assert_eq!(selected_settings.class_names, prod_settings.class_names); 289 | } 290 | 291 | #[test] 292 | fn do_not_use_dev_settings_for_release_build() { 293 | let mut dev_settings = Settings::default(); 294 | let class_name_generation = ClassNameGeneration { 295 | template: String::from("abc"), 296 | ..Default::default() 297 | }; 298 | dev_settings.class_names = class_name_generation; 299 | 300 | let selected_settings = Settings::choose_settings(Some(dev_settings.clone()), None, false); 301 | 302 | assert_ne!(selected_settings.class_names, dev_settings.class_names); 303 | } 304 | } 305 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # turf 🌱 2 | //! 3 | //! `turf` allows you to build SCSS to CSS during compile time and inject those styles into your binary. 4 | //! 5 | //! [![Crates.io][crates-badge]][crates-url] 6 | //! [![Docs.rs][docs-badge]][docs-url] 7 | //! [![MIT licensed][lic-badge]][lic-url] 8 | //! 9 | //! [crates-badge]: https://img.shields.io/crates/v/turf.svg 10 | //! [crates-url]: https://crates.io/crates/turf 11 | //! [docs-badge]: https://img.shields.io/docsrs/turf/latest.svg?logo=docsdotrs&label=docs.rs 12 | //! [docs-url]: https://docs.rs/turf 13 | //! [lic-url]: https://github.com/myFavShrimp/turf/blob/master/LICENSE 14 | //! [lic-badge]: https://img.shields.io/badge/license-MIT-blue.svg 15 | //! 16 | //! **turf will:** 17 | //! 18 | //! - 🌿 transform your SCSS files into CSS with [grass](https://github.com/connorskees/grass/), right at compilation time 19 | //! - 🪴 generate unique and dynamic class names for your CSS during compilation 20 | //! - 🔬 minify and optimize your CSS using [lightningcss](https://github.com/parcel-bundler/lightningcss), ensuring compatibility with various browser targets 21 | //! - 🎨 inject the generated CSS into your binary, guaranteeing quick access to your styles whenever you need them 22 | //! 23 | //! ## Usage 24 | //! 25 | //! For a complete runnable example project, you can check out one of the examples: 26 | //! 27 | //! | [leptos-example](https://github.com/myFavShrimp/turf/tree/main/examples/leptos-example) | [yew-example](https://github.com/myFavShrimp/turf/tree/main/examples/yew-example) | [dioxus-example](https://github.com/myFavShrimp/turf/tree/main/examples/dioxus-example) | [axum-askama-htmx](https://github.com/myFavShrimp/turf/tree/main/examples/axum-askama-htmx) | 28 | //! | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | 29 | //! 30 | //! **1. Create SCSS styles for your application** 31 | //! 32 | //! ```scss 33 | //! // file at scss/file/path.scss 34 | //! 35 | //! .TopLevelClass { 36 | //! color: red; 37 | //! 38 | //! .SomeClass { 39 | //! color: blue; 40 | //! } 41 | //! } 42 | //! ``` 43 | //! 44 | //! **2. Use the `style_sheet` macro to include the resulting CSS in your code** 45 | //! 46 | //! ```rust,ignore 47 | //! turf::style_sheet!("scss/file/path.scss"); 48 | //! ``` 49 | //! 50 | //! The macro from the above example will expand to the following code: 51 | //! 52 | //! ```rust 53 | //! static STYLE_SHEET: &'static str = ""; 54 | //! struct ClassName; 55 | //! impl ClassName { 56 | //! pub const TOP_LEVEL_CLASS: &'static str = ""; 57 | //! pub const SOME_CLASS: &'static str = ""; 58 | //! } 59 | //! ``` 60 | //! 61 | //! **3. Use the `ClassName` struct and its associated constants to access the generated class names** 62 | //! 63 | //! ```rust,ignore 64 | //! let top_level_class_name = ClassName::TOP_LEVEL_CLASS; 65 | //! let some_class_name = ClassName::SOME_CLASS; 66 | //! ``` 67 | //! 68 | //! ### Configuration 69 | //! 70 | //! The configuration for turf can be specified in the Cargo.toml file using the `[package.metadata.turf]` and `[package.metadata.turf-dev]` keys. This allows you to conveniently manage your SCSS compilation settings for both development and production builds within your project's manifest. 71 | //! 72 | //! Both profiles offer the exact same configuration options. However, if you haven't specified a `[package.metadata.turf-dev]` profile, the `[package.metadata.turf]` settings will also be applied to debug builds. This ensures consistency in the compilation process across different build types unless you explicitly define a separate configuration for the development profile. 73 | //! 74 | //! Example configuration: 75 | //! 76 | //! ```toml 77 | //! [package.metadata.turf] 78 | //! minify = true 79 | //! load_paths = ["path/to/shared/scss/files", "path/to/other/shared/scss/files"] 80 | //! browser_targets = [ 81 | //! "defaults", 82 | //! "> 5%", 83 | //! "safari 12", 84 | //! ] 85 | //! 86 | //! [package.metadata.turf.class_names] 87 | //! template = "-with-custom-" 88 | //! excludes = ["exclude-this-class-please", "^abc-[123]{4}"] 89 | //! 90 | //! [package.metadata.turf.file_output] 91 | //! global_css_file_path = "path/to/global.css" 92 | //! separate_css_files_path = "dir/for/separate/css/" 93 | //! ``` 94 | //! 95 | //! The following configuration options are available: 96 | //! 97 | //! - `minify` (default: `true`): Specifies whether the generated CSS should be minified or not. If set to true, the CSS output will be compressed and optimized for reduced file size. If set to false, the CSS output will be formatted with indentation and line breaks for improved readability. 98 | //! 99 | //! - `load_paths`: Specifies additional paths to search for SCSS files to include during compilation. It accepts a list of string values, where each value represents a directory path to be included. This option allows you to import SCSS files from multiple directories. 100 | //! 101 | //! - `browser_targets`: Defines the target browser versions for compatibility when generating CSS. It accepts an array of strings in [browserslist](https://browsersl.ist/) format (e.g., "defaults", "> 5%", "safari 12"). This ensures the generated CSS is compatible with the specified browser versions. 102 | //! 103 | //! - `class_names`: Allows configuration of the CSS class name generation. It expects a structure that contains two values for generating CSS class names and excluding class names from the uniquification process. 104 | //! 105 | //! - `debug` (default: `false`): When set to true, this option will enable debug output of the read configuration and the generated CSS class names. This can be helpful for troubleshooting and understanding how the CSS is being generated. 106 | //! 107 | //! - `file_output`: Enables output of compiled CSS. It expects a structure that contains two values for a single global CSS file or separate CSS files for each compiled SCSS file. 108 | //! 109 | //! #### The `class_names` Key 110 | //! 111 | //! - `template` (default: `"class-"`): Specifies the template for generating randomized CSS class names. The template can include placeholders to customize the output: 112 | //! - `` will be replaced with a unique identifier for each CSS class name 113 | //! - `` will be replaced with the original class name from the SCSS file 114 | //! - `` will be replaced with the hash of the original class name from the SCSS file 115 | //! - `` will be replaced with the first 5 characters of the hash of the original class name from the SCSS file 116 | //! - `` will be replaced with the hash of the SCSS file 117 | //! - `` will be replaced with the first 8 characters of the hash of the SCSS file 118 | //! 119 | //! - `excludes`: An array of regex patterns that exclude class names in your SCSS files from the class name uniquification process. 120 | //! 121 | //! #### The `file_output` Key 122 | //! 123 | //! - `global_css_file_path`: Specifies the file path for a global CSS file. If set, a CSS file will be created at the provided path, and all compiled styles will be written to this file. This allows you to have a single CSS file containing all the compiled styles. 124 | //! 125 | //! - `separate_css_files_path`: Specifies the directory path for separate CSS files. If set, all compiled CSS files will be saved in the specified directory. Each compiled SCSS file will have its corresponding CSS file in this directory, allowing for modular CSS management. The file name for inline SCSS style definitions will be a 64 bit hash that is computed from the original SCSS style. 126 | //! 127 | //! ### Additional Macros 128 | //! 129 | //! turf provides a few additional macros for other use cases. 130 | //! 131 | //! #### The `style_sheet_values` Macro 132 | //! 133 | //! In some cases, it may be necessary to have a struct's instance to access the class names (for example when using turf in [askama](https://github.com/djc/askama) templates). 134 | //! The `turf::style_sheet_values` macro provides an alternative to directly including the resulting CSS and obtaining the associated class names. It returns a tuple of `(style_sheet: &'static str, class_names: struct)`. 135 | //! 136 | //! **Usage:** 137 | //! 138 | //! ```rust,ignore 139 | //! let (style_sheet, class_names) = turf::style_sheet_values!("path/to/style.scss"); 140 | //! let some_class_name = class_names.some_class; 141 | //! ``` 142 | //! 143 | //! #### The `inline_style_sheet` Macro 144 | //! 145 | //! If you don't want your style sheet to live in another file, you can use the `turf::inline_style_sheet` macro. It allows you to write inline SCSS which will then be compiled to CSS. 146 | //! 147 | //! **Usage:** 148 | //! 149 | //! ```rust,ignore 150 | //! turf::inline_style_sheet! { 151 | //! .TopLevelClass { 152 | //! color: red; 153 | //! 154 | //! .SomeClass { 155 | //! color: blue; 156 | //! } 157 | //! } 158 | //! } 159 | //! 160 | //! // ... 161 | //! 162 | //! let some_class_name = ClassName::SOME_CLASS; 163 | //! ``` 164 | //! 165 | //! #### The `inline_style_sheet_values` Macro 166 | //! 167 | //! This macro combines the functionality of both the `style_sheet_values` and `inline_style_sheet` macros. It allows you to write inline SCSS and returns an tuple of `(style_sheet: &'static str, class_names: struct)`. 168 | //! 169 | //! **Usage:** 170 | //! 171 | //! ```rust,ignore 172 | //! let (style_sheet, class_names) = turf::inline_style_sheet_values! { 173 | //! .TopLevelClass { 174 | //! color: red; 175 | //! 176 | //! .SomeClass { 177 | //! color: blue; 178 | //! } 179 | //! } 180 | //! }; 181 | //! let some_class_name = class_names.some_class; 182 | //! ``` 183 | 184 | /// Generates the static variable `STYLE_SHEET` and the `ClassName` struct with default settings or the settings specified in the `Cargo.toml` 185 | /// 186 | /// **Usage:** 187 | /// 188 | /// ```rust,ignore 189 | /// turf::style_sheet!("scss/file/path.scss"); 190 | /// 191 | /// let style_sheet_str = STYLE_SHEET; 192 | /// let some_class_name = ClassName::SOME_CLASS; 193 | /// ``` 194 | pub use turf_macros::style_sheet; 195 | 196 | /// Returns a tuple of `(style_sheet: &'static str, class_names: struct)` 197 | /// 198 | /// In some cases, it may be necessary to have a struct's instance (for example when using turf in [askama](https://github.com/djc/askama) templates). 199 | /// The `turf::style_sheet_values` macro simplifies the process of including the resulting CSS and obtaining the associated class names. It allows you to retrieve both the style sheet and the generated class names in a tuple. 200 | /// 201 | /// **Usage:** 202 | /// 203 | /// ```rust,ignore 204 | /// let (style_sheet, class_names) = turf::style_sheet_values!("path/to/style.scss"); 205 | /// 206 | /// let style_sheet_str = style_sheet; 207 | /// let some_class_name = class_names.some_class; 208 | /// ``` 209 | pub use turf_macros::style_sheet_values; 210 | 211 | /// Generates the static variable `STYLE_SHEET` and the `ClassName` struct from inline SCSS styles with default settings or the settings specified in the `Cargo.toml` 212 | /// 213 | /// If you don't want your style sheet to live in another file, you can use the `turf::inline_style_sheet` macro. It allows you to write inline SCSS which will then be compiled to CSS. 214 | /// 215 | /// **Usage:** 216 | /// 217 | /// ```rust,ignore 218 | /// turf::inline_style_sheet! { 219 | /// .TopLevelClass { 220 | /// color: red; 221 | /// 222 | /// .SomeClass { 223 | /// color: blue; 224 | /// } 225 | /// } 226 | /// } 227 | /// 228 | /// // ... 229 | /// 230 | /// let some_class_name = ClassName::SOME_CLASS; 231 | /// ``` 232 | pub use turf_macros::inline_style_sheet; 233 | 234 | /// Returns a tuple of `(style_sheet: &'static str, class_names: struct)` from inline SCSS styles 235 | /// 236 | /// This macro combines the functionality of both the `style_sheet_values` and `inline_style_sheet` macros. It allows you to write inline SCSS and returns an tuple of `(style_sheet: &'static str, class_names: struct)`. 237 | /// 238 | /// **Usage:** 239 | /// 240 | /// ```rust,ignore 241 | /// let (style_sheet, class_names) = turf::inline_style_sheet_values! { 242 | /// .TopLevelClass { 243 | /// color: red; 244 | /// 245 | /// .SomeClass { 246 | /// color: blue; 247 | /// } 248 | /// } 249 | /// }; 250 | /// let some_class_name = class_names.some_class; 251 | /// ``` 252 | pub use turf_macros::inline_style_sheet_values; 253 | -------------------------------------------------------------------------------- /turf_internals/src/transformer.rs: -------------------------------------------------------------------------------- 1 | use lightningcss::{ 2 | selector::{Component, Selector}, 3 | stylesheet::{ParserOptions, StyleSheet}, 4 | visit_types, 5 | visitor::{Visit, VisitTypes, Visitor}, 6 | }; 7 | use regex::RegexSet; 8 | use std::{collections::HashMap, convert::Infallible}; 9 | 10 | const CHARSET: &[u8] = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"; 11 | 12 | #[derive(thiserror::Error, Debug)] 13 | pub enum TransformationVisitorInitializationError { 14 | #[error("error obtaining random id - {0}")] 15 | RandError(#[from] getrandom::Error), 16 | #[error("class name exclude pattern invalid - {0}")] 17 | RegexError(#[from] regex::Error), 18 | } 19 | 20 | pub struct TransformationVisitor { 21 | pub(crate) classes: HashMap, 22 | pub(crate) random_number_generator: oorandom::Rand32, 23 | pub(crate) class_name_template: String, 24 | pub(crate) class_name_exclude_patterns: RegexSet, 25 | pub(crate) style_sheet_hash: String, 26 | pub(crate) debug: bool, 27 | } 28 | 29 | impl TransformationVisitor { 30 | fn try_new( 31 | settings: &crate::Settings, 32 | style_sheet_hash: &str, 33 | ) -> Result { 34 | let class_name_generation = settings.class_names.clone(); 35 | Ok(Self { 36 | debug: settings.debug, 37 | classes: Default::default(), 38 | random_number_generator: oorandom::Rand32::new(random_seed()?), 39 | class_name_template: class_name_generation.template, 40 | class_name_exclude_patterns: RegexSet::new(class_name_generation.excludes)?, 41 | style_sheet_hash: String::from(style_sheet_hash), 42 | }) 43 | } 44 | 45 | fn randomized_class_id(&mut self, length: u32) -> String { 46 | // Creates a random id as part of a class template. The id consists of `length` characters. 47 | // With the exception of the first character, each character can be an alphanumeric, `_` or `-`. 48 | // The first character can only be a letter or `_` to stay compliant with the CSS spec. 49 | assert!( 50 | length <= 6, // Limited by rand_u32, must be rand_u64 for larger values 51 | "'randomized_class_id' can be no longer than 6 characters, was {}", 52 | length 53 | ); 54 | let mut encoded_chars = String::new(); 55 | // Only allow a letter or `_` for the first character, doesn't allow a number or `-` 56 | let mut char_index = self.random_number_generator.rand_range(10..63) as usize; 57 | encoded_chars.push(CHARSET[char_index] as char); 58 | let mut random_bits = self.random_number_generator.rand_u32(); 59 | for _ in 0..(length - 1) { 60 | char_index = (random_bits & 0x3F) as usize; // Only use the last 6 bits (0-64) 61 | encoded_chars.push(CHARSET[char_index] as char); 62 | random_bits >>= 6; // Shift to the next 6 bits 63 | } 64 | encoded_chars 65 | } 66 | 67 | fn randomized_class_name(&mut self, class_name: String, style_sheet_hash: String) -> String { 68 | match self.classes.get(&class_name) { 69 | Some(random_class_name) => random_class_name.clone(), 70 | None => { 71 | let id: String = self.randomized_class_id(6); 72 | apply_template( 73 | &self.class_name_template, 74 | &class_name, 75 | &id, 76 | &style_sheet_hash, 77 | ) 78 | } 79 | } 80 | } 81 | } 82 | 83 | impl<'i> Visitor<'i> for TransformationVisitor { 84 | type Error = Infallible; 85 | 86 | fn visit_types(&self) -> VisitTypes { 87 | visit_types!(SELECTORS) 88 | } 89 | 90 | fn visit_selector(&mut self, selectors: &mut Selector<'i>) -> Result<(), Self::Error> { 91 | for selector in selectors.iter_mut_raw_match_order() { 92 | match selector { 93 | Component::Class(c) => { 94 | let original_class_name = c.to_string(); 95 | 96 | if self.class_name_exclude_patterns.is_empty() 97 | || !self 98 | .class_name_exclude_patterns 99 | .is_match(&original_class_name) 100 | { 101 | let new_class_name = self 102 | .randomized_class_name( 103 | original_class_name.clone(), 104 | self.style_sheet_hash.clone(), 105 | ) 106 | .to_string(); 107 | self.classes 108 | .insert(original_class_name.clone(), new_class_name.clone()); 109 | 110 | if self.debug { 111 | crate::compile_message(&format!( 112 | "class name mapping - {:?} = {:?}", 113 | &original_class_name, &new_class_name 114 | )); 115 | } 116 | 117 | *c = new_class_name.into(); 118 | } else { 119 | self.classes 120 | .insert(original_class_name.clone(), original_class_name.clone()); 121 | 122 | if self.debug { 123 | crate::compile_message(&format!( 124 | "class name excluded - {:?}", 125 | &original_class_name 126 | )); 127 | } 128 | } 129 | } 130 | Component::Slotted(s) => s.visit(self)?, 131 | Component::Host(Some(selector)) => selector.visit(self)?, 132 | Component::Negation(s) 133 | | Component::Where(s) 134 | | Component::Is(s) 135 | | Component::Any(_, s) 136 | | Component::Has(s) => { 137 | s.iter_mut().try_for_each(|selector| selector.visit(self))? 138 | } 139 | _ => (), 140 | } 141 | } 142 | 143 | Ok(()) 144 | } 145 | } 146 | 147 | fn apply_template( 148 | class_name_template: &str, 149 | original_class_name: &str, 150 | id: &str, 151 | style_sheet_hash: &str, 152 | ) -> String { 153 | let name_hash = xxhash_rust::xxh3::xxh3_128(original_class_name.as_bytes()); 154 | let name_hash_string = format!("{name_hash:x}"); 155 | 156 | class_name_template 157 | .replace("", original_class_name) 158 | .replace("", id) 159 | .replace("", &name_hash_string) 160 | .replace("", &name_hash_string[..5]) 161 | .replace("", style_sheet_hash) 162 | .replace("", &style_sheet_hash[..8]) 163 | } 164 | 165 | #[derive(Debug, thiserror::Error)] 166 | pub enum TransformationError { 167 | #[error("error processing css - {0}")] 168 | Lightningcss(String), 169 | #[error("Initialization of css tranformer failed")] 170 | Initialization(#[from] TransformationVisitorInitializationError), 171 | } 172 | 173 | pub fn transform_stylesheet( 174 | css: &str, 175 | hash: &str, 176 | settings: crate::Settings, 177 | ) -> Result<(String, HashMap), TransformationError> { 178 | let mut stylesheet = StyleSheet::parse(css, ParserOptions::default()) 179 | .map_err(|e| e.to_string()) 180 | .map_err(TransformationError::Lightningcss)?; 181 | 182 | let mut visitor = TransformationVisitor::try_new(&settings, hash)?; 183 | 184 | stylesheet 185 | .visit(&mut visitor) 186 | .expect("css visitor never fails"); 187 | 188 | let printer_options: lightningcss::printer::PrinterOptions<'_> = settings.into(); 189 | 190 | stylesheet 191 | .minify(lightningcss::stylesheet::MinifyOptions { 192 | targets: printer_options.targets, 193 | unused_symbols: Default::default(), 194 | }) 195 | .map_err(|e| e.to_string()) 196 | .map_err(TransformationError::Lightningcss)?; 197 | 198 | let css_result = stylesheet 199 | .to_css(printer_options) 200 | .map_err(|e| e.to_string()) 201 | .map_err(TransformationError::Lightningcss)?; 202 | 203 | Ok((css_result.code, visitor.classes)) 204 | } 205 | 206 | fn random_seed() -> Result { 207 | let mut buf = [0u8; 8]; 208 | getrandom::getrandom(&mut buf)?; 209 | Ok(u64::from_ne_bytes(buf)) 210 | } 211 | 212 | #[cfg(test)] 213 | mod tests { 214 | use crate::settings::{BrowserTargets, ClassNameGeneration}; 215 | 216 | use super::transform_stylesheet; 217 | 218 | #[test] 219 | fn basic_visitor() { 220 | let style = r#" 221 | .test { 222 | color: red; 223 | } 224 | "#; 225 | let transformation_result = transform_stylesheet( 226 | style, 227 | "SGVsbG8gdHVyZiB3b3JsZCBvZiBzdHlsZQ", 228 | crate::Settings::default(), 229 | ) 230 | .unwrap(); 231 | 232 | assert!(transformation_result.0.starts_with(".class-")); 233 | assert!(transformation_result.0.ends_with("{color:red}")); 234 | assert!(transformation_result.0.starts_with(&format!( 235 | ".{}", 236 | transformation_result.1.get("test").unwrap() 237 | ))); 238 | } 239 | 240 | #[test] 241 | fn inner_selector_visitor() { 242 | let style = r#" 243 | .test:not(.withoutme) { 244 | color: red; 245 | } 246 | "#; 247 | let transformation_result = transform_stylesheet( 248 | style, 249 | "SGVsbG8gdHVyZiB3b3JsZCBvZiBzdHlsZQ", 250 | crate::Settings::default(), 251 | ) 252 | .unwrap(); 253 | 254 | assert!(transformation_result.0.starts_with(".class-")); 255 | assert!(transformation_result.0.ends_with("{color:red}")); 256 | assert!(transformation_result.0.starts_with(&format!( 257 | ".{}:not(.class-", 258 | transformation_result.1.get("test").unwrap() 259 | ))); 260 | assert!(transformation_result.0.starts_with(&format!( 261 | ".{}:not(.{})", 262 | transformation_result.1.get("test").unwrap(), 263 | transformation_result.1.get("withoutme").unwrap() 264 | ))); 265 | } 266 | 267 | #[test] 268 | fn custom_template() { 269 | let style = r#" 270 | .test { 271 | color: red; 272 | } 273 | "#; 274 | let class_name_generation = ClassNameGeneration { 275 | template: String::from("fancy_style---"), 276 | ..Default::default() 277 | }; 278 | let settings = crate::Settings { 279 | class_names: class_name_generation, 280 | ..Default::default() 281 | }; 282 | let transformation_result = 283 | transform_stylesheet(style, "SGVsbG8gdHVyZiB3b3JsZCBvZiBzdHlsZQ", settings).unwrap(); 284 | 285 | assert!(transformation_result 286 | .0 287 | .starts_with(".fancy_style-test-SGVsbG8g-")); 288 | assert!(transformation_result.0.ends_with("{color:red}")); 289 | assert!(transformation_result.0.starts_with(&format!( 290 | ".{}", 291 | transformation_result.1.get("test").unwrap() 292 | ))); 293 | } 294 | 295 | #[test] 296 | fn custom_template_without_id() { 297 | let style = r#" 298 | .test { 299 | color: red; 300 | } 301 | "#; 302 | let class_name_generation = ClassNameGeneration { 303 | template: String::from("fancy_style-"), 304 | ..Default::default() 305 | }; 306 | let settings = crate::Settings { 307 | class_names: class_name_generation, 308 | ..Default::default() 309 | }; 310 | let transformation_result = 311 | transform_stylesheet(style, "SGVsbG8gdHVyZiB3b3JsZCBvZiBzdHlsZQ", settings).unwrap(); 312 | 313 | assert_eq!(transformation_result.0, ".fancy_style-test{color:red}"); 314 | assert!(transformation_result.0.starts_with(&format!( 315 | ".{}", 316 | transformation_result.1.get("test").unwrap() 317 | ))); 318 | } 319 | 320 | #[test] 321 | fn custom_template_with_hashes() { 322 | let style = r#" 323 | .test { 324 | color: red; 325 | } 326 | "#; 327 | let class_name_generation = ClassNameGeneration { 328 | template: String::from("----"), 329 | ..Default::default() 330 | }; 331 | let settings = crate::Settings { 332 | class_names: class_name_generation, 333 | ..Default::default() 334 | }; 335 | let transformation_result = 336 | transform_stylesheet(style, "SGVsbG8gdHVyZiB3b3JsZCBvZiBzdHlsZQ", settings).unwrap(); 337 | 338 | assert_eq!( 339 | transformation_result.0, 340 | ".SGVsbG8gdHVyZiB3b3JsZCBvZiBzdHlsZQ-SGVsbG8g-6c78e0e3bd51d358d01e758642b85fb8-6c78e-test{color:red}" 341 | ); 342 | assert!(transformation_result.0.starts_with(&format!( 343 | ".{}", 344 | transformation_result.1.get("test").unwrap() 345 | ))); 346 | } 347 | 348 | #[test] 349 | fn vendor_prefixes() { 350 | let style = r#" 351 | .test { 352 | user-select: none; 353 | background: image-set("1.jpg" 1x, "2.jpg" 2x); 354 | -webkit-transition: background 200ms; 355 | -moz-transition: background 200ms; 356 | transition: background 200ms; 357 | } 358 | "#; 359 | let class_name_generation = ClassNameGeneration { 360 | template: String::from(""), 361 | ..Default::default() 362 | }; 363 | let settings = crate::Settings { 364 | class_names: class_name_generation, 365 | browser_targets: BrowserTargets( 366 | lightningcss::targets::Browsers::from_browserslist([ 367 | "chrome 100, firefox 100, safari 12", 368 | ]) 369 | .unwrap(), 370 | ), 371 | ..Default::default() 372 | }; 373 | let transformation_result = 374 | transform_stylesheet(style, "SGVsbG8gdHVyZiB3b3JsZCBvZiBzdHlsZQ", settings).unwrap(); 375 | 376 | assert_eq!( 377 | transformation_result.0, 378 | ".test{-webkit-user-select:none;user-select:none;background:-webkit-image-set(url(1.jpg) 1x,url(2.jpg) 2x);background:image-set(\"1.jpg\" 1x,\"2.jpg\" 2x);transition:background .2s}" 379 | ); 380 | assert!(transformation_result.0.starts_with(&format!( 381 | ".{}", 382 | transformation_result.1.get("test").unwrap() 383 | ))); 384 | } 385 | } 386 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "ahash" 7 | version = "0.8.11" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 10 | dependencies = [ 11 | "cfg-if", 12 | "getrandom", 13 | "once_cell", 14 | "serde", 15 | "version_check", 16 | "zerocopy", 17 | ] 18 | 19 | [[package]] 20 | name = "aho-corasick" 21 | version = "1.1.3" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 24 | dependencies = [ 25 | "memchr", 26 | ] 27 | 28 | [[package]] 29 | name = "allocator-api2" 30 | version = "0.2.21" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" 33 | 34 | [[package]] 35 | name = "android-tzdata" 36 | version = "0.1.1" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 39 | 40 | [[package]] 41 | name = "android_system_properties" 42 | version = "0.1.5" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 45 | dependencies = [ 46 | "libc", 47 | ] 48 | 49 | [[package]] 50 | name = "autocfg" 51 | version = "1.4.0" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 54 | 55 | [[package]] 56 | name = "bitflags" 57 | version = "2.9.0" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" 60 | 61 | [[package]] 62 | name = "browserslist-rs" 63 | version = "0.17.0" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "74c973b79d9b6b89854493185ab760c6ef8e54bcfad10ad4e33991e46b374ac8" 66 | dependencies = [ 67 | "ahash", 68 | "chrono", 69 | "either", 70 | "indexmap", 71 | "itertools 0.13.0", 72 | "nom", 73 | "serde", 74 | "serde_json", 75 | "thiserror", 76 | ] 77 | 78 | [[package]] 79 | name = "bumpalo" 80 | version = "3.17.0" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" 83 | 84 | [[package]] 85 | name = "cc" 86 | version = "1.2.19" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" 89 | dependencies = [ 90 | "shlex", 91 | ] 92 | 93 | [[package]] 94 | name = "cfg-if" 95 | version = "1.0.0" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 98 | 99 | [[package]] 100 | name = "chrono" 101 | version = "0.4.40" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" 104 | dependencies = [ 105 | "android-tzdata", 106 | "iana-time-zone", 107 | "num-traits", 108 | "windows-link", 109 | ] 110 | 111 | [[package]] 112 | name = "codemap" 113 | version = "0.1.3" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "b9e769b5c8c8283982a987c6e948e540254f1058d5a74b8794914d4ef5fc2a24" 116 | 117 | [[package]] 118 | name = "const-str" 119 | version = "0.3.2" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "21077772762a1002bb421c3af42ac1725fa56066bfc53d9a55bb79905df2aaf3" 122 | dependencies = [ 123 | "const-str-proc-macro", 124 | ] 125 | 126 | [[package]] 127 | name = "const-str-proc-macro" 128 | version = "0.3.2" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "5e1e0fdd2e5d3041e530e1b21158aeeef8b5d0e306bc5c1e3d6cf0930d10e25a" 131 | dependencies = [ 132 | "proc-macro2", 133 | "quote", 134 | "syn 1.0.109", 135 | ] 136 | 137 | [[package]] 138 | name = "convert_case" 139 | version = "0.6.0" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" 142 | dependencies = [ 143 | "unicode-segmentation", 144 | ] 145 | 146 | [[package]] 147 | name = "core-foundation-sys" 148 | version = "0.8.7" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 151 | 152 | [[package]] 153 | name = "cssparser" 154 | version = "0.33.0" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "9be934d936a0fbed5bcdc01042b770de1398bf79d0e192f49fa7faea0e99281e" 157 | dependencies = [ 158 | "cssparser-macros", 159 | "dtoa-short", 160 | "itoa", 161 | "phf", 162 | "smallvec", 163 | ] 164 | 165 | [[package]] 166 | name = "cssparser-color" 167 | version = "0.1.0" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "556c099a61d85989d7af52b692e35a8d68a57e7df8c6d07563dc0778b3960c9f" 170 | dependencies = [ 171 | "cssparser", 172 | ] 173 | 174 | [[package]] 175 | name = "cssparser-macros" 176 | version = "0.6.1" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" 179 | dependencies = [ 180 | "quote", 181 | "syn 2.0.100", 182 | ] 183 | 184 | [[package]] 185 | name = "data-encoding" 186 | version = "2.9.0" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" 189 | 190 | [[package]] 191 | name = "dtoa" 192 | version = "1.0.10" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" 195 | 196 | [[package]] 197 | name = "dtoa-short" 198 | version = "0.3.5" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" 201 | dependencies = [ 202 | "dtoa", 203 | ] 204 | 205 | [[package]] 206 | name = "either" 207 | version = "1.15.0" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 210 | 211 | [[package]] 212 | name = "equivalent" 213 | version = "1.0.2" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 216 | 217 | [[package]] 218 | name = "getrandom" 219 | version = "0.2.15" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 222 | dependencies = [ 223 | "cfg-if", 224 | "js-sys", 225 | "libc", 226 | "wasi", 227 | "wasm-bindgen", 228 | ] 229 | 230 | [[package]] 231 | name = "grass" 232 | version = "0.13.4" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "f7a68216437ef68f0738e48d6c7bb9e6e6a92237e001b03d838314b068f33c94" 235 | dependencies = [ 236 | "getrandom", 237 | "grass_compiler", 238 | ] 239 | 240 | [[package]] 241 | name = "grass_compiler" 242 | version = "0.13.4" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "2d9e3df7f0222ce5184154973d247c591d9aadc28ce7a73c6cd31100c9facff6" 245 | dependencies = [ 246 | "codemap", 247 | "indexmap", 248 | "lasso", 249 | "once_cell", 250 | "phf", 251 | ] 252 | 253 | [[package]] 254 | name = "hashbrown" 255 | version = "0.14.5" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 258 | dependencies = [ 259 | "ahash", 260 | "allocator-api2", 261 | ] 262 | 263 | [[package]] 264 | name = "hashbrown" 265 | version = "0.15.2" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 268 | 269 | [[package]] 270 | name = "iana-time-zone" 271 | version = "0.1.63" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" 274 | dependencies = [ 275 | "android_system_properties", 276 | "core-foundation-sys", 277 | "iana-time-zone-haiku", 278 | "js-sys", 279 | "log", 280 | "wasm-bindgen", 281 | "windows-core", 282 | ] 283 | 284 | [[package]] 285 | name = "iana-time-zone-haiku" 286 | version = "0.1.2" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 289 | dependencies = [ 290 | "cc", 291 | ] 292 | 293 | [[package]] 294 | name = "indexmap" 295 | version = "2.9.0" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" 298 | dependencies = [ 299 | "equivalent", 300 | "hashbrown 0.15.2", 301 | "serde", 302 | ] 303 | 304 | [[package]] 305 | name = "itertools" 306 | version = "0.10.5" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 309 | dependencies = [ 310 | "either", 311 | ] 312 | 313 | [[package]] 314 | name = "itertools" 315 | version = "0.13.0" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" 318 | dependencies = [ 319 | "either", 320 | ] 321 | 322 | [[package]] 323 | name = "itoa" 324 | version = "1.0.15" 325 | source = "registry+https://github.com/rust-lang/crates.io-index" 326 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 327 | 328 | [[package]] 329 | name = "js-sys" 330 | version = "0.3.77" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" 333 | dependencies = [ 334 | "once_cell", 335 | "wasm-bindgen", 336 | ] 337 | 338 | [[package]] 339 | name = "lasso" 340 | version = "0.7.3" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "6e14eda50a3494b3bf7b9ce51c52434a761e383d7238ce1dd5dcec2fbc13e9fb" 343 | dependencies = [ 344 | "hashbrown 0.14.5", 345 | ] 346 | 347 | [[package]] 348 | name = "lazy_static" 349 | version = "1.5.0" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 352 | 353 | [[package]] 354 | name = "libc" 355 | version = "0.2.172" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" 358 | 359 | [[package]] 360 | name = "lightningcss" 361 | version = "1.0.0-alpha.65" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "c84f971730745f4aaac013b6cf4328baf1548efc973c0d95cfd843a3c1ca07af" 364 | dependencies = [ 365 | "ahash", 366 | "bitflags", 367 | "browserslist-rs", 368 | "const-str", 369 | "cssparser", 370 | "cssparser-color", 371 | "data-encoding", 372 | "getrandom", 373 | "indexmap", 374 | "itertools 0.10.5", 375 | "lazy_static", 376 | "lightningcss-derive", 377 | "parcel_selectors", 378 | "paste", 379 | "pathdiff", 380 | "smallvec", 381 | ] 382 | 383 | [[package]] 384 | name = "lightningcss-derive" 385 | version = "1.0.0-alpha.43" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "84c12744d1279367caed41739ef094c325d53fb0ffcd4f9b84a368796f870252" 388 | dependencies = [ 389 | "convert_case", 390 | "proc-macro2", 391 | "quote", 392 | "syn 1.0.109", 393 | ] 394 | 395 | [[package]] 396 | name = "log" 397 | version = "0.4.27" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 400 | 401 | [[package]] 402 | name = "memchr" 403 | version = "2.7.4" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 406 | 407 | [[package]] 408 | name = "minimal-lexical" 409 | version = "0.2.1" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 412 | 413 | [[package]] 414 | name = "nom" 415 | version = "7.1.3" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 418 | dependencies = [ 419 | "memchr", 420 | "minimal-lexical", 421 | ] 422 | 423 | [[package]] 424 | name = "num-traits" 425 | version = "0.2.19" 426 | source = "registry+https://github.com/rust-lang/crates.io-index" 427 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 428 | dependencies = [ 429 | "autocfg", 430 | ] 431 | 432 | [[package]] 433 | name = "once_cell" 434 | version = "1.21.3" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 437 | 438 | [[package]] 439 | name = "oorandom" 440 | version = "11.1.5" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" 443 | 444 | [[package]] 445 | name = "parcel_selectors" 446 | version = "0.28.1" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "dccbc6fb560df303a44e511618256029410efbc87779018f751ef12c488271fe" 449 | dependencies = [ 450 | "bitflags", 451 | "cssparser", 452 | "log", 453 | "phf", 454 | "phf_codegen", 455 | "precomputed-hash", 456 | "rustc-hash", 457 | "smallvec", 458 | ] 459 | 460 | [[package]] 461 | name = "paste" 462 | version = "1.0.15" 463 | source = "registry+https://github.com/rust-lang/crates.io-index" 464 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 465 | 466 | [[package]] 467 | name = "pathdiff" 468 | version = "0.2.3" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" 471 | 472 | [[package]] 473 | name = "phf" 474 | version = "0.11.3" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" 477 | dependencies = [ 478 | "phf_macros", 479 | "phf_shared", 480 | ] 481 | 482 | [[package]] 483 | name = "phf_codegen" 484 | version = "0.11.3" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" 487 | dependencies = [ 488 | "phf_generator", 489 | "phf_shared", 490 | ] 491 | 492 | [[package]] 493 | name = "phf_generator" 494 | version = "0.11.3" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" 497 | dependencies = [ 498 | "phf_shared", 499 | "rand", 500 | ] 501 | 502 | [[package]] 503 | name = "phf_macros" 504 | version = "0.11.3" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" 507 | dependencies = [ 508 | "phf_generator", 509 | "phf_shared", 510 | "proc-macro2", 511 | "quote", 512 | "syn 2.0.100", 513 | ] 514 | 515 | [[package]] 516 | name = "phf_shared" 517 | version = "0.11.3" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" 520 | dependencies = [ 521 | "siphasher", 522 | ] 523 | 524 | [[package]] 525 | name = "precomputed-hash" 526 | version = "0.1.1" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" 529 | 530 | [[package]] 531 | name = "proc-macro2" 532 | version = "1.0.94" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" 535 | dependencies = [ 536 | "unicode-ident", 537 | ] 538 | 539 | [[package]] 540 | name = "quote" 541 | version = "1.0.40" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 544 | dependencies = [ 545 | "proc-macro2", 546 | ] 547 | 548 | [[package]] 549 | name = "rand" 550 | version = "0.8.5" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 553 | dependencies = [ 554 | "rand_core", 555 | ] 556 | 557 | [[package]] 558 | name = "rand_core" 559 | version = "0.6.4" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 562 | 563 | [[package]] 564 | name = "regex" 565 | version = "1.11.1" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 568 | dependencies = [ 569 | "aho-corasick", 570 | "memchr", 571 | "regex-automata", 572 | "regex-syntax", 573 | ] 574 | 575 | [[package]] 576 | name = "regex-automata" 577 | version = "0.4.9" 578 | source = "registry+https://github.com/rust-lang/crates.io-index" 579 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 580 | dependencies = [ 581 | "aho-corasick", 582 | "memchr", 583 | "regex-syntax", 584 | ] 585 | 586 | [[package]] 587 | name = "regex-syntax" 588 | version = "0.8.5" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 591 | 592 | [[package]] 593 | name = "rustc-hash" 594 | version = "2.1.1" 595 | source = "registry+https://github.com/rust-lang/crates.io-index" 596 | checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" 597 | 598 | [[package]] 599 | name = "rustversion" 600 | version = "1.0.20" 601 | source = "registry+https://github.com/rust-lang/crates.io-index" 602 | checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" 603 | 604 | [[package]] 605 | name = "ryu" 606 | version = "1.0.20" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 609 | 610 | [[package]] 611 | name = "serde" 612 | version = "1.0.219" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 615 | dependencies = [ 616 | "serde_derive", 617 | ] 618 | 619 | [[package]] 620 | name = "serde_derive" 621 | version = "1.0.219" 622 | source = "registry+https://github.com/rust-lang/crates.io-index" 623 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 624 | dependencies = [ 625 | "proc-macro2", 626 | "quote", 627 | "syn 2.0.100", 628 | ] 629 | 630 | [[package]] 631 | name = "serde_json" 632 | version = "1.0.140" 633 | source = "registry+https://github.com/rust-lang/crates.io-index" 634 | checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" 635 | dependencies = [ 636 | "itoa", 637 | "memchr", 638 | "ryu", 639 | "serde", 640 | ] 641 | 642 | [[package]] 643 | name = "serde_spanned" 644 | version = "0.6.8" 645 | source = "registry+https://github.com/rust-lang/crates.io-index" 646 | checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 647 | dependencies = [ 648 | "serde", 649 | ] 650 | 651 | [[package]] 652 | name = "shlex" 653 | version = "1.3.0" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 656 | 657 | [[package]] 658 | name = "siphasher" 659 | version = "1.0.1" 660 | source = "registry+https://github.com/rust-lang/crates.io-index" 661 | checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" 662 | 663 | [[package]] 664 | name = "smallvec" 665 | version = "1.15.0" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" 668 | 669 | [[package]] 670 | name = "syn" 671 | version = "1.0.109" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 674 | dependencies = [ 675 | "proc-macro2", 676 | "quote", 677 | "unicode-ident", 678 | ] 679 | 680 | [[package]] 681 | name = "syn" 682 | version = "2.0.100" 683 | source = "registry+https://github.com/rust-lang/crates.io-index" 684 | checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" 685 | dependencies = [ 686 | "proc-macro2", 687 | "quote", 688 | "unicode-ident", 689 | ] 690 | 691 | [[package]] 692 | name = "thiserror" 693 | version = "1.0.69" 694 | source = "registry+https://github.com/rust-lang/crates.io-index" 695 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 696 | dependencies = [ 697 | "thiserror-impl", 698 | ] 699 | 700 | [[package]] 701 | name = "thiserror-impl" 702 | version = "1.0.69" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 705 | dependencies = [ 706 | "proc-macro2", 707 | "quote", 708 | "syn 2.0.100", 709 | ] 710 | 711 | [[package]] 712 | name = "toml" 713 | version = "0.8.20" 714 | source = "registry+https://github.com/rust-lang/crates.io-index" 715 | checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" 716 | dependencies = [ 717 | "serde", 718 | "serde_spanned", 719 | "toml_datetime", 720 | "toml_edit", 721 | ] 722 | 723 | [[package]] 724 | name = "toml_datetime" 725 | version = "0.6.8" 726 | source = "registry+https://github.com/rust-lang/crates.io-index" 727 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 728 | dependencies = [ 729 | "serde", 730 | ] 731 | 732 | [[package]] 733 | name = "toml_edit" 734 | version = "0.22.24" 735 | source = "registry+https://github.com/rust-lang/crates.io-index" 736 | checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" 737 | dependencies = [ 738 | "indexmap", 739 | "serde", 740 | "serde_spanned", 741 | "toml_datetime", 742 | "winnow", 743 | ] 744 | 745 | [[package]] 746 | name = "turf" 747 | version = "0.10.1" 748 | dependencies = [ 749 | "turf_macros", 750 | ] 751 | 752 | [[package]] 753 | name = "turf_internals" 754 | version = "0.10.1" 755 | dependencies = [ 756 | "getrandom", 757 | "grass", 758 | "lightningcss", 759 | "oorandom", 760 | "regex", 761 | "serde", 762 | "thiserror", 763 | "toml", 764 | "xxhash-rust", 765 | ] 766 | 767 | [[package]] 768 | name = "turf_macros" 769 | version = "0.10.1" 770 | dependencies = [ 771 | "convert_case", 772 | "proc-macro2", 773 | "quote", 774 | "turf_internals", 775 | ] 776 | 777 | [[package]] 778 | name = "unicode-ident" 779 | version = "1.0.18" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 782 | 783 | [[package]] 784 | name = "unicode-segmentation" 785 | version = "1.12.0" 786 | source = "registry+https://github.com/rust-lang/crates.io-index" 787 | checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" 788 | 789 | [[package]] 790 | name = "version_check" 791 | version = "0.9.5" 792 | source = "registry+https://github.com/rust-lang/crates.io-index" 793 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 794 | 795 | [[package]] 796 | name = "wasi" 797 | version = "0.11.0+wasi-snapshot-preview1" 798 | source = "registry+https://github.com/rust-lang/crates.io-index" 799 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 800 | 801 | [[package]] 802 | name = "wasm-bindgen" 803 | version = "0.2.100" 804 | source = "registry+https://github.com/rust-lang/crates.io-index" 805 | checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" 806 | dependencies = [ 807 | "cfg-if", 808 | "once_cell", 809 | "rustversion", 810 | "wasm-bindgen-macro", 811 | ] 812 | 813 | [[package]] 814 | name = "wasm-bindgen-backend" 815 | version = "0.2.100" 816 | source = "registry+https://github.com/rust-lang/crates.io-index" 817 | checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" 818 | dependencies = [ 819 | "bumpalo", 820 | "log", 821 | "proc-macro2", 822 | "quote", 823 | "syn 2.0.100", 824 | "wasm-bindgen-shared", 825 | ] 826 | 827 | [[package]] 828 | name = "wasm-bindgen-macro" 829 | version = "0.2.100" 830 | source = "registry+https://github.com/rust-lang/crates.io-index" 831 | checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" 832 | dependencies = [ 833 | "quote", 834 | "wasm-bindgen-macro-support", 835 | ] 836 | 837 | [[package]] 838 | name = "wasm-bindgen-macro-support" 839 | version = "0.2.100" 840 | source = "registry+https://github.com/rust-lang/crates.io-index" 841 | checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" 842 | dependencies = [ 843 | "proc-macro2", 844 | "quote", 845 | "syn 2.0.100", 846 | "wasm-bindgen-backend", 847 | "wasm-bindgen-shared", 848 | ] 849 | 850 | [[package]] 851 | name = "wasm-bindgen-shared" 852 | version = "0.2.100" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" 855 | dependencies = [ 856 | "unicode-ident", 857 | ] 858 | 859 | [[package]] 860 | name = "windows-core" 861 | version = "0.61.0" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" 864 | dependencies = [ 865 | "windows-implement", 866 | "windows-interface", 867 | "windows-link", 868 | "windows-result", 869 | "windows-strings", 870 | ] 871 | 872 | [[package]] 873 | name = "windows-implement" 874 | version = "0.60.0" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" 877 | dependencies = [ 878 | "proc-macro2", 879 | "quote", 880 | "syn 2.0.100", 881 | ] 882 | 883 | [[package]] 884 | name = "windows-interface" 885 | version = "0.59.1" 886 | source = "registry+https://github.com/rust-lang/crates.io-index" 887 | checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" 888 | dependencies = [ 889 | "proc-macro2", 890 | "quote", 891 | "syn 2.0.100", 892 | ] 893 | 894 | [[package]] 895 | name = "windows-link" 896 | version = "0.1.1" 897 | source = "registry+https://github.com/rust-lang/crates.io-index" 898 | checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" 899 | 900 | [[package]] 901 | name = "windows-result" 902 | version = "0.3.2" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" 905 | dependencies = [ 906 | "windows-link", 907 | ] 908 | 909 | [[package]] 910 | name = "windows-strings" 911 | version = "0.4.0" 912 | source = "registry+https://github.com/rust-lang/crates.io-index" 913 | checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" 914 | dependencies = [ 915 | "windows-link", 916 | ] 917 | 918 | [[package]] 919 | name = "winnow" 920 | version = "0.7.6" 921 | source = "registry+https://github.com/rust-lang/crates.io-index" 922 | checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" 923 | dependencies = [ 924 | "memchr", 925 | ] 926 | 927 | [[package]] 928 | name = "xxhash-rust" 929 | version = "0.8.15" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" 932 | 933 | [[package]] 934 | name = "zerocopy" 935 | version = "0.7.35" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 938 | dependencies = [ 939 | "zerocopy-derive", 940 | ] 941 | 942 | [[package]] 943 | name = "zerocopy-derive" 944 | version = "0.7.35" 945 | source = "registry+https://github.com/rust-lang/crates.io-index" 946 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 947 | dependencies = [ 948 | "proc-macro2", 949 | "quote", 950 | "syn 2.0.100", 951 | ] 952 | -------------------------------------------------------------------------------- /tests/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "ahash" 7 | version = "0.8.11" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 10 | dependencies = [ 11 | "cfg-if", 12 | "getrandom", 13 | "once_cell", 14 | "serde", 15 | "version_check", 16 | "zerocopy", 17 | ] 18 | 19 | [[package]] 20 | name = "aho-corasick" 21 | version = "1.1.3" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 24 | dependencies = [ 25 | "memchr", 26 | ] 27 | 28 | [[package]] 29 | name = "allocator-api2" 30 | version = "0.2.21" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" 33 | 34 | [[package]] 35 | name = "android-tzdata" 36 | version = "0.1.1" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 39 | 40 | [[package]] 41 | name = "android_system_properties" 42 | version = "0.1.5" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 45 | dependencies = [ 46 | "libc", 47 | ] 48 | 49 | [[package]] 50 | name = "autocfg" 51 | version = "1.4.0" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 54 | 55 | [[package]] 56 | name = "bitflags" 57 | version = "2.9.0" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" 60 | 61 | [[package]] 62 | name = "browserslist-rs" 63 | version = "0.17.0" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "74c973b79d9b6b89854493185ab760c6ef8e54bcfad10ad4e33991e46b374ac8" 66 | dependencies = [ 67 | "ahash", 68 | "chrono", 69 | "either", 70 | "indexmap", 71 | "itertools 0.13.0", 72 | "nom", 73 | "serde", 74 | "serde_json", 75 | "thiserror", 76 | ] 77 | 78 | [[package]] 79 | name = "bumpalo" 80 | version = "3.17.0" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" 83 | 84 | [[package]] 85 | name = "cc" 86 | version = "1.2.19" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" 89 | dependencies = [ 90 | "shlex", 91 | ] 92 | 93 | [[package]] 94 | name = "cfg-if" 95 | version = "1.0.0" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 98 | 99 | [[package]] 100 | name = "chrono" 101 | version = "0.4.40" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" 104 | dependencies = [ 105 | "android-tzdata", 106 | "iana-time-zone", 107 | "num-traits", 108 | "windows-link", 109 | ] 110 | 111 | [[package]] 112 | name = "codemap" 113 | version = "0.1.3" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "b9e769b5c8c8283982a987c6e948e540254f1058d5a74b8794914d4ef5fc2a24" 116 | 117 | [[package]] 118 | name = "const-str" 119 | version = "0.3.2" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "21077772762a1002bb421c3af42ac1725fa56066bfc53d9a55bb79905df2aaf3" 122 | dependencies = [ 123 | "const-str-proc-macro", 124 | ] 125 | 126 | [[package]] 127 | name = "const-str-proc-macro" 128 | version = "0.3.2" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "5e1e0fdd2e5d3041e530e1b21158aeeef8b5d0e306bc5c1e3d6cf0930d10e25a" 131 | dependencies = [ 132 | "proc-macro2", 133 | "quote", 134 | "syn 1.0.109", 135 | ] 136 | 137 | [[package]] 138 | name = "convert_case" 139 | version = "0.6.0" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" 142 | dependencies = [ 143 | "unicode-segmentation", 144 | ] 145 | 146 | [[package]] 147 | name = "core-foundation-sys" 148 | version = "0.8.7" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 151 | 152 | [[package]] 153 | name = "cssparser" 154 | version = "0.33.0" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "9be934d936a0fbed5bcdc01042b770de1398bf79d0e192f49fa7faea0e99281e" 157 | dependencies = [ 158 | "cssparser-macros", 159 | "dtoa-short", 160 | "itoa", 161 | "phf", 162 | "smallvec", 163 | ] 164 | 165 | [[package]] 166 | name = "cssparser-color" 167 | version = "0.1.0" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "556c099a61d85989d7af52b692e35a8d68a57e7df8c6d07563dc0778b3960c9f" 170 | dependencies = [ 171 | "cssparser", 172 | ] 173 | 174 | [[package]] 175 | name = "cssparser-macros" 176 | version = "0.6.1" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" 179 | dependencies = [ 180 | "quote", 181 | "syn 2.0.100", 182 | ] 183 | 184 | [[package]] 185 | name = "data-encoding" 186 | version = "2.9.0" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" 189 | 190 | [[package]] 191 | name = "define_inline_style_sheet" 192 | version = "0.1.0" 193 | dependencies = [ 194 | "turf", 195 | "turf_internals", 196 | ] 197 | 198 | [[package]] 199 | name = "dtoa" 200 | version = "1.0.10" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" 203 | 204 | [[package]] 205 | name = "dtoa-short" 206 | version = "0.3.5" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" 209 | dependencies = [ 210 | "dtoa", 211 | ] 212 | 213 | [[package]] 214 | name = "either" 215 | version = "1.15.0" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 218 | 219 | [[package]] 220 | name = "equivalent" 221 | version = "1.0.2" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 224 | 225 | [[package]] 226 | name = "getrandom" 227 | version = "0.2.15" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 230 | dependencies = [ 231 | "cfg-if", 232 | "js-sys", 233 | "libc", 234 | "wasi", 235 | "wasm-bindgen", 236 | ] 237 | 238 | [[package]] 239 | name = "grass" 240 | version = "0.13.4" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "f7a68216437ef68f0738e48d6c7bb9e6e6a92237e001b03d838314b068f33c94" 243 | dependencies = [ 244 | "getrandom", 245 | "grass_compiler", 246 | ] 247 | 248 | [[package]] 249 | name = "grass_compiler" 250 | version = "0.13.4" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "2d9e3df7f0222ce5184154973d247c591d9aadc28ce7a73c6cd31100c9facff6" 253 | dependencies = [ 254 | "codemap", 255 | "indexmap", 256 | "lasso", 257 | "once_cell", 258 | "phf", 259 | ] 260 | 261 | [[package]] 262 | name = "hashbrown" 263 | version = "0.14.5" 264 | source = "registry+https://github.com/rust-lang/crates.io-index" 265 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 266 | dependencies = [ 267 | "ahash", 268 | "allocator-api2", 269 | ] 270 | 271 | [[package]] 272 | name = "hashbrown" 273 | version = "0.15.2" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 276 | 277 | [[package]] 278 | name = "iana-time-zone" 279 | version = "0.1.63" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" 282 | dependencies = [ 283 | "android_system_properties", 284 | "core-foundation-sys", 285 | "iana-time-zone-haiku", 286 | "js-sys", 287 | "log", 288 | "wasm-bindgen", 289 | "windows-core", 290 | ] 291 | 292 | [[package]] 293 | name = "iana-time-zone-haiku" 294 | version = "0.1.2" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 297 | dependencies = [ 298 | "cc", 299 | ] 300 | 301 | [[package]] 302 | name = "indexmap" 303 | version = "2.9.0" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" 306 | dependencies = [ 307 | "equivalent", 308 | "hashbrown 0.15.2", 309 | "serde", 310 | ] 311 | 312 | [[package]] 313 | name = "itertools" 314 | version = "0.10.5" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 317 | dependencies = [ 318 | "either", 319 | ] 320 | 321 | [[package]] 322 | name = "itertools" 323 | version = "0.13.0" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" 326 | dependencies = [ 327 | "either", 328 | ] 329 | 330 | [[package]] 331 | name = "itoa" 332 | version = "1.0.15" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 335 | 336 | [[package]] 337 | name = "js-sys" 338 | version = "0.3.77" 339 | source = "registry+https://github.com/rust-lang/crates.io-index" 340 | checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" 341 | dependencies = [ 342 | "once_cell", 343 | "wasm-bindgen", 344 | ] 345 | 346 | [[package]] 347 | name = "lasso" 348 | version = "0.7.3" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | checksum = "6e14eda50a3494b3bf7b9ce51c52434a761e383d7238ce1dd5dcec2fbc13e9fb" 351 | dependencies = [ 352 | "hashbrown 0.14.5", 353 | ] 354 | 355 | [[package]] 356 | name = "lazy_static" 357 | version = "1.5.0" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 360 | 361 | [[package]] 362 | name = "libc" 363 | version = "0.2.172" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" 366 | 367 | [[package]] 368 | name = "lightningcss" 369 | version = "1.0.0-alpha.65" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "c84f971730745f4aaac013b6cf4328baf1548efc973c0d95cfd843a3c1ca07af" 372 | dependencies = [ 373 | "ahash", 374 | "bitflags", 375 | "browserslist-rs", 376 | "const-str", 377 | "cssparser", 378 | "cssparser-color", 379 | "data-encoding", 380 | "getrandom", 381 | "indexmap", 382 | "itertools 0.10.5", 383 | "lazy_static", 384 | "lightningcss-derive", 385 | "parcel_selectors", 386 | "paste", 387 | "pathdiff", 388 | "smallvec", 389 | ] 390 | 391 | [[package]] 392 | name = "lightningcss-derive" 393 | version = "1.0.0-alpha.43" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "84c12744d1279367caed41739ef094c325d53fb0ffcd4f9b84a368796f870252" 396 | dependencies = [ 397 | "convert_case", 398 | "proc-macro2", 399 | "quote", 400 | "syn 1.0.109", 401 | ] 402 | 403 | [[package]] 404 | name = "load_settings_from_cargo_manifest" 405 | version = "0.1.0" 406 | dependencies = [ 407 | "turf", 408 | "turf_internals", 409 | ] 410 | 411 | [[package]] 412 | name = "log" 413 | version = "0.4.27" 414 | source = "registry+https://github.com/rust-lang/crates.io-index" 415 | checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 416 | 417 | [[package]] 418 | name = "memchr" 419 | version = "2.7.4" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 422 | 423 | [[package]] 424 | name = "minimal-lexical" 425 | version = "0.2.1" 426 | source = "registry+https://github.com/rust-lang/crates.io-index" 427 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 428 | 429 | [[package]] 430 | name = "nom" 431 | version = "7.1.3" 432 | source = "registry+https://github.com/rust-lang/crates.io-index" 433 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 434 | dependencies = [ 435 | "memchr", 436 | "minimal-lexical", 437 | ] 438 | 439 | [[package]] 440 | name = "num-traits" 441 | version = "0.2.19" 442 | source = "registry+https://github.com/rust-lang/crates.io-index" 443 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 444 | dependencies = [ 445 | "autocfg", 446 | ] 447 | 448 | [[package]] 449 | name = "once_cell" 450 | version = "1.21.3" 451 | source = "registry+https://github.com/rust-lang/crates.io-index" 452 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 453 | 454 | [[package]] 455 | name = "oorandom" 456 | version = "11.1.5" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" 459 | 460 | [[package]] 461 | name = "parcel_selectors" 462 | version = "0.28.1" 463 | source = "registry+https://github.com/rust-lang/crates.io-index" 464 | checksum = "dccbc6fb560df303a44e511618256029410efbc87779018f751ef12c488271fe" 465 | dependencies = [ 466 | "bitflags", 467 | "cssparser", 468 | "log", 469 | "phf", 470 | "phf_codegen", 471 | "precomputed-hash", 472 | "rustc-hash", 473 | "smallvec", 474 | ] 475 | 476 | [[package]] 477 | name = "paste" 478 | version = "1.0.15" 479 | source = "registry+https://github.com/rust-lang/crates.io-index" 480 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 481 | 482 | [[package]] 483 | name = "pathdiff" 484 | version = "0.2.3" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" 487 | 488 | [[package]] 489 | name = "phf" 490 | version = "0.11.3" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" 493 | dependencies = [ 494 | "phf_macros", 495 | "phf_shared", 496 | ] 497 | 498 | [[package]] 499 | name = "phf_codegen" 500 | version = "0.11.3" 501 | source = "registry+https://github.com/rust-lang/crates.io-index" 502 | checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" 503 | dependencies = [ 504 | "phf_generator", 505 | "phf_shared", 506 | ] 507 | 508 | [[package]] 509 | name = "phf_generator" 510 | version = "0.11.3" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" 513 | dependencies = [ 514 | "phf_shared", 515 | "rand", 516 | ] 517 | 518 | [[package]] 519 | name = "phf_macros" 520 | version = "0.11.3" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" 523 | dependencies = [ 524 | "phf_generator", 525 | "phf_shared", 526 | "proc-macro2", 527 | "quote", 528 | "syn 2.0.100", 529 | ] 530 | 531 | [[package]] 532 | name = "phf_shared" 533 | version = "0.11.3" 534 | source = "registry+https://github.com/rust-lang/crates.io-index" 535 | checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" 536 | dependencies = [ 537 | "siphasher", 538 | ] 539 | 540 | [[package]] 541 | name = "precomputed-hash" 542 | version = "0.1.1" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" 545 | 546 | [[package]] 547 | name = "proc-macro2" 548 | version = "1.0.94" 549 | source = "registry+https://github.com/rust-lang/crates.io-index" 550 | checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" 551 | dependencies = [ 552 | "unicode-ident", 553 | ] 554 | 555 | [[package]] 556 | name = "quote" 557 | version = "1.0.40" 558 | source = "registry+https://github.com/rust-lang/crates.io-index" 559 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 560 | dependencies = [ 561 | "proc-macro2", 562 | ] 563 | 564 | [[package]] 565 | name = "rand" 566 | version = "0.8.5" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 569 | dependencies = [ 570 | "rand_core", 571 | ] 572 | 573 | [[package]] 574 | name = "rand_core" 575 | version = "0.6.4" 576 | source = "registry+https://github.com/rust-lang/crates.io-index" 577 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 578 | 579 | [[package]] 580 | name = "regex" 581 | version = "1.11.1" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 584 | dependencies = [ 585 | "aho-corasick", 586 | "memchr", 587 | "regex-automata", 588 | "regex-syntax", 589 | ] 590 | 591 | [[package]] 592 | name = "regex-automata" 593 | version = "0.4.9" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 596 | dependencies = [ 597 | "aho-corasick", 598 | "memchr", 599 | "regex-syntax", 600 | ] 601 | 602 | [[package]] 603 | name = "regex-syntax" 604 | version = "0.8.5" 605 | source = "registry+https://github.com/rust-lang/crates.io-index" 606 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 607 | 608 | [[package]] 609 | name = "rustc-hash" 610 | version = "2.1.1" 611 | source = "registry+https://github.com/rust-lang/crates.io-index" 612 | checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" 613 | 614 | [[package]] 615 | name = "rustversion" 616 | version = "1.0.20" 617 | source = "registry+https://github.com/rust-lang/crates.io-index" 618 | checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" 619 | 620 | [[package]] 621 | name = "ryu" 622 | version = "1.0.20" 623 | source = "registry+https://github.com/rust-lang/crates.io-index" 624 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 625 | 626 | [[package]] 627 | name = "serde" 628 | version = "1.0.219" 629 | source = "registry+https://github.com/rust-lang/crates.io-index" 630 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 631 | dependencies = [ 632 | "serde_derive", 633 | ] 634 | 635 | [[package]] 636 | name = "serde_derive" 637 | version = "1.0.219" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 640 | dependencies = [ 641 | "proc-macro2", 642 | "quote", 643 | "syn 2.0.100", 644 | ] 645 | 646 | [[package]] 647 | name = "serde_json" 648 | version = "1.0.140" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" 651 | dependencies = [ 652 | "itoa", 653 | "memchr", 654 | "ryu", 655 | "serde", 656 | ] 657 | 658 | [[package]] 659 | name = "serde_spanned" 660 | version = "0.6.8" 661 | source = "registry+https://github.com/rust-lang/crates.io-index" 662 | checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 663 | dependencies = [ 664 | "serde", 665 | ] 666 | 667 | [[package]] 668 | name = "shlex" 669 | version = "1.3.0" 670 | source = "registry+https://github.com/rust-lang/crates.io-index" 671 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 672 | 673 | [[package]] 674 | name = "siphasher" 675 | version = "1.0.1" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" 678 | 679 | [[package]] 680 | name = "smallvec" 681 | version = "1.15.0" 682 | source = "registry+https://github.com/rust-lang/crates.io-index" 683 | checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" 684 | 685 | [[package]] 686 | name = "syn" 687 | version = "1.0.109" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 690 | dependencies = [ 691 | "proc-macro2", 692 | "quote", 693 | "unicode-ident", 694 | ] 695 | 696 | [[package]] 697 | name = "syn" 698 | version = "2.0.100" 699 | source = "registry+https://github.com/rust-lang/crates.io-index" 700 | checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" 701 | dependencies = [ 702 | "proc-macro2", 703 | "quote", 704 | "unicode-ident", 705 | ] 706 | 707 | [[package]] 708 | name = "thiserror" 709 | version = "1.0.69" 710 | source = "registry+https://github.com/rust-lang/crates.io-index" 711 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 712 | dependencies = [ 713 | "thiserror-impl", 714 | ] 715 | 716 | [[package]] 717 | name = "thiserror-impl" 718 | version = "1.0.69" 719 | source = "registry+https://github.com/rust-lang/crates.io-index" 720 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 721 | dependencies = [ 722 | "proc-macro2", 723 | "quote", 724 | "syn 2.0.100", 725 | ] 726 | 727 | [[package]] 728 | name = "toml" 729 | version = "0.8.20" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" 732 | dependencies = [ 733 | "serde", 734 | "serde_spanned", 735 | "toml_datetime", 736 | "toml_edit", 737 | ] 738 | 739 | [[package]] 740 | name = "toml_datetime" 741 | version = "0.6.8" 742 | source = "registry+https://github.com/rust-lang/crates.io-index" 743 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 744 | dependencies = [ 745 | "serde", 746 | ] 747 | 748 | [[package]] 749 | name = "toml_edit" 750 | version = "0.22.24" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" 753 | dependencies = [ 754 | "indexmap", 755 | "serde", 756 | "serde_spanned", 757 | "toml_datetime", 758 | "winnow", 759 | ] 760 | 761 | [[package]] 762 | name = "turf" 763 | version = "0.10.0" 764 | dependencies = [ 765 | "turf_macros", 766 | ] 767 | 768 | [[package]] 769 | name = "turf_internals" 770 | version = "0.10.0" 771 | dependencies = [ 772 | "getrandom", 773 | "grass", 774 | "lightningcss", 775 | "oorandom", 776 | "regex", 777 | "serde", 778 | "thiserror", 779 | "toml", 780 | "xxhash-rust", 781 | ] 782 | 783 | [[package]] 784 | name = "turf_macros" 785 | version = "0.10.0" 786 | dependencies = [ 787 | "convert_case", 788 | "proc-macro2", 789 | "quote", 790 | "turf_internals", 791 | ] 792 | 793 | [[package]] 794 | name = "unicode-ident" 795 | version = "1.0.18" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 798 | 799 | [[package]] 800 | name = "unicode-segmentation" 801 | version = "1.12.0" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" 804 | 805 | [[package]] 806 | name = "use_default_settings" 807 | version = "0.1.0" 808 | dependencies = [ 809 | "turf", 810 | "turf_internals", 811 | ] 812 | 813 | [[package]] 814 | name = "version_check" 815 | version = "0.9.5" 816 | source = "registry+https://github.com/rust-lang/crates.io-index" 817 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 818 | 819 | [[package]] 820 | name = "wasi" 821 | version = "0.11.0+wasi-snapshot-preview1" 822 | source = "registry+https://github.com/rust-lang/crates.io-index" 823 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 824 | 825 | [[package]] 826 | name = "wasm-bindgen" 827 | version = "0.2.100" 828 | source = "registry+https://github.com/rust-lang/crates.io-index" 829 | checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" 830 | dependencies = [ 831 | "cfg-if", 832 | "once_cell", 833 | "rustversion", 834 | "wasm-bindgen-macro", 835 | ] 836 | 837 | [[package]] 838 | name = "wasm-bindgen-backend" 839 | version = "0.2.100" 840 | source = "registry+https://github.com/rust-lang/crates.io-index" 841 | checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" 842 | dependencies = [ 843 | "bumpalo", 844 | "log", 845 | "proc-macro2", 846 | "quote", 847 | "syn 2.0.100", 848 | "wasm-bindgen-shared", 849 | ] 850 | 851 | [[package]] 852 | name = "wasm-bindgen-macro" 853 | version = "0.2.100" 854 | source = "registry+https://github.com/rust-lang/crates.io-index" 855 | checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" 856 | dependencies = [ 857 | "quote", 858 | "wasm-bindgen-macro-support", 859 | ] 860 | 861 | [[package]] 862 | name = "wasm-bindgen-macro-support" 863 | version = "0.2.100" 864 | source = "registry+https://github.com/rust-lang/crates.io-index" 865 | checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" 866 | dependencies = [ 867 | "proc-macro2", 868 | "quote", 869 | "syn 2.0.100", 870 | "wasm-bindgen-backend", 871 | "wasm-bindgen-shared", 872 | ] 873 | 874 | [[package]] 875 | name = "wasm-bindgen-shared" 876 | version = "0.2.100" 877 | source = "registry+https://github.com/rust-lang/crates.io-index" 878 | checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" 879 | dependencies = [ 880 | "unicode-ident", 881 | ] 882 | 883 | [[package]] 884 | name = "windows-core" 885 | version = "0.61.0" 886 | source = "registry+https://github.com/rust-lang/crates.io-index" 887 | checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" 888 | dependencies = [ 889 | "windows-implement", 890 | "windows-interface", 891 | "windows-link", 892 | "windows-result", 893 | "windows-strings", 894 | ] 895 | 896 | [[package]] 897 | name = "windows-implement" 898 | version = "0.60.0" 899 | source = "registry+https://github.com/rust-lang/crates.io-index" 900 | checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" 901 | dependencies = [ 902 | "proc-macro2", 903 | "quote", 904 | "syn 2.0.100", 905 | ] 906 | 907 | [[package]] 908 | name = "windows-interface" 909 | version = "0.59.1" 910 | source = "registry+https://github.com/rust-lang/crates.io-index" 911 | checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" 912 | dependencies = [ 913 | "proc-macro2", 914 | "quote", 915 | "syn 2.0.100", 916 | ] 917 | 918 | [[package]] 919 | name = "windows-link" 920 | version = "0.1.1" 921 | source = "registry+https://github.com/rust-lang/crates.io-index" 922 | checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" 923 | 924 | [[package]] 925 | name = "windows-result" 926 | version = "0.3.2" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" 929 | dependencies = [ 930 | "windows-link", 931 | ] 932 | 933 | [[package]] 934 | name = "windows-strings" 935 | version = "0.4.0" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" 938 | dependencies = [ 939 | "windows-link", 940 | ] 941 | 942 | [[package]] 943 | name = "winnow" 944 | version = "0.7.6" 945 | source = "registry+https://github.com/rust-lang/crates.io-index" 946 | checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" 947 | dependencies = [ 948 | "memchr", 949 | ] 950 | 951 | [[package]] 952 | name = "xxhash-rust" 953 | version = "0.8.15" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" 956 | 957 | [[package]] 958 | name = "zerocopy" 959 | version = "0.7.35" 960 | source = "registry+https://github.com/rust-lang/crates.io-index" 961 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 962 | dependencies = [ 963 | "zerocopy-derive", 964 | ] 965 | 966 | [[package]] 967 | name = "zerocopy-derive" 968 | version = "0.7.35" 969 | source = "registry+https://github.com/rust-lang/crates.io-index" 970 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 971 | dependencies = [ 972 | "proc-macro2", 973 | "quote", 974 | "syn 2.0.100", 975 | ] 976 | -------------------------------------------------------------------------------- /examples/axum-askama-htmx/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "ahash" 22 | version = "0.8.11" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 25 | dependencies = [ 26 | "cfg-if", 27 | "getrandom", 28 | "once_cell", 29 | "serde", 30 | "version_check", 31 | "zerocopy", 32 | ] 33 | 34 | [[package]] 35 | name = "aho-corasick" 36 | version = "1.1.3" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 39 | dependencies = [ 40 | "memchr", 41 | ] 42 | 43 | [[package]] 44 | name = "allocator-api2" 45 | version = "0.2.21" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" 48 | 49 | [[package]] 50 | name = "android-tzdata" 51 | version = "0.1.1" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 54 | 55 | [[package]] 56 | name = "android_system_properties" 57 | version = "0.1.5" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 60 | dependencies = [ 61 | "libc", 62 | ] 63 | 64 | [[package]] 65 | name = "askama" 66 | version = "0.12.1" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" 69 | dependencies = [ 70 | "askama_derive", 71 | "askama_escape", 72 | "humansize", 73 | "num-traits", 74 | "percent-encoding", 75 | ] 76 | 77 | [[package]] 78 | name = "askama_axum" 79 | version = "0.4.0" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "a41603f7cdbf5ac4af60760f17253eb6adf6ec5b6f14a7ed830cf687d375f163" 82 | dependencies = [ 83 | "askama", 84 | "axum-core", 85 | "http", 86 | ] 87 | 88 | [[package]] 89 | name = "askama_derive" 90 | version = "0.12.5" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" 93 | dependencies = [ 94 | "askama_parser", 95 | "basic-toml", 96 | "mime", 97 | "mime_guess", 98 | "proc-macro2", 99 | "quote", 100 | "serde", 101 | "syn 2.0.100", 102 | ] 103 | 104 | [[package]] 105 | name = "askama_escape" 106 | version = "0.10.3" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" 109 | 110 | [[package]] 111 | name = "askama_parser" 112 | version = "0.2.1" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" 115 | dependencies = [ 116 | "nom", 117 | ] 118 | 119 | [[package]] 120 | name = "async-trait" 121 | version = "0.1.88" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" 124 | dependencies = [ 125 | "proc-macro2", 126 | "quote", 127 | "syn 2.0.100", 128 | ] 129 | 130 | [[package]] 131 | name = "autocfg" 132 | version = "1.4.0" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 135 | 136 | [[package]] 137 | name = "axum" 138 | version = "0.7.9" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" 141 | dependencies = [ 142 | "async-trait", 143 | "axum-core", 144 | "bytes", 145 | "futures-util", 146 | "http", 147 | "http-body", 148 | "http-body-util", 149 | "hyper", 150 | "hyper-util", 151 | "itoa", 152 | "matchit", 153 | "memchr", 154 | "mime", 155 | "percent-encoding", 156 | "pin-project-lite", 157 | "rustversion", 158 | "serde", 159 | "serde_json", 160 | "serde_path_to_error", 161 | "serde_urlencoded", 162 | "sync_wrapper", 163 | "tokio", 164 | "tower 0.5.2", 165 | "tower-layer", 166 | "tower-service", 167 | "tracing", 168 | ] 169 | 170 | [[package]] 171 | name = "axum-askama-htmx" 172 | version = "0.1.0" 173 | dependencies = [ 174 | "askama", 175 | "askama_axum", 176 | "axum", 177 | "tokio", 178 | "tower 0.4.13", 179 | "turf", 180 | ] 181 | 182 | [[package]] 183 | name = "axum-core" 184 | version = "0.4.5" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" 187 | dependencies = [ 188 | "async-trait", 189 | "bytes", 190 | "futures-util", 191 | "http", 192 | "http-body", 193 | "http-body-util", 194 | "mime", 195 | "pin-project-lite", 196 | "rustversion", 197 | "sync_wrapper", 198 | "tower-layer", 199 | "tower-service", 200 | "tracing", 201 | ] 202 | 203 | [[package]] 204 | name = "backtrace" 205 | version = "0.3.74" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 208 | dependencies = [ 209 | "addr2line", 210 | "cfg-if", 211 | "libc", 212 | "miniz_oxide", 213 | "object", 214 | "rustc-demangle", 215 | "windows-targets", 216 | ] 217 | 218 | [[package]] 219 | name = "basic-toml" 220 | version = "0.1.10" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" 223 | dependencies = [ 224 | "serde", 225 | ] 226 | 227 | [[package]] 228 | name = "bitflags" 229 | version = "2.9.0" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" 232 | 233 | [[package]] 234 | name = "browserslist-rs" 235 | version = "0.17.0" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "74c973b79d9b6b89854493185ab760c6ef8e54bcfad10ad4e33991e46b374ac8" 238 | dependencies = [ 239 | "ahash", 240 | "chrono", 241 | "either", 242 | "indexmap", 243 | "itertools 0.13.0", 244 | "nom", 245 | "serde", 246 | "serde_json", 247 | "thiserror", 248 | ] 249 | 250 | [[package]] 251 | name = "bumpalo" 252 | version = "3.17.0" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" 255 | 256 | [[package]] 257 | name = "bytes" 258 | version = "1.10.1" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" 261 | 262 | [[package]] 263 | name = "cc" 264 | version = "1.2.19" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" 267 | dependencies = [ 268 | "shlex", 269 | ] 270 | 271 | [[package]] 272 | name = "cfg-if" 273 | version = "1.0.0" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 276 | 277 | [[package]] 278 | name = "chrono" 279 | version = "0.4.40" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" 282 | dependencies = [ 283 | "android-tzdata", 284 | "iana-time-zone", 285 | "num-traits", 286 | "windows-link", 287 | ] 288 | 289 | [[package]] 290 | name = "codemap" 291 | version = "0.1.3" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "b9e769b5c8c8283982a987c6e948e540254f1058d5a74b8794914d4ef5fc2a24" 294 | 295 | [[package]] 296 | name = "const-str" 297 | version = "0.3.2" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "21077772762a1002bb421c3af42ac1725fa56066bfc53d9a55bb79905df2aaf3" 300 | dependencies = [ 301 | "const-str-proc-macro", 302 | ] 303 | 304 | [[package]] 305 | name = "const-str-proc-macro" 306 | version = "0.3.2" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "5e1e0fdd2e5d3041e530e1b21158aeeef8b5d0e306bc5c1e3d6cf0930d10e25a" 309 | dependencies = [ 310 | "proc-macro2", 311 | "quote", 312 | "syn 1.0.109", 313 | ] 314 | 315 | [[package]] 316 | name = "convert_case" 317 | version = "0.6.0" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" 320 | dependencies = [ 321 | "unicode-segmentation", 322 | ] 323 | 324 | [[package]] 325 | name = "core-foundation-sys" 326 | version = "0.8.7" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 329 | 330 | [[package]] 331 | name = "cssparser" 332 | version = "0.33.0" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "9be934d936a0fbed5bcdc01042b770de1398bf79d0e192f49fa7faea0e99281e" 335 | dependencies = [ 336 | "cssparser-macros", 337 | "dtoa-short", 338 | "itoa", 339 | "phf", 340 | "smallvec", 341 | ] 342 | 343 | [[package]] 344 | name = "cssparser-color" 345 | version = "0.1.0" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "556c099a61d85989d7af52b692e35a8d68a57e7df8c6d07563dc0778b3960c9f" 348 | dependencies = [ 349 | "cssparser", 350 | ] 351 | 352 | [[package]] 353 | name = "cssparser-macros" 354 | version = "0.6.1" 355 | source = "registry+https://github.com/rust-lang/crates.io-index" 356 | checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" 357 | dependencies = [ 358 | "quote", 359 | "syn 2.0.100", 360 | ] 361 | 362 | [[package]] 363 | name = "data-encoding" 364 | version = "2.9.0" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" 367 | 368 | [[package]] 369 | name = "dtoa" 370 | version = "1.0.10" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" 373 | 374 | [[package]] 375 | name = "dtoa-short" 376 | version = "0.3.5" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" 379 | dependencies = [ 380 | "dtoa", 381 | ] 382 | 383 | [[package]] 384 | name = "either" 385 | version = "1.15.0" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 388 | 389 | [[package]] 390 | name = "equivalent" 391 | version = "1.0.2" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 394 | 395 | [[package]] 396 | name = "fnv" 397 | version = "1.0.7" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 400 | 401 | [[package]] 402 | name = "form_urlencoded" 403 | version = "1.2.1" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 406 | dependencies = [ 407 | "percent-encoding", 408 | ] 409 | 410 | [[package]] 411 | name = "futures-channel" 412 | version = "0.3.31" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 415 | dependencies = [ 416 | "futures-core", 417 | ] 418 | 419 | [[package]] 420 | name = "futures-core" 421 | version = "0.3.31" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 424 | 425 | [[package]] 426 | name = "futures-task" 427 | version = "0.3.31" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 430 | 431 | [[package]] 432 | name = "futures-util" 433 | version = "0.3.31" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 436 | dependencies = [ 437 | "futures-core", 438 | "futures-task", 439 | "pin-project-lite", 440 | "pin-utils", 441 | ] 442 | 443 | [[package]] 444 | name = "getrandom" 445 | version = "0.2.15" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 448 | dependencies = [ 449 | "cfg-if", 450 | "js-sys", 451 | "libc", 452 | "wasi", 453 | "wasm-bindgen", 454 | ] 455 | 456 | [[package]] 457 | name = "gimli" 458 | version = "0.31.1" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 461 | 462 | [[package]] 463 | name = "grass" 464 | version = "0.13.4" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "f7a68216437ef68f0738e48d6c7bb9e6e6a92237e001b03d838314b068f33c94" 467 | dependencies = [ 468 | "getrandom", 469 | "grass_compiler", 470 | ] 471 | 472 | [[package]] 473 | name = "grass_compiler" 474 | version = "0.13.4" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "2d9e3df7f0222ce5184154973d247c591d9aadc28ce7a73c6cd31100c9facff6" 477 | dependencies = [ 478 | "codemap", 479 | "indexmap", 480 | "lasso", 481 | "once_cell", 482 | "phf", 483 | ] 484 | 485 | [[package]] 486 | name = "hashbrown" 487 | version = "0.14.5" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 490 | dependencies = [ 491 | "ahash", 492 | "allocator-api2", 493 | ] 494 | 495 | [[package]] 496 | name = "hashbrown" 497 | version = "0.15.2" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 500 | 501 | [[package]] 502 | name = "http" 503 | version = "1.3.1" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" 506 | dependencies = [ 507 | "bytes", 508 | "fnv", 509 | "itoa", 510 | ] 511 | 512 | [[package]] 513 | name = "http-body" 514 | version = "1.0.1" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 517 | dependencies = [ 518 | "bytes", 519 | "http", 520 | ] 521 | 522 | [[package]] 523 | name = "http-body-util" 524 | version = "0.1.3" 525 | source = "registry+https://github.com/rust-lang/crates.io-index" 526 | checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" 527 | dependencies = [ 528 | "bytes", 529 | "futures-core", 530 | "http", 531 | "http-body", 532 | "pin-project-lite", 533 | ] 534 | 535 | [[package]] 536 | name = "httparse" 537 | version = "1.10.1" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" 540 | 541 | [[package]] 542 | name = "httpdate" 543 | version = "1.0.3" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 546 | 547 | [[package]] 548 | name = "humansize" 549 | version = "2.1.3" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" 552 | dependencies = [ 553 | "libm", 554 | ] 555 | 556 | [[package]] 557 | name = "hyper" 558 | version = "1.6.0" 559 | source = "registry+https://github.com/rust-lang/crates.io-index" 560 | checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" 561 | dependencies = [ 562 | "bytes", 563 | "futures-channel", 564 | "futures-util", 565 | "http", 566 | "http-body", 567 | "httparse", 568 | "httpdate", 569 | "itoa", 570 | "pin-project-lite", 571 | "smallvec", 572 | "tokio", 573 | ] 574 | 575 | [[package]] 576 | name = "hyper-util" 577 | version = "0.1.11" 578 | source = "registry+https://github.com/rust-lang/crates.io-index" 579 | checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" 580 | dependencies = [ 581 | "bytes", 582 | "futures-util", 583 | "http", 584 | "http-body", 585 | "hyper", 586 | "pin-project-lite", 587 | "tokio", 588 | "tower-service", 589 | ] 590 | 591 | [[package]] 592 | name = "iana-time-zone" 593 | version = "0.1.63" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" 596 | dependencies = [ 597 | "android_system_properties", 598 | "core-foundation-sys", 599 | "iana-time-zone-haiku", 600 | "js-sys", 601 | "log", 602 | "wasm-bindgen", 603 | "windows-core", 604 | ] 605 | 606 | [[package]] 607 | name = "iana-time-zone-haiku" 608 | version = "0.1.2" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 611 | dependencies = [ 612 | "cc", 613 | ] 614 | 615 | [[package]] 616 | name = "indexmap" 617 | version = "2.9.0" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" 620 | dependencies = [ 621 | "equivalent", 622 | "hashbrown 0.15.2", 623 | "serde", 624 | ] 625 | 626 | [[package]] 627 | name = "itertools" 628 | version = "0.10.5" 629 | source = "registry+https://github.com/rust-lang/crates.io-index" 630 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 631 | dependencies = [ 632 | "either", 633 | ] 634 | 635 | [[package]] 636 | name = "itertools" 637 | version = "0.13.0" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" 640 | dependencies = [ 641 | "either", 642 | ] 643 | 644 | [[package]] 645 | name = "itoa" 646 | version = "1.0.15" 647 | source = "registry+https://github.com/rust-lang/crates.io-index" 648 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 649 | 650 | [[package]] 651 | name = "js-sys" 652 | version = "0.3.77" 653 | source = "registry+https://github.com/rust-lang/crates.io-index" 654 | checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" 655 | dependencies = [ 656 | "once_cell", 657 | "wasm-bindgen", 658 | ] 659 | 660 | [[package]] 661 | name = "lasso" 662 | version = "0.7.3" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "6e14eda50a3494b3bf7b9ce51c52434a761e383d7238ce1dd5dcec2fbc13e9fb" 665 | dependencies = [ 666 | "hashbrown 0.14.5", 667 | ] 668 | 669 | [[package]] 670 | name = "lazy_static" 671 | version = "1.5.0" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 674 | 675 | [[package]] 676 | name = "libc" 677 | version = "0.2.172" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" 680 | 681 | [[package]] 682 | name = "libm" 683 | version = "0.2.11" 684 | source = "registry+https://github.com/rust-lang/crates.io-index" 685 | checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" 686 | 687 | [[package]] 688 | name = "lightningcss" 689 | version = "1.0.0-alpha.65" 690 | source = "registry+https://github.com/rust-lang/crates.io-index" 691 | checksum = "c84f971730745f4aaac013b6cf4328baf1548efc973c0d95cfd843a3c1ca07af" 692 | dependencies = [ 693 | "ahash", 694 | "bitflags", 695 | "browserslist-rs", 696 | "const-str", 697 | "cssparser", 698 | "cssparser-color", 699 | "data-encoding", 700 | "getrandom", 701 | "indexmap", 702 | "itertools 0.10.5", 703 | "lazy_static", 704 | "lightningcss-derive", 705 | "parcel_selectors", 706 | "paste", 707 | "pathdiff", 708 | "smallvec", 709 | ] 710 | 711 | [[package]] 712 | name = "lightningcss-derive" 713 | version = "1.0.0-alpha.43" 714 | source = "registry+https://github.com/rust-lang/crates.io-index" 715 | checksum = "84c12744d1279367caed41739ef094c325d53fb0ffcd4f9b84a368796f870252" 716 | dependencies = [ 717 | "convert_case", 718 | "proc-macro2", 719 | "quote", 720 | "syn 1.0.109", 721 | ] 722 | 723 | [[package]] 724 | name = "lock_api" 725 | version = "0.4.12" 726 | source = "registry+https://github.com/rust-lang/crates.io-index" 727 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 728 | dependencies = [ 729 | "autocfg", 730 | "scopeguard", 731 | ] 732 | 733 | [[package]] 734 | name = "log" 735 | version = "0.4.27" 736 | source = "registry+https://github.com/rust-lang/crates.io-index" 737 | checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 738 | 739 | [[package]] 740 | name = "matchit" 741 | version = "0.7.3" 742 | source = "registry+https://github.com/rust-lang/crates.io-index" 743 | checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" 744 | 745 | [[package]] 746 | name = "memchr" 747 | version = "2.7.4" 748 | source = "registry+https://github.com/rust-lang/crates.io-index" 749 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 750 | 751 | [[package]] 752 | name = "mime" 753 | version = "0.3.17" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 756 | 757 | [[package]] 758 | name = "mime_guess" 759 | version = "2.0.5" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" 762 | dependencies = [ 763 | "mime", 764 | "unicase", 765 | ] 766 | 767 | [[package]] 768 | name = "minimal-lexical" 769 | version = "0.2.1" 770 | source = "registry+https://github.com/rust-lang/crates.io-index" 771 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 772 | 773 | [[package]] 774 | name = "miniz_oxide" 775 | version = "0.8.8" 776 | source = "registry+https://github.com/rust-lang/crates.io-index" 777 | checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" 778 | dependencies = [ 779 | "adler2", 780 | ] 781 | 782 | [[package]] 783 | name = "mio" 784 | version = "1.0.3" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 787 | dependencies = [ 788 | "libc", 789 | "wasi", 790 | "windows-sys", 791 | ] 792 | 793 | [[package]] 794 | name = "nom" 795 | version = "7.1.3" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 798 | dependencies = [ 799 | "memchr", 800 | "minimal-lexical", 801 | ] 802 | 803 | [[package]] 804 | name = "num-traits" 805 | version = "0.2.19" 806 | source = "registry+https://github.com/rust-lang/crates.io-index" 807 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 808 | dependencies = [ 809 | "autocfg", 810 | ] 811 | 812 | [[package]] 813 | name = "object" 814 | version = "0.36.7" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 817 | dependencies = [ 818 | "memchr", 819 | ] 820 | 821 | [[package]] 822 | name = "once_cell" 823 | version = "1.21.3" 824 | source = "registry+https://github.com/rust-lang/crates.io-index" 825 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 826 | 827 | [[package]] 828 | name = "oorandom" 829 | version = "11.1.5" 830 | source = "registry+https://github.com/rust-lang/crates.io-index" 831 | checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" 832 | 833 | [[package]] 834 | name = "parcel_selectors" 835 | version = "0.28.1" 836 | source = "registry+https://github.com/rust-lang/crates.io-index" 837 | checksum = "dccbc6fb560df303a44e511618256029410efbc87779018f751ef12c488271fe" 838 | dependencies = [ 839 | "bitflags", 840 | "cssparser", 841 | "log", 842 | "phf", 843 | "phf_codegen", 844 | "precomputed-hash", 845 | "rustc-hash", 846 | "smallvec", 847 | ] 848 | 849 | [[package]] 850 | name = "parking_lot" 851 | version = "0.12.3" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 854 | dependencies = [ 855 | "lock_api", 856 | "parking_lot_core", 857 | ] 858 | 859 | [[package]] 860 | name = "parking_lot_core" 861 | version = "0.9.10" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 864 | dependencies = [ 865 | "cfg-if", 866 | "libc", 867 | "redox_syscall", 868 | "smallvec", 869 | "windows-targets", 870 | ] 871 | 872 | [[package]] 873 | name = "paste" 874 | version = "1.0.15" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 877 | 878 | [[package]] 879 | name = "pathdiff" 880 | version = "0.2.3" 881 | source = "registry+https://github.com/rust-lang/crates.io-index" 882 | checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" 883 | 884 | [[package]] 885 | name = "percent-encoding" 886 | version = "2.3.1" 887 | source = "registry+https://github.com/rust-lang/crates.io-index" 888 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 889 | 890 | [[package]] 891 | name = "phf" 892 | version = "0.11.3" 893 | source = "registry+https://github.com/rust-lang/crates.io-index" 894 | checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" 895 | dependencies = [ 896 | "phf_macros", 897 | "phf_shared", 898 | ] 899 | 900 | [[package]] 901 | name = "phf_codegen" 902 | version = "0.11.3" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" 905 | dependencies = [ 906 | "phf_generator", 907 | "phf_shared", 908 | ] 909 | 910 | [[package]] 911 | name = "phf_generator" 912 | version = "0.11.3" 913 | source = "registry+https://github.com/rust-lang/crates.io-index" 914 | checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" 915 | dependencies = [ 916 | "phf_shared", 917 | "rand", 918 | ] 919 | 920 | [[package]] 921 | name = "phf_macros" 922 | version = "0.11.3" 923 | source = "registry+https://github.com/rust-lang/crates.io-index" 924 | checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" 925 | dependencies = [ 926 | "phf_generator", 927 | "phf_shared", 928 | "proc-macro2", 929 | "quote", 930 | "syn 2.0.100", 931 | ] 932 | 933 | [[package]] 934 | name = "phf_shared" 935 | version = "0.11.3" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" 938 | dependencies = [ 939 | "siphasher", 940 | ] 941 | 942 | [[package]] 943 | name = "pin-project" 944 | version = "1.1.10" 945 | source = "registry+https://github.com/rust-lang/crates.io-index" 946 | checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" 947 | dependencies = [ 948 | "pin-project-internal", 949 | ] 950 | 951 | [[package]] 952 | name = "pin-project-internal" 953 | version = "1.1.10" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" 956 | dependencies = [ 957 | "proc-macro2", 958 | "quote", 959 | "syn 2.0.100", 960 | ] 961 | 962 | [[package]] 963 | name = "pin-project-lite" 964 | version = "0.2.16" 965 | source = "registry+https://github.com/rust-lang/crates.io-index" 966 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 967 | 968 | [[package]] 969 | name = "pin-utils" 970 | version = "0.1.0" 971 | source = "registry+https://github.com/rust-lang/crates.io-index" 972 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 973 | 974 | [[package]] 975 | name = "precomputed-hash" 976 | version = "0.1.1" 977 | source = "registry+https://github.com/rust-lang/crates.io-index" 978 | checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" 979 | 980 | [[package]] 981 | name = "proc-macro2" 982 | version = "1.0.94" 983 | source = "registry+https://github.com/rust-lang/crates.io-index" 984 | checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" 985 | dependencies = [ 986 | "unicode-ident", 987 | ] 988 | 989 | [[package]] 990 | name = "quote" 991 | version = "1.0.40" 992 | source = "registry+https://github.com/rust-lang/crates.io-index" 993 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 994 | dependencies = [ 995 | "proc-macro2", 996 | ] 997 | 998 | [[package]] 999 | name = "rand" 1000 | version = "0.8.5" 1001 | source = "registry+https://github.com/rust-lang/crates.io-index" 1002 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1003 | dependencies = [ 1004 | "rand_core", 1005 | ] 1006 | 1007 | [[package]] 1008 | name = "rand_core" 1009 | version = "0.6.4" 1010 | source = "registry+https://github.com/rust-lang/crates.io-index" 1011 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1012 | 1013 | [[package]] 1014 | name = "redox_syscall" 1015 | version = "0.5.11" 1016 | source = "registry+https://github.com/rust-lang/crates.io-index" 1017 | checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" 1018 | dependencies = [ 1019 | "bitflags", 1020 | ] 1021 | 1022 | [[package]] 1023 | name = "regex" 1024 | version = "1.11.1" 1025 | source = "registry+https://github.com/rust-lang/crates.io-index" 1026 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 1027 | dependencies = [ 1028 | "aho-corasick", 1029 | "memchr", 1030 | "regex-automata", 1031 | "regex-syntax", 1032 | ] 1033 | 1034 | [[package]] 1035 | name = "regex-automata" 1036 | version = "0.4.9" 1037 | source = "registry+https://github.com/rust-lang/crates.io-index" 1038 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 1039 | dependencies = [ 1040 | "aho-corasick", 1041 | "memchr", 1042 | "regex-syntax", 1043 | ] 1044 | 1045 | [[package]] 1046 | name = "regex-syntax" 1047 | version = "0.8.5" 1048 | source = "registry+https://github.com/rust-lang/crates.io-index" 1049 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1050 | 1051 | [[package]] 1052 | name = "rustc-demangle" 1053 | version = "0.1.24" 1054 | source = "registry+https://github.com/rust-lang/crates.io-index" 1055 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1056 | 1057 | [[package]] 1058 | name = "rustc-hash" 1059 | version = "2.1.1" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" 1062 | 1063 | [[package]] 1064 | name = "rustversion" 1065 | version = "1.0.20" 1066 | source = "registry+https://github.com/rust-lang/crates.io-index" 1067 | checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" 1068 | 1069 | [[package]] 1070 | name = "ryu" 1071 | version = "1.0.20" 1072 | source = "registry+https://github.com/rust-lang/crates.io-index" 1073 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 1074 | 1075 | [[package]] 1076 | name = "scopeguard" 1077 | version = "1.2.0" 1078 | source = "registry+https://github.com/rust-lang/crates.io-index" 1079 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1080 | 1081 | [[package]] 1082 | name = "serde" 1083 | version = "1.0.219" 1084 | source = "registry+https://github.com/rust-lang/crates.io-index" 1085 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 1086 | dependencies = [ 1087 | "serde_derive", 1088 | ] 1089 | 1090 | [[package]] 1091 | name = "serde_derive" 1092 | version = "1.0.219" 1093 | source = "registry+https://github.com/rust-lang/crates.io-index" 1094 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 1095 | dependencies = [ 1096 | "proc-macro2", 1097 | "quote", 1098 | "syn 2.0.100", 1099 | ] 1100 | 1101 | [[package]] 1102 | name = "serde_json" 1103 | version = "1.0.140" 1104 | source = "registry+https://github.com/rust-lang/crates.io-index" 1105 | checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" 1106 | dependencies = [ 1107 | "itoa", 1108 | "memchr", 1109 | "ryu", 1110 | "serde", 1111 | ] 1112 | 1113 | [[package]] 1114 | name = "serde_path_to_error" 1115 | version = "0.1.17" 1116 | source = "registry+https://github.com/rust-lang/crates.io-index" 1117 | checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" 1118 | dependencies = [ 1119 | "itoa", 1120 | "serde", 1121 | ] 1122 | 1123 | [[package]] 1124 | name = "serde_spanned" 1125 | version = "0.6.8" 1126 | source = "registry+https://github.com/rust-lang/crates.io-index" 1127 | checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 1128 | dependencies = [ 1129 | "serde", 1130 | ] 1131 | 1132 | [[package]] 1133 | name = "serde_urlencoded" 1134 | version = "0.7.1" 1135 | source = "registry+https://github.com/rust-lang/crates.io-index" 1136 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1137 | dependencies = [ 1138 | "form_urlencoded", 1139 | "itoa", 1140 | "ryu", 1141 | "serde", 1142 | ] 1143 | 1144 | [[package]] 1145 | name = "shlex" 1146 | version = "1.3.0" 1147 | source = "registry+https://github.com/rust-lang/crates.io-index" 1148 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1149 | 1150 | [[package]] 1151 | name = "signal-hook-registry" 1152 | version = "1.4.2" 1153 | source = "registry+https://github.com/rust-lang/crates.io-index" 1154 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 1155 | dependencies = [ 1156 | "libc", 1157 | ] 1158 | 1159 | [[package]] 1160 | name = "siphasher" 1161 | version = "1.0.1" 1162 | source = "registry+https://github.com/rust-lang/crates.io-index" 1163 | checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" 1164 | 1165 | [[package]] 1166 | name = "smallvec" 1167 | version = "1.15.0" 1168 | source = "registry+https://github.com/rust-lang/crates.io-index" 1169 | checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" 1170 | 1171 | [[package]] 1172 | name = "socket2" 1173 | version = "0.5.9" 1174 | source = "registry+https://github.com/rust-lang/crates.io-index" 1175 | checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" 1176 | dependencies = [ 1177 | "libc", 1178 | "windows-sys", 1179 | ] 1180 | 1181 | [[package]] 1182 | name = "syn" 1183 | version = "1.0.109" 1184 | source = "registry+https://github.com/rust-lang/crates.io-index" 1185 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1186 | dependencies = [ 1187 | "proc-macro2", 1188 | "quote", 1189 | "unicode-ident", 1190 | ] 1191 | 1192 | [[package]] 1193 | name = "syn" 1194 | version = "2.0.100" 1195 | source = "registry+https://github.com/rust-lang/crates.io-index" 1196 | checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" 1197 | dependencies = [ 1198 | "proc-macro2", 1199 | "quote", 1200 | "unicode-ident", 1201 | ] 1202 | 1203 | [[package]] 1204 | name = "sync_wrapper" 1205 | version = "1.0.2" 1206 | source = "registry+https://github.com/rust-lang/crates.io-index" 1207 | checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 1208 | 1209 | [[package]] 1210 | name = "thiserror" 1211 | version = "1.0.69" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 1214 | dependencies = [ 1215 | "thiserror-impl", 1216 | ] 1217 | 1218 | [[package]] 1219 | name = "thiserror-impl" 1220 | version = "1.0.69" 1221 | source = "registry+https://github.com/rust-lang/crates.io-index" 1222 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 1223 | dependencies = [ 1224 | "proc-macro2", 1225 | "quote", 1226 | "syn 2.0.100", 1227 | ] 1228 | 1229 | [[package]] 1230 | name = "tokio" 1231 | version = "1.44.2" 1232 | source = "registry+https://github.com/rust-lang/crates.io-index" 1233 | checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" 1234 | dependencies = [ 1235 | "backtrace", 1236 | "bytes", 1237 | "libc", 1238 | "mio", 1239 | "parking_lot", 1240 | "pin-project-lite", 1241 | "signal-hook-registry", 1242 | "socket2", 1243 | "tokio-macros", 1244 | "windows-sys", 1245 | ] 1246 | 1247 | [[package]] 1248 | name = "tokio-macros" 1249 | version = "2.5.0" 1250 | source = "registry+https://github.com/rust-lang/crates.io-index" 1251 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 1252 | dependencies = [ 1253 | "proc-macro2", 1254 | "quote", 1255 | "syn 2.0.100", 1256 | ] 1257 | 1258 | [[package]] 1259 | name = "toml" 1260 | version = "0.8.20" 1261 | source = "registry+https://github.com/rust-lang/crates.io-index" 1262 | checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" 1263 | dependencies = [ 1264 | "serde", 1265 | "serde_spanned", 1266 | "toml_datetime", 1267 | "toml_edit", 1268 | ] 1269 | 1270 | [[package]] 1271 | name = "toml_datetime" 1272 | version = "0.6.8" 1273 | source = "registry+https://github.com/rust-lang/crates.io-index" 1274 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 1275 | dependencies = [ 1276 | "serde", 1277 | ] 1278 | 1279 | [[package]] 1280 | name = "toml_edit" 1281 | version = "0.22.24" 1282 | source = "registry+https://github.com/rust-lang/crates.io-index" 1283 | checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" 1284 | dependencies = [ 1285 | "indexmap", 1286 | "serde", 1287 | "serde_spanned", 1288 | "toml_datetime", 1289 | "winnow", 1290 | ] 1291 | 1292 | [[package]] 1293 | name = "tower" 1294 | version = "0.4.13" 1295 | source = "registry+https://github.com/rust-lang/crates.io-index" 1296 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 1297 | dependencies = [ 1298 | "futures-core", 1299 | "futures-util", 1300 | "pin-project", 1301 | "pin-project-lite", 1302 | "tower-layer", 1303 | "tower-service", 1304 | "tracing", 1305 | ] 1306 | 1307 | [[package]] 1308 | name = "tower" 1309 | version = "0.5.2" 1310 | source = "registry+https://github.com/rust-lang/crates.io-index" 1311 | checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" 1312 | dependencies = [ 1313 | "futures-core", 1314 | "futures-util", 1315 | "pin-project-lite", 1316 | "sync_wrapper", 1317 | "tokio", 1318 | "tower-layer", 1319 | "tower-service", 1320 | "tracing", 1321 | ] 1322 | 1323 | [[package]] 1324 | name = "tower-layer" 1325 | version = "0.3.3" 1326 | source = "registry+https://github.com/rust-lang/crates.io-index" 1327 | checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" 1328 | 1329 | [[package]] 1330 | name = "tower-service" 1331 | version = "0.3.3" 1332 | source = "registry+https://github.com/rust-lang/crates.io-index" 1333 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 1334 | 1335 | [[package]] 1336 | name = "tracing" 1337 | version = "0.1.41" 1338 | source = "registry+https://github.com/rust-lang/crates.io-index" 1339 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 1340 | dependencies = [ 1341 | "log", 1342 | "pin-project-lite", 1343 | "tracing-core", 1344 | ] 1345 | 1346 | [[package]] 1347 | name = "tracing-core" 1348 | version = "0.1.33" 1349 | source = "registry+https://github.com/rust-lang/crates.io-index" 1350 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 1351 | dependencies = [ 1352 | "once_cell", 1353 | ] 1354 | 1355 | [[package]] 1356 | name = "turf" 1357 | version = "0.10.0" 1358 | dependencies = [ 1359 | "turf_macros", 1360 | ] 1361 | 1362 | [[package]] 1363 | name = "turf_internals" 1364 | version = "0.10.0" 1365 | dependencies = [ 1366 | "getrandom", 1367 | "grass", 1368 | "lightningcss", 1369 | "oorandom", 1370 | "regex", 1371 | "serde", 1372 | "thiserror", 1373 | "toml", 1374 | "xxhash-rust", 1375 | ] 1376 | 1377 | [[package]] 1378 | name = "turf_macros" 1379 | version = "0.10.0" 1380 | dependencies = [ 1381 | "convert_case", 1382 | "proc-macro2", 1383 | "quote", 1384 | "turf_internals", 1385 | ] 1386 | 1387 | [[package]] 1388 | name = "unicase" 1389 | version = "2.8.1" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" 1392 | 1393 | [[package]] 1394 | name = "unicode-ident" 1395 | version = "1.0.18" 1396 | source = "registry+https://github.com/rust-lang/crates.io-index" 1397 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 1398 | 1399 | [[package]] 1400 | name = "unicode-segmentation" 1401 | version = "1.12.0" 1402 | source = "registry+https://github.com/rust-lang/crates.io-index" 1403 | checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" 1404 | 1405 | [[package]] 1406 | name = "version_check" 1407 | version = "0.9.5" 1408 | source = "registry+https://github.com/rust-lang/crates.io-index" 1409 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1410 | 1411 | [[package]] 1412 | name = "wasi" 1413 | version = "0.11.0+wasi-snapshot-preview1" 1414 | source = "registry+https://github.com/rust-lang/crates.io-index" 1415 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1416 | 1417 | [[package]] 1418 | name = "wasm-bindgen" 1419 | version = "0.2.100" 1420 | source = "registry+https://github.com/rust-lang/crates.io-index" 1421 | checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" 1422 | dependencies = [ 1423 | "cfg-if", 1424 | "once_cell", 1425 | "rustversion", 1426 | "wasm-bindgen-macro", 1427 | ] 1428 | 1429 | [[package]] 1430 | name = "wasm-bindgen-backend" 1431 | version = "0.2.100" 1432 | source = "registry+https://github.com/rust-lang/crates.io-index" 1433 | checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" 1434 | dependencies = [ 1435 | "bumpalo", 1436 | "log", 1437 | "proc-macro2", 1438 | "quote", 1439 | "syn 2.0.100", 1440 | "wasm-bindgen-shared", 1441 | ] 1442 | 1443 | [[package]] 1444 | name = "wasm-bindgen-macro" 1445 | version = "0.2.100" 1446 | source = "registry+https://github.com/rust-lang/crates.io-index" 1447 | checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" 1448 | dependencies = [ 1449 | "quote", 1450 | "wasm-bindgen-macro-support", 1451 | ] 1452 | 1453 | [[package]] 1454 | name = "wasm-bindgen-macro-support" 1455 | version = "0.2.100" 1456 | source = "registry+https://github.com/rust-lang/crates.io-index" 1457 | checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" 1458 | dependencies = [ 1459 | "proc-macro2", 1460 | "quote", 1461 | "syn 2.0.100", 1462 | "wasm-bindgen-backend", 1463 | "wasm-bindgen-shared", 1464 | ] 1465 | 1466 | [[package]] 1467 | name = "wasm-bindgen-shared" 1468 | version = "0.2.100" 1469 | source = "registry+https://github.com/rust-lang/crates.io-index" 1470 | checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" 1471 | dependencies = [ 1472 | "unicode-ident", 1473 | ] 1474 | 1475 | [[package]] 1476 | name = "windows-core" 1477 | version = "0.61.0" 1478 | source = "registry+https://github.com/rust-lang/crates.io-index" 1479 | checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" 1480 | dependencies = [ 1481 | "windows-implement", 1482 | "windows-interface", 1483 | "windows-link", 1484 | "windows-result", 1485 | "windows-strings", 1486 | ] 1487 | 1488 | [[package]] 1489 | name = "windows-implement" 1490 | version = "0.60.0" 1491 | source = "registry+https://github.com/rust-lang/crates.io-index" 1492 | checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" 1493 | dependencies = [ 1494 | "proc-macro2", 1495 | "quote", 1496 | "syn 2.0.100", 1497 | ] 1498 | 1499 | [[package]] 1500 | name = "windows-interface" 1501 | version = "0.59.1" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" 1504 | dependencies = [ 1505 | "proc-macro2", 1506 | "quote", 1507 | "syn 2.0.100", 1508 | ] 1509 | 1510 | [[package]] 1511 | name = "windows-link" 1512 | version = "0.1.1" 1513 | source = "registry+https://github.com/rust-lang/crates.io-index" 1514 | checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" 1515 | 1516 | [[package]] 1517 | name = "windows-result" 1518 | version = "0.3.2" 1519 | source = "registry+https://github.com/rust-lang/crates.io-index" 1520 | checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" 1521 | dependencies = [ 1522 | "windows-link", 1523 | ] 1524 | 1525 | [[package]] 1526 | name = "windows-strings" 1527 | version = "0.4.0" 1528 | source = "registry+https://github.com/rust-lang/crates.io-index" 1529 | checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" 1530 | dependencies = [ 1531 | "windows-link", 1532 | ] 1533 | 1534 | [[package]] 1535 | name = "windows-sys" 1536 | version = "0.52.0" 1537 | source = "registry+https://github.com/rust-lang/crates.io-index" 1538 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1539 | dependencies = [ 1540 | "windows-targets", 1541 | ] 1542 | 1543 | [[package]] 1544 | name = "windows-targets" 1545 | version = "0.52.6" 1546 | source = "registry+https://github.com/rust-lang/crates.io-index" 1547 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1548 | dependencies = [ 1549 | "windows_aarch64_gnullvm", 1550 | "windows_aarch64_msvc", 1551 | "windows_i686_gnu", 1552 | "windows_i686_gnullvm", 1553 | "windows_i686_msvc", 1554 | "windows_x86_64_gnu", 1555 | "windows_x86_64_gnullvm", 1556 | "windows_x86_64_msvc", 1557 | ] 1558 | 1559 | [[package]] 1560 | name = "windows_aarch64_gnullvm" 1561 | version = "0.52.6" 1562 | source = "registry+https://github.com/rust-lang/crates.io-index" 1563 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1564 | 1565 | [[package]] 1566 | name = "windows_aarch64_msvc" 1567 | version = "0.52.6" 1568 | source = "registry+https://github.com/rust-lang/crates.io-index" 1569 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1570 | 1571 | [[package]] 1572 | name = "windows_i686_gnu" 1573 | version = "0.52.6" 1574 | source = "registry+https://github.com/rust-lang/crates.io-index" 1575 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1576 | 1577 | [[package]] 1578 | name = "windows_i686_gnullvm" 1579 | version = "0.52.6" 1580 | source = "registry+https://github.com/rust-lang/crates.io-index" 1581 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1582 | 1583 | [[package]] 1584 | name = "windows_i686_msvc" 1585 | version = "0.52.6" 1586 | source = "registry+https://github.com/rust-lang/crates.io-index" 1587 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1588 | 1589 | [[package]] 1590 | name = "windows_x86_64_gnu" 1591 | version = "0.52.6" 1592 | source = "registry+https://github.com/rust-lang/crates.io-index" 1593 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1594 | 1595 | [[package]] 1596 | name = "windows_x86_64_gnullvm" 1597 | version = "0.52.6" 1598 | source = "registry+https://github.com/rust-lang/crates.io-index" 1599 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1600 | 1601 | [[package]] 1602 | name = "windows_x86_64_msvc" 1603 | version = "0.52.6" 1604 | source = "registry+https://github.com/rust-lang/crates.io-index" 1605 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1606 | 1607 | [[package]] 1608 | name = "winnow" 1609 | version = "0.7.6" 1610 | source = "registry+https://github.com/rust-lang/crates.io-index" 1611 | checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" 1612 | dependencies = [ 1613 | "memchr", 1614 | ] 1615 | 1616 | [[package]] 1617 | name = "xxhash-rust" 1618 | version = "0.8.15" 1619 | source = "registry+https://github.com/rust-lang/crates.io-index" 1620 | checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" 1621 | 1622 | [[package]] 1623 | name = "zerocopy" 1624 | version = "0.7.35" 1625 | source = "registry+https://github.com/rust-lang/crates.io-index" 1626 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 1627 | dependencies = [ 1628 | "zerocopy-derive", 1629 | ] 1630 | 1631 | [[package]] 1632 | name = "zerocopy-derive" 1633 | version = "0.7.35" 1634 | source = "registry+https://github.com/rust-lang/crates.io-index" 1635 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 1636 | dependencies = [ 1637 | "proc-macro2", 1638 | "quote", 1639 | "syn 2.0.100", 1640 | ] 1641 | --------------------------------------------------------------------------------