From a2f1b72204b57ba6336bd5c59dc52b5b49a66662 Mon Sep 17 00:00:00 2001 From: Yiffy Dev Date: Wed, 30 Oct 2024 10:59:43 +0500 Subject: [PATCH] initial os release. I really expect SO much bugs, guys. good luck =) --- .gitignore | 4 + Cargo.lock | 1476 ++++++++++++++++++++ Cargo.toml | 80 ++ LICENSE | 0 README.md | 589 ++++++++ examples/define-styles/Cargo.lock | 1483 ++++++++++++++++++++ examples/define-styles/Cargo.toml | 9 + examples/define-styles/src/lib.rs | 104 ++ examples/leptos-axum/.gitignore | 14 + examples/leptos-axum/Cargo.toml | 67 + examples/leptos-axum/LICENSE | 24 + examples/leptos-axum/README.md | 90 ++ examples/leptos-axum/build.rs | 11 + examples/leptos-axum/public/favicon.ico | Bin 0 -> 15406 bytes examples/leptos-axum/src/lib.rs | 10 + examples/leptos-axum/src/main.rs | 38 + examples/leptos-axum/src/routes/home.rs | 33 + examples/leptos-axum/src/routes/home.scss | 12 + examples/leptos-axum/src/routes/mod.rs | 1 + examples/leptos-axum/src/shell.rs | 43 + examples/use-styles/Cargo.lock | 1491 +++++++++++++++++++++ examples/use-styles/Cargo.toml | 24 + examples/use-styles/assets/prelude.css | 4 + examples/use-styles/build.rs | 22 + examples/use-styles/src/main.rs | 17 + examples/use-styles/src/main.sass | 12 + sabry_build/Cargo.toml | 28 + sabry_build/src/buildmagic.rs | 305 +++++ sabry_build/src/filevisit.rs | 51 + sabry_build/src/lib.rs | 3 + sabry_intrnl/Cargo.toml | 28 + sabry_intrnl/src/compiler/mod.rs | 120 ++ sabry_intrnl/src/config/manifest.rs | 44 + sabry_intrnl/src/config/mod.rs | 253 ++++ sabry_intrnl/src/lib.rs | 4 + sabry_intrnl/src/scoper/hash.rs | 97 ++ sabry_intrnl/src/scoper/mod.rs | 423 ++++++ sabry_intrnl/src/syntax/mod.rs | 226 ++++ sabry_procmacro/Cargo.toml | 22 + sabry_procmacro/src/lib.rs | 117 ++ sabry_procmacro_impl/Cargo.toml | 26 + sabry_procmacro_impl/src/impls/mod.rs | 202 +++ sabry_procmacro_impl/src/impls/sassy.rs | 68 + sabry_procmacro_impl/src/impls/styly.rs | 209 +++ sabry_procmacro_impl/src/impls/usey.rs | 71 + sabry_procmacro_impl/src/lib.rs | 4 + src/lib.rs | 6 + 47 files changed, 7965 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 examples/define-styles/Cargo.lock create mode 100644 examples/define-styles/Cargo.toml create mode 100644 examples/define-styles/src/lib.rs create mode 100644 examples/leptos-axum/.gitignore create mode 100644 examples/leptos-axum/Cargo.toml create mode 100644 examples/leptos-axum/LICENSE create mode 100644 examples/leptos-axum/README.md create mode 100644 examples/leptos-axum/build.rs create mode 100644 examples/leptos-axum/public/favicon.ico create mode 100644 examples/leptos-axum/src/lib.rs create mode 100644 examples/leptos-axum/src/main.rs create mode 100644 examples/leptos-axum/src/routes/home.rs create mode 100644 examples/leptos-axum/src/routes/home.scss create mode 100644 examples/leptos-axum/src/routes/mod.rs create mode 100644 examples/leptos-axum/src/shell.rs create mode 100644 examples/use-styles/Cargo.lock create mode 100644 examples/use-styles/Cargo.toml create mode 100644 examples/use-styles/assets/prelude.css create mode 100644 examples/use-styles/build.rs create mode 100644 examples/use-styles/src/main.rs create mode 100644 examples/use-styles/src/main.sass create mode 100644 sabry_build/Cargo.toml create mode 100644 sabry_build/src/buildmagic.rs create mode 100644 sabry_build/src/filevisit.rs create mode 100644 sabry_build/src/lib.rs create mode 100644 sabry_intrnl/Cargo.toml create mode 100644 sabry_intrnl/src/compiler/mod.rs create mode 100644 sabry_intrnl/src/config/manifest.rs create mode 100644 sabry_intrnl/src/config/mod.rs create mode 100644 sabry_intrnl/src/lib.rs create mode 100644 sabry_intrnl/src/scoper/hash.rs create mode 100644 sabry_intrnl/src/scoper/mod.rs create mode 100644 sabry_intrnl/src/syntax/mod.rs create mode 100644 sabry_procmacro/Cargo.toml create mode 100644 sabry_procmacro/src/lib.rs create mode 100644 sabry_procmacro_impl/Cargo.toml create mode 100644 sabry_procmacro_impl/src/impls/mod.rs create mode 100644 sabry_procmacro_impl/src/impls/sassy.rs create mode 100644 sabry_procmacro_impl/src/impls/styly.rs create mode 100644 sabry_procmacro_impl/src/impls/usey.rs create mode 100644 sabry_procmacro_impl/src/lib.rs create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f276f31 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +**/target +rust-toolchain.toml +.vscode +.profile diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..80d7a63 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1476 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "anstream" +version = "0.6.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64-simd" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "781dd20c3aff0bd194fe7d2a977dd92f21c173891f3a03b677359e5fa457e5d5" +dependencies = [ + "simd-abstraction", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake3" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" + +[[package]] +name = "cc" +version = "1.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "codemap" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e769b5c8c8283982a987c6e948e540254f1058d5a74b8794914d4ef5fc2a24" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "const-str" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21077772762a1002bb421c3af42ac1725fa56066bfc53d9a55bb79905df2aaf3" +dependencies = [ + "const-str-proc-macro", +] + +[[package]] +name = "const-str-proc-macro" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1e0fdd2e5d3041e530e1b21158aeeef8b5d0e306bc5c1e3d6cf0930d10e25a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "const_format" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "cssparser" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be934d936a0fbed5bcdc01042b770de1398bf79d0e192f49fa7faea0e99281e" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf 0.11.2", + "smallvec", +] + +[[package]] +name = "cssparser-color" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556c099a61d85989d7af52b692e35a8d68a57e7df8c6d07563dc0778b3960c9f" +dependencies = [ + "cssparser", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.85", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "data-url" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a30bfce702bcfa94e906ef82421f2c0e61c076ad76030c16ee5d2e9a32fe193" +dependencies = [ + "matches", +] + +[[package]] +name = "dtoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "grass" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7a68216437ef68f0738e48d6c7bb9e6e6a92237e001b03d838314b068f33c94" +dependencies = [ + "clap", + "getrandom", + "grass_compiler", +] + +[[package]] +name = "grass_compiler" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d9e3df7f0222ce5184154973d247c591d9aadc28ce7a73c6cd31100c9facff6" +dependencies = [ + "codemap", + "indexmap", + "lasso", + "once_cell", + "phf 0.11.2", + "rand", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash 0.8.11", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.0", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lasso" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e14eda50a3494b3bf7b9ce51c52434a761e383d7238ce1dd5dcec2fbc13e9fb" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "lightningcss" +version = "1.0.0-alpha.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e225b3fa0a8bd5562c8833b1a32afa88761c4e661d3177b8cdc4e13cbf078e" +dependencies = [ + "ahash 0.8.11", + "bitflags", + "const-str", + "cssparser", + "cssparser-color", + "dashmap", + "data-encoding", + "getrandom", + "itertools", + "lazy_static", + "lightningcss-derive", + "parcel_selectors", + "parcel_sourcemap", + "paste", + "pathdiff", + "rayon", + "serde", + "smallvec", +] + +[[package]] +name = "lightningcss-derive" +version = "1.0.0-alpha.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12744d1279367caed41739ef094c325d53fb0ffcd4f9b84a368796f870252" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "outref" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4" + +[[package]] +name = "parcel_selectors" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4d26c18a8377a64728c04bf3b2e48ec43b0c77e687a18e03eb837d65e08a14" +dependencies = [ + "bitflags", + "cssparser", + "fxhash", + "log", + "phf 0.10.1", + "phf_codegen", + "precomputed-hash", + "smallvec", +] + +[[package]] +name = "parcel_sourcemap" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "485b74d7218068b2b7c0e3ff12fbc61ae11d57cb5d8224f525bd304c6be05bbb" +dependencies = [ + "base64-simd", + "data-url", + "rkyv", + "serde", + "serde_json", + "vlq", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pathdiff" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" + +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_shared 0.10.0", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator 0.11.2", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.85", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "raffia" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c36f58fa7ad2f26bca656054c902becddeac5582df2bb31d4b4d2a148c62cfd5" +dependencies = [ + "raffia_macro", + "smallvec", +] + +[[package]] +name = "raffia_macro" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fdb50eb5bf734fa5a770680a61876a6ec77b99c1e0e52d1f18ad6ebfa85759f" +dependencies = [ + "heck", + "quote", + "syn 2.0.85", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "rkyv" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "sabry" +version = "0.0.1" +dependencies = [ + "sabry_build", + "sabry_intrnl", + "sabry_procmacro", +] + +[[package]] +name = "sabry_build" +version = "0.0.1" +dependencies = [ + "proc-macro2", + "sabry_intrnl", + "sabry_procmacro_impl", + "syn 2.0.85", + "thiserror", + "walkdir", +] + +[[package]] +name = "sabry_intrnl" +version = "0.0.1" +dependencies = [ + "base64", + "blake3", + "const_format", + "grass", + "lightningcss", + "proc-macro2", + "raffia", + "regex", + "serde", + "syn 2.0.85", + "thiserror", + "toml", +] + +[[package]] +name = "sabry_procmacro" +version = "0.0.1" +dependencies = [ + "sabry_procmacro_impl", +] + +[[package]] +name = "sabry_procmacro_impl" +version = "0.0.1" +dependencies = [ + "proc-macro2", + "quote", + "raffia", + "regex", + "sabry_intrnl", + "syn 2.0.85", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "serde" +version = "1.0.213" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.213" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", +] + +[[package]] +name = "serde_json" +version = "1.0.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-abstraction" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cadb29c57caadc51ff8346233b5cec1d240b68ce55cf1afc764818791876987" +dependencies = [ + "outref", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vlq" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65dd7eed29412da847b0f78bcec0ac98588165988a8cfe41d4ea1d429f8ccfff" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.85", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..c31dc20 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,80 @@ +[workspace] +resolver = "2" +members = [ + "sabry_procmacro", + "sabry_procmacro_impl", + "sabry_intrnl", +] +exclude = [ + "examples" +] + +[workspace.dependencies] +sabry_intrnl = {path = "sabry_intrnl", version = "0.0.1"} +sabry_procmacro = {path = "sabry_procmacro", version = "0.0.1"} +sabry_procmacro_impl = {path = "sabry_procmacro_impl", version = "0.0.1"} +sabry_build = {path = "sabry_build", version = "0.0.1"} + +syn = {version = "^2.0"} +quote = {version = "^1.0"} +proc-macro2 = {version = "^1.0"} +raffia = {version = "^0.9"} +regex = {version = "^1.11"} +grass = {version = "^0.13"} +lightningcss = {version = "1.0.0-alpha.59"} +blake3 = {version = "^1.5"} +base64 = {version = "^0.22"} +const_format = {version = "^0.2"} + +thiserror = {version = "^1.0"} +serde = {version = "^1.0"} +toml = {version = "^0.8"} + + +[workspace.package] +version = "0.0.1" +edition = "2021" +rust-version = "1.82" +authors = ["Svyatoslav Pushkarev "] +license = "MIT" +publish = true + +[package] +name = "sabry" +description = "Syntactically Awesome But RustY - crate that brings SCSS/SASS into rust." +keywords = ["web", "sass", "scss", "macro"] +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +publish.workspace = true + +[dependencies] +sabry_procmacro = {workspace = true, optional = true} +sabry_build = {workspace = true, optional = true} +sabry_intrnl = {workspace = true} + +[features] +default = ["scss"] +procmacro = [ + "dep:sabry_procmacro" +] +sass = [ + "procmacro", + "sabry_procmacro/sass", + "sabry_intrnl/sass", + "sabry_build/sass" +] +scss = [ + "procmacro", + "sabry_procmacro/scss", + "sabry_intrnl/scss", + "sabry_build/scss" +] +build = [ + "dep:sabry_build" +] +net-files = [ + "sabry_build/net-files" +] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000..e969449 --- /dev/null +++ b/README.md @@ -0,0 +1,589 @@ +# 🧙🏻 SABRY - Syntactically Awesome, But RustY + +**Y**et another **R**usty **B**oilerplate-free **A**gnostic **S**tyling crate, which brings your SASS/SCSS style into Rust. Written by a fox this time. + +\* sabry isn't "syntactically awesome", it refers to SASS abbr expansion. + +> **Project status** - early, good enough for my team's non-critical "for-fun" pre-production, on demand. WIP features have no ETA. I'm pretty happy with ergonomics and taste of the crate, and I'll do my best to keep DX the way it is between minor versions - but there's no guarantee on backwards-compatibility and no refunds if something breaks. +> +> "master" branch is what's currently on crates.io +> +> each version ever been on crates.io (except the latest release) is available in "r_x.x.x" branch +> +> the latest-trashy state is in the "window" branch + +At first, I'll show how this crate "tastes". With SABRY, its in your power to: + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +Write arbitrary SASS/SCSS code and ship it *as a crate* however you please: with modules, with feature flags, etc. Say "bye" to manual copying, cli-tools and consts. + +```rust +sassy!(tokens {@mixin colored{color: red;}}); +``` + + +📦 +
+ +Code your SASS in separate files to get proper syntax highlighting, or do sass-in-the-rust to keep things in one place + +```rust +styly!(component {.btn {color: green;}}); +styly!(extras "src/components/extras.scss"); +``` + + +:3 +
+ +Depend on styles with cargo, at build time, which brings all the rusty sweeties in: versions, updates, cratesio, local registries, workspaces, etc. + +```toml +[build-dependencies] +tgk_brandstyle = {version = "0.0.1", features = ["utils"]} +``` + + +🦀 +
+ +`@use` your style-crates in sass code *naturally* + +```rust +styly!(breadcumb { + @use 'tokens'; + .scope {@include tokens.badge(primary);} +}) +``` + + +🪄 +
+ +Keep things as private and modular as you wish + +```rust +styly!(pub cats "src/sections/cats/style.scss"); +styly!(dogs {#howl {border: none;}}) + +/// something like render function +{ +
+
    +
    +} +``` + +
    +^_^ +
    + +Compile all the sweet SASS/SCSS into the optimized CSS bundle, ship it in CSS shunks or even include the compiled style into the binary + +```rust +styly!(cssbundle {.c1 {color: white;}}) +styly!(const binary {.c2 {color: black;}}) +``` + + +🏗️ +
    + +Sabry will gladly: + +- scope and hash your styles, so they won't conflict, with amazing [raffia](https://crates.io/crates/raffia) parser +- compile SASS/SCSS into CSS with [grass](https://crates.io/crates/grass) +- optimize produced CSS with [lightningcss](https://crates.io/crates/lightningcss) +- prepare ready CSS bundle and put it wherever you wish +- include CSS into the build artifact - if you really want it + +Also, just about everything is pub-available in this crate - Sabry is ready for experiments. + + +## Usage + +Feel free to check out examples: + +|[crate of styles](./examples//define-styles/)|[style usage](./examples/use-styles/)|[leptox-axum with sabry](./examples/leptos-axum)| +|-|-|-| + +### Create a crate full of arbitrary SASS + +The only need is the dependency + +```toml +#Cargo.toml + +[dependencies] +sabry = {version = "0.0.1"} +``` +And a proc-macro +```rust +// lib.rs +use sabry::sassy; + +sassy!(mixins "assets/mixins.scss"); +sassy!(styles { + $primary-color: black; + @mixin colored($col: primary) { + @if $col == primary { + color: $primary-color; + } @else { + color: $col; + } + } +}); +``` +Now you can build and see two ready for export macros: `mixins!` and `styles!`. +These are usefull on their own, as invocation of `mixins!()` or `styles!()` - both shall give you the code literal. + +However there's more sweet use case for them, which is covered below. + +### Write scoped styles + +Depend on sabry +```toml +# Cargo.toml + +[dependencies] +sabry = {version = "0.0.1"} +``` +And create a style scope wherever you want: +```rust +// breadcumblist.rs +use sabry::styly; + +styly!(const styles { + .cumbs { + display: flex; + &__list { + display: flex; + } + } + #wolf { + color: white; + } +}); + +fn render() -> HtmlElement { + div().class(styles::cumbs).chain( + ul().class(styles::_list(styles::cumbs)) + ).chain( + span().id(styles::thewolf) + ) +} +``` +> That `const` usage is covered in the [following](#constant-styly-scopes) section. In this example we dont invoke sabry build-magic, so, to be as close to real life as possible, I used a const. + +Every selector, if that does make sense, now available for you as a member of `styles` scope. In this example - `styles::cumbs`, `styles::thewolf` and `styles::_list()`. More about scoping and member names you can read [here](#styly-scopes). + +### Use styles earlier created in another crate + +The combination of previous two, with some additional work to do and some extra sugar to enjoy. + +Sabry is needed as both dependency and build-dependency. +To be able to compile all styles sabry also needs the *build* feature flag: +```toml +# Cargo.toml + +[dependencies] +sabry = {version = "0.0.1"} + +[build-dependencies] +sabry = {version = "0.0.1", features = ["build"]} +``` +> If you do use some non-default feature flags make sure to keep them in sync between sabry-dependency and sabry-build-dependency. + +Then you have to tell sabry when code should be compiled. We'll do this in *build.rs* file. +```rust +// build.rs +use shared_styles::{mixins, styles}; + +fn main(){ + sabry::buildy( + sabry::usey!( + mixins!(), + styles!() + ) + ).expect("Failed to build sabry styles"); +} +``` +`buildy` is the entry function of sabry build-time process. The handy `usey!` macro will do just proper handling of our style-macros for it. + +Now lets get back to the code and use the mixin defined in another crate: +```rust +// breadcumblist.rs +use sabry::styly; + +styly!(styles { + @use "mixins"; + .cumbs { + display: flex; + &__list { + display: flex; + } + } + #wolf { + @include mixins.colored(white); + } +}); + +fn render() -> HtmlElement { + div().class(styles::cumbs).chain( + ul().class(styles::_list(styles::cumbs)) + ).chain( + span().id(styles::thewolf) + ) +} +``` +So the `mixins!` macro we just passed to the `usey!` macro inside of `buildy` function call is now accessible with simple and natural `@use "mixins"` SASS rule! + +## Configuration + +Sabry configuration lives in `[package.metadata.sabry]` table of the manifest file. + +All configurations are optional, but with default configuration sabry won't produce any CSS files. + +Full example, close to defaults: +```toml +# Cargo.toml + +[package.metadata.sabry] +css.bundle = "target/static/style.css" +css.bundle_prelude = ["assets/prelude.css"] +css.scopes = "target/statis/scopes/" +css.minify = true + +sass.intermediate_dir = "target/.sabry/sass" +sass.module_name_collision = "merge" +sass.modules = ["assets/sass/mod1.scss"] +sass.scanroot = "src" + +hash.size = 6 +hash.collision = "error" +hash.use_scope_name = true +hash.use_code_size = true +hash.use_item_names = false +hash.use_code_text = false + +[package.metadata.sabry.lightningcss.targets] +chrome = "120" +safari = "13.2" +ie = "6" +``` + +### `sabry.css` + +**bundle** *(no default)* - file path ro write CSS bundle into relative to project root + +**bundle_prelude** *(no default)* - collection of CSS files, relative to the project root, which content will be inserted before the compiled style into the *bundle* file if any + +**scopes** *(no default)* - dir path to put separate CSS for every scope into relative to project root + +**minify** *(default true)* - print compressed CSS output and do the lightningcss thing + +### `sabry.sass` + +**intermediate_dir** *(default "target/.sabry/sass")* - file to put SASS/SCSS modules into so they are available with `@use` in code + +**scanroot** *(default "src")* - root directory to start scanning "rs" files from. Used in build function + +**modules** *(no default)* - collection of SASS/SCSS files, relative to the project root, which should be available as modules as well + +**module_name_collision** *(default "merge")* - how to handle similary named modules. + +*merge* - merge content + +*error* - break building process with an error + +### `sabry.hash` + +**size** *(default 6)* - size of hash in bytes. Feel free to increase/decrease. + +**use_scope_name** *(default true)* - wether to use scope identifier to calculate hash + +**use_code_size** *(default true)* - wether to use scope code size to calculate hash + +**use_item_names** *(default false)* - wether to use all scoped item idents to calculate hash + +**use_code_text** *(default false)* - wether to use the scope code text to calculate hash + +**collision** *(default "ignore")* - how to handle similarity of generated hashes + +*ignore* - dont do anything + +*error* - break building process with an error + +### `sabry.lightningcss.targets` + +Does require `css.minify` to be *true*. + +Empty by default. + +Available keys: chrome, firefox, edge, safari, saf_ios, samsung, android, ie + +Value - minimal browser version to support in "M.m.p" format, where: + +- *M* - major +- *m* - minor +- *p* - patch + +For example `{ie = "9", saf_ios = "13.2"}` will try to generate CSS supported on both IE 9 and Safari-on-ios 13.2 + +## Detailed guide + +### Style definition with `sassy!` + +The `sassy!` macro is available with *procmacro* feature which is enabled by default. + +It does accept the following syntax: `$name(:$syntax)? ({ $code })|($filename)`, where + +- *$name* is any identifier valid for `macro_rules!` +- *$syntax* is either `sass` or `scss` +- *$code* is valid arbitrary style code in specified syntax +- *$filename* is a string literal which contains path to the file relative to package root + +Examples: +```rust +sassy!(module1 {$primary-color: red;}); +sassy!(module2 "src/assets/module2.scss"); +sassy!(module3:sass "src/assets/module3.sass"); +// works, but there are catches. +sassy!(module4:sass { + =colored + color: red +}); +``` + +You may omit the syntax specifier - sabry uses SCSS as the default one. + +The given code to `sassy!` is not checked to be valid code in given syntax (wip). + +> SASS support inside of rust files is experimental. If you do want to use SASS tabbed syntax - consider to use files path instead of sass-in-rust option. + +### Scoping with `styly!` + +The `styly!` macro is available with *procmacro* feature flag which is enabled by default. + +It does accept the following syntax: `pub? const? $ident(:$syntax)? ({ $code })|($filename)`, where + +- *pub* is explained [here](#public-styly-scopes) +- *const* is explained [here](#constant-styly-scopes) +- *$ident* is any identifier valid for `mod` +- *$syntax* is either `sass` or `scss` +- *$code* is arbitrary style code valid with given syntax +- *$filename* is a string literal which contains path to the file relative to package root + +Examples +```rust +styly!(fox {.fur {color: red; &-dark {color: black;}}}) +styly!(pub fox {.fur {color: red; &-dark {color: black;}}}) +styly!(pub const fox:sass { + .fur + color: red + &-dark + color: black +}) +``` +Every of those calls will produce the styling scope as a module. Differences are explained right below. + +In general the scope does look like this: +```rust +const FOX: &str = "J9k_s9"; +mod fox { + pub const fur: &str = "J9k_s9 fur"; + pub fn _dark(c: &str) -> String {format!("{c}-dark")} +} +``` + +#### Styly scopes + +Styly macro itself does not generate the scope. It is done in the `sabry_intrnl::scoper`. However, as a result, you will have the following: + +- `const` with the UPPER_CASE name of the scope, which contains its hash +- `mod` with exact scope name which is the scope you're going to use + - for simple selectors, like `.fur` you will have a const members with hashed original selectors to use wherever you need a class/id/etc. + - for parent-selectors like `&-dark` you will have a non-const function, which will create matching the selector from any other. + +You can read more about scoping and hashing in the [scoping](#scoping) section. + +#### Public styly scopes + +By default generated `mod` is private. You can make both mod and wrapper style constant public by adding the `pub` to macro call: + +```rust +styly!(pub whatever "src/assets/whatever.scss"); +``` + +#### Constant styly scopes + +As you've seen above, scope doe not contain any style code by itself. That's the use case i advise mostly. + +However you could still compile styles into the artifact by simply adding the `const` to the macro call: + +```rust +styly!(const scope "src/assets/scope.scss"); +``` +Which results in following: +```rust +const SCOPE: &str = /* scope hash */; +const SCOPE_CSS: &str = /* compiled from src/assets/scope.scss */; +mod scope {/* selector collection */} +``` + +> **There is a catch** | with the `const` modifier macro must compile CSS at compile-time. That results in several game changers: +> +> *First*. You could avoid the "build magic". Sabry will just compile given styles with procmacro at compile time. +> +> *Second*. If you `@use` something inside of constant-flavored scope, you can only success if sabry *did the build magic before compilation of that macro call*. So you still can compile the styles into the artifact and enjoy mixins from other crates, but, in general, you are going to receive some false-positives from editor. +> +> Worth of notice: sabry will still include const-flavored styles into the CSS bundle during build time. + +### Building with `buildy` and `usey!` + +The `buildy` function is available with *build* feature which needs to be enabled explicitly. + +This function accepts an iterator of pairs: (file_name, code) in form of `(String, String)` type. File name should have an extension, so grass can infere syntax during CSS compilation. + +Each of those pairs is processed as a file which sabry needs to write into +the configured `intermediate_dir` and then passed into the CSS compiler. + +You could, for example, define the module "mixin_a": +```rust +buildy(vec![("mixin_a".to_string(), "@mixin a(){}".to_string())]); +``` + +However there's a usey macro, which handles this for you: +```rust +buildy( + usey!(mixins!(), utils!()) +); +``` + +The `usey!` macro accepts the following syntax: +`#($macro,)*`, where + +- *$macro* is a macro which handles three expansions: + - `() => { $code }` + - `(name) => { $name }` + - `(syntax) => { $syntax }` + +Where for the *$macro*: + +- *$code* is a source code of style as a string literal +- *$name* is a name of module without extension as a string literal +- *$syntax* is either "sass" or "scss" + + +Exactly this kind of macros is produced by [`sassy!`](#style-definition-with-sassy). + +### Scoping + +Sabry handles scoping by restriction or mutation of existing selectors +with the hash. Hash is calculated for the entire scope by the [`styly!`](#scoping-with-styly) macro. + +Currently the following types of selectors are scoped: + +- class +- id +- SASS parent selectors (see below, there is a catch) +- tagname (see below, there is a catch) + +Sabry does not make difference between top-level and nested selectors, +also selector complexity isn't taken into account: sabry simply walks through all compound selectors +and apply scoping for supported ones. + +Different selector types are scoped differently: + +- class selectors are restricted with scope hash: `.class` -> `.HASH.class` +- id selector are mutated with scope hash: `#id` -> `#id-HASH` +- tagname selectors are changed into indirect descendance: `div` -> `.HASH div` + +> **There is a catch** | currently tagname selectors are scoped with indirect descendancy +> hash restriction. That means - if you do use tagnames in scoped stylesheets, you have to wrap your markdown +> with `SCOPE` class generated by `styly!` macro. +> +> Also if there are nested tagname selectors - sabry won't take this into account and you'll +> have to wrap them with `SCOPE` class as well + +As for **SASS parent selectors**: they are currently handled in different way. Instead of +walking up the syntax tree sabry just creates function member for the scope and leave the rest to grass: + +```rust +styly!(scope { + .cls1 { + &-dark {} + } +}); +``` +is something like +```rust +const SCOPE: &str = "Ut8CskJ"; +mod scope { + pub const cls1: &str = "Ut8CskJ cls1"; + pub fn _dark(c: &str) -> String {format!("{c}-dark")} +} +``` + +So you still can get the scoped variant of `cls1-dark` class: `scope::_dark(scope::cls1)`. + +This isn't very handy, also isn't strict enough, and is a high-priority subject to change. wip. + +## WIP + +*(sorted by my own priority)*, "dones" are excluded + +- [] Crates of styled components - currently the only way to create them seems to be const styly. + - [] CSS support +- [] There are some strange parsing errors, seems like a bug, however very hard to reproduce. Have to investigate. Maybe do more tests. +- [] Experience with cargo-leptos is fine, and we do use it, however its a bit "raughy". Need to do something about it. + +## Contributions + +Any contributions are always welcome! + +If you find this crate usefull, wanna stick with it in some project, but do miss some +features - feel free to submit a PR. + +> If you'd like to fork for the PR - please, use the "window" branch, not the "master". + +If you encounter any bugs/problems or have use case where things dont work as they should +for the latest version - please, open an issue! + +If you'd like to lend a paw - feel free to check the [WIP](#wip) section out, or to search for "TODO" comments. + +## MSRV + +Sabry passes its own tests on 1.82 nightly. + +There *were* some strange parsing issues reports on *stable* channel, seems to be fixed. idk. + +## License + +MIT. diff --git a/examples/define-styles/Cargo.lock b/examples/define-styles/Cargo.lock new file mode 100644 index 0000000..963559d --- /dev/null +++ b/examples/define-styles/Cargo.lock @@ -0,0 +1,1483 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "anstream" +version = "0.6.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64-simd" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "781dd20c3aff0bd194fe7d2a977dd92f21c173891f3a03b677359e5fa457e5d5" +dependencies = [ + "simd-abstraction", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake3" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" + +[[package]] +name = "cc" +version = "1.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "codemap" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e769b5c8c8283982a987c6e948e540254f1058d5a74b8794914d4ef5fc2a24" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "const-str" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21077772762a1002bb421c3af42ac1725fa56066bfc53d9a55bb79905df2aaf3" +dependencies = [ + "const-str-proc-macro", +] + +[[package]] +name = "const-str-proc-macro" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1e0fdd2e5d3041e530e1b21158aeeef8b5d0e306bc5c1e3d6cf0930d10e25a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "const_format" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "cssparser" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be934d936a0fbed5bcdc01042b770de1398bf79d0e192f49fa7faea0e99281e" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf 0.11.2", + "smallvec", +] + +[[package]] +name = "cssparser-color" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556c099a61d85989d7af52b692e35a8d68a57e7df8c6d07563dc0778b3960c9f" +dependencies = [ + "cssparser", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.85", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "data-url" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a30bfce702bcfa94e906ef82421f2c0e61c076ad76030c16ee5d2e9a32fe193" +dependencies = [ + "matches", +] + +[[package]] +name = "define-styles" +version = "0.0.0" +dependencies = [ + "sabry", +] + +[[package]] +name = "dtoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "grass" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7a68216437ef68f0738e48d6c7bb9e6e6a92237e001b03d838314b068f33c94" +dependencies = [ + "clap", + "getrandom", + "grass_compiler", +] + +[[package]] +name = "grass_compiler" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d9e3df7f0222ce5184154973d247c591d9aadc28ce7a73c6cd31100c9facff6" +dependencies = [ + "codemap", + "indexmap", + "lasso", + "once_cell", + "phf 0.11.2", + "rand", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash 0.8.11", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.0", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lasso" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e14eda50a3494b3bf7b9ce51c52434a761e383d7238ce1dd5dcec2fbc13e9fb" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "lightningcss" +version = "1.0.0-alpha.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e225b3fa0a8bd5562c8833b1a32afa88761c4e661d3177b8cdc4e13cbf078e" +dependencies = [ + "ahash 0.8.11", + "bitflags", + "const-str", + "cssparser", + "cssparser-color", + "dashmap", + "data-encoding", + "getrandom", + "itertools", + "lazy_static", + "lightningcss-derive", + "parcel_selectors", + "parcel_sourcemap", + "paste", + "pathdiff", + "rayon", + "serde", + "smallvec", +] + +[[package]] +name = "lightningcss-derive" +version = "1.0.0-alpha.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12744d1279367caed41739ef094c325d53fb0ffcd4f9b84a368796f870252" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "outref" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4" + +[[package]] +name = "parcel_selectors" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4d26c18a8377a64728c04bf3b2e48ec43b0c77e687a18e03eb837d65e08a14" +dependencies = [ + "bitflags", + "cssparser", + "fxhash", + "log", + "phf 0.10.1", + "phf_codegen", + "precomputed-hash", + "smallvec", +] + +[[package]] +name = "parcel_sourcemap" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "485b74d7218068b2b7c0e3ff12fbc61ae11d57cb5d8224f525bd304c6be05bbb" +dependencies = [ + "base64-simd", + "data-url", + "rkyv", + "serde", + "serde_json", + "vlq", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pathdiff" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" + +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_shared 0.10.0", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator 0.11.2", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.85", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "raffia" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c36f58fa7ad2f26bca656054c902becddeac5582df2bb31d4b4d2a148c62cfd5" +dependencies = [ + "raffia_macro", + "smallvec", +] + +[[package]] +name = "raffia_macro" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fdb50eb5bf734fa5a770680a61876a6ec77b99c1e0e52d1f18ad6ebfa85759f" +dependencies = [ + "heck", + "quote", + "syn 2.0.85", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "rkyv" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "sabry" +version = "0.0.1" +dependencies = [ + "sabry_build", + "sabry_intrnl", + "sabry_procmacro", +] + +[[package]] +name = "sabry_build" +version = "0.0.0" +dependencies = [ + "proc-macro2", + "sabry_intrnl", + "sabry_procmacro_impl", + "syn 2.0.85", + "thiserror", + "walkdir", +] + +[[package]] +name = "sabry_intrnl" +version = "0.0.0" +dependencies = [ + "base64", + "blake3", + "const_format", + "grass", + "lightningcss", + "proc-macro2", + "raffia", + "regex", + "serde", + "syn 2.0.85", + "thiserror", + "toml", +] + +[[package]] +name = "sabry_procmacro" +version = "0.0.0" +dependencies = [ + "sabry_procmacro_impl", +] + +[[package]] +name = "sabry_procmacro_impl" +version = "0.0.0" +dependencies = [ + "proc-macro2", + "quote", + "raffia", + "regex", + "sabry_intrnl", + "syn 2.0.85", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "serde" +version = "1.0.213" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.213" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", +] + +[[package]] +name = "serde_json" +version = "1.0.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-abstraction" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cadb29c57caadc51ff8346233b5cec1d240b68ce55cf1afc764818791876987" +dependencies = [ + "outref", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vlq" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65dd7eed29412da847b0f78bcec0ac98588165988a8cfe41d4ea1d429f8ccfff" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.85", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", +] diff --git a/examples/define-styles/Cargo.toml b/examples/define-styles/Cargo.toml new file mode 100644 index 0000000..496ecd3 --- /dev/null +++ b/examples/define-styles/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "define-styles" +version = "0.0.0" +edition = "2021" +rust-version = "1.82" +publish = false + +[dependencies] +sabry = {path = "../../", features = ["sass"]} diff --git a/examples/define-styles/src/lib.rs b/examples/define-styles/src/lib.rs new file mode 100644 index 0000000..bdf62c3 --- /dev/null +++ b/examples/define-styles/src/lib.rs @@ -0,0 +1,104 @@ +use sabry::sassy; + +sassy!(utils { + @mixin flex($direction, $align, $justify, $gap: .5rem) { + display: flex; + list-style: none; + gap: $gap; + flex-direction: $direction; + + @if $align == start{ + align-items: flex-start; + } + @else if $align == end{ + align-items: flex-end; + } + @else{ + align-items: $align; + } + + @if $justify == start { + justify-content: flex-start; + } + @else if $justify == end { + justify-content: flex-end; + } + @else { + justify-content: $justify; + } + } +}); + +sassy!(theme { + $thm-surface-primary: #2b2a29; + $thm-surface-secondary: #6C6C6C; + $thm-surface-tertiary: #4C4C4C; + $thm-surface-accent: #B0CB1F; + + $thm-text-primary: #ffffff; + $thm-text-secondary: #ffffff; + $thm-text-tertiary: #ffffff; + $thm-text-accent: #B0CB1F; + + @mixin surface($style: primary) { + @if $style == primary { + @include txt(primary); + background-color: $thm-surface-primary; + } + @else if $style == secondary { + @include txt(secondary); + background-color: $thm-surface-secondary; + } + @else if $style == accent { + @include txt; + background-color: $thm-surface-accent; + } + } + + @mixin txt($style: primary) { + @if $style == primary { + font-weight: 500; + color: $thm-text-primary; + } + @else if $style == secondary { + font-weight: 400; + color: $thm-text-secondary; + } + @else if $style == tertiary { + font-weight: 400; + color: $thm-text-tertiary; + } + @else if $style == accent { + font-weight: 500; + color: $thm-text-accent; + } + } +}); + +sassy!(tokens { + @use "theme"; + + @mixin clickable($style: accent, $scale: 1.2, $clickscale: 0.9){ + @if $style == accent{ + @include theme.surface(accent); + } + @else if $style == secondary { + @include theme.surface(secondary); + } + + cursor: pointer; + outline: none; + -webkit-tap-highlight-color: #00000000; + transition: transform .07s, filter .07s; + &:hover{ + transform: scale($scale); + } + &:focus-visible { + outline: 2px solid #fff; + } + &:active { + filter: brightness(.9); + transform: scale($clickscale); + } + } +}); diff --git a/examples/leptos-axum/.gitignore b/examples/leptos-axum/.gitignore new file mode 100644 index 0000000..6985cf1 --- /dev/null +++ b/examples/leptos-axum/.gitignore @@ -0,0 +1,14 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/examples/leptos-axum/Cargo.toml b/examples/leptos-axum/Cargo.toml new file mode 100644 index 0000000..7033f16 --- /dev/null +++ b/examples/leptos-axum/Cargo.toml @@ -0,0 +1,67 @@ +[package] +name = "leptos-axum-sabry" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +leptos = { version = "0.7.0-gamma3" } +leptos_axum = { version = "0.7.0-gamma3", optional = true } +leptos_meta = { version = "0.7.0-gamma3" } +leptos_router = { version = "0.7.0-gamma3" } +axum = { version = "0.7", optional = true } +console_error_panic_hook = "0.1" +tokio = { version = "1", features = ["rt-multi-thread"], optional = true } +tower = { version = "0.4", optional = true } +tower-http = { version = "0.5", features = ["fs"], optional = true } +wasm-bindgen = "=0.2.93" +thiserror = "1" +tracing = { version = "0.1", optional = true } +http = "1" + +# sabry with sass +sabry = {path = "../../", features = ["sass"]} + +[build-dependencies] +# sabry for build with sass +sabry = {path = "../../", features = ["build", "sass"]} +# lets depend on our styles +define-styles = {path = "../define-styles"} + +[features] +hydrate = ["leptos/hydrate"] +ssr = [ + "dep:axum", + "dep:tokio", + "dep:tower", + "dep:tower-http", + "dep:leptos_axum", + "leptos/ssr", + "leptos_meta/ssr", + "leptos_router/ssr", + "dep:tracing", +] + +[package.metadata.sabry] +css.minify = true +# We'll use bundle for leptos +css.bundle = "target/.sabry/target/bundle.css" + +[package.metadata.leptos] +output-name = "leptos-axum" +site-root = "target/site" +site-pkg-dir = "pkg" +# Sabry-generated bundle for leptos +style-file = "target/.sabry/target/bundle.css" +assets-dir = "public" +site-addr = "127.0.0.1:3000" +reload-port = 3001 +browserquery = "defaults" +env = "DEV" +bin-features = ["ssr"] +bin-default-features = false +lib-features = ["hydrate"] +lib-default-features = false diff --git a/examples/leptos-axum/LICENSE b/examples/leptos-axum/LICENSE new file mode 100644 index 0000000..fdddb29 --- /dev/null +++ b/examples/leptos-axum/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/examples/leptos-axum/README.md b/examples/leptos-axum/README.md new file mode 100644 index 0000000..e5d3c4a --- /dev/null +++ b/examples/leptos-axum/README.md @@ -0,0 +1,90 @@ + + + Leptos Logo + + +# Leptos Axum Starter Template + +This is a template for use with the [Leptos](https://github.com/leptos-rs/leptos) web framework and the [cargo-leptos](https://github.com/akesson/cargo-leptos) tool using [Axum](https://github.com/tokio-rs/axum). + +## Creating your template repo + +If you don't have `cargo-leptos` installed you can install it with + +```bash +cargo install cargo-leptos --locked +``` + +Then run +```bash +cargo leptos new --git https://github.com/leptos-rs/start-axum-0.7 +``` + +to generate a new project template. + +```bash +cd leptos-axum +``` + +to go to your newly created project. +Feel free to explore the project structure, but the best place to start with your application code is in `src/app.rs`. +Addtionally, Cargo.toml may need updating as new versions of the dependencies are released, especially if things are not working after a `cargo update`. + +## Running your project + +```bash +cargo leptos watch +``` + +## Installing Additional Tools + +By default, `cargo-leptos` uses `nightly` Rust, `cargo-generate`, and `sass`. If you run into any trouble, you may need to install one or more of these tools. + +1. `rustup toolchain install nightly --allow-downgrade` - make sure you have Rust nightly +2. `rustup target add wasm32-unknown-unknown` - add the ability to compile Rust to WebAssembly +3. `cargo install cargo-generate` - install `cargo-generate` binary (should be installed automatically in future) +4. `npm install -g sass` - install `dart-sass` (should be optional in future + +## Compiling for Release +```bash +cargo leptos build --release +``` + +Will generate your server binary in target/server/release and your site package in target/site + +## Testing Your Project +```bash +cargo leptos end-to-end +``` + +```bash +cargo leptos end-to-end --release +``` + +Cargo-leptos uses Playwright as the end-to-end test tool. +Tests are located in end2end/tests directory. + +## Executing a Server on a Remote Machine Without the Toolchain +After running a `cargo leptos build --release` the minimum files needed are: + +1. The server binary located in `target/server/release` +2. The `site` directory and all files within located in `target/site` + +Copy these files to your remote server. The directory structure should be: +```text +leptos-axum +site/ +``` +Set the following environment variables (updating for your project as needed): +```text +LEPTOS_OUTPUT_NAME="leptos-axum" +LEPTOS_SITE_ROOT="site" +LEPTOS_SITE_PKG_DIR="pkg" +LEPTOS_SITE_ADDR="127.0.0.1:3000" +LEPTOS_RELOAD_PORT="3001" +``` +Finally, run the server binary. + +## Licensing + +This template itself is released under the Unlicense. You should replace the LICENSE for your own application with an appropriate license if you plan to release it publicly. diff --git a/examples/leptos-axum/build.rs b/examples/leptos-axum/build.rs new file mode 100644 index 0000000..be74188 --- /dev/null +++ b/examples/leptos-axum/build.rs @@ -0,0 +1,11 @@ +use define_styles::{theme, utils, tokens}; + +fn main(){ + sabry::buildy( + sabry::usey!( + utils!(), + theme!(), + tokens!() + ) + ).expect("Failed to build with sabry"); +} diff --git a/examples/leptos-axum/public/favicon.ico b/examples/leptos-axum/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..2ba8527cb12f5f28f331b8d361eef560492d4c77 GIT binary patch literal 15406 zcmeHOd3aPs5`TblWD*3D%tXPJ#q(n!z$P=3gCjvf#a)E}a;Uf>h{pmVih!a-5LVO` zB?JrzEFicD0wRLo0iPfO372xnkvkzFlRHB)lcTnNZ}KK@US{UKN#b8?e_zkLy1RZ= zT~*y(-6IICgf>E_P6A)M3(wvl2qr-gx_5Ux-_uzT*6_Q&ee1v9B?vzS3&K5IhO2N5 z$9ukLN<`G>$$|GLnga~y%>f}*j%+w@(ixVUb^1_Gjoc;(?TrD3m2)RduFblVN)uy; zQAEd^T{5>-YYH%|Kv{V^cxHMBr1Ik7Frht$imC`rqx@5*| z+OqN!xAjqmaU=qR$uGDMa7p!W9oZ+64($4xDk^FyFQ<_9Z`(;DLnB<;LLJD1<&vnZ zo0(>zIkQTse}qNMb6+i`th54(3pKm8;UAJ<_BULR*Z=m5FU7jiW(&#l+}WkHZ|e@1 z`pm;Q^pCuLUQUrnQ(hPM10pSSHQS=Bf8DqG1&!-B!oQQ|FuzLruL1w(+g<8&znyI? zzX-}?SwUvNjEuT?7uUOy{Fb@xKklpj+jdYM^IK9}NxvLRZd{l9FHEQJ4IO~q%4I0O zAN|*8x^nIU4Giw?f*tmNx=7H)2-Zn?J^B6SgpcW3ZXV_57Sn%Mtfr_=w|sYpAhdJT zcKo6Z*oIOU(az~3$LOEWm9Q)dYWMA}T7L23MVGqrcA%4H)+^`+=j+Hh8CTCnnG2Rh zgcXVW%F8$R9)6}f=NQiLPt8qt3xNUQI>Q*)H1lzk<&n?XR-f}tc&9V0H0lhGqHJ^N zN%h(9-Of2_)!Xk{qdIkU>1%mk%I_Id1!MU*yq&&>)Q+!L^t&-2mW9Xq7g9C@* zl&PKJ&su2L+iku?Te?Pf?k3tUK){Bj_gb&aPo8Ago^XI~mRTd(5{&^tf1)!-lSMha z@$~ae!r(~`=p&|mMxy2EiZQ6FvXb(1avS*`Pj%$)*?vwceGKHmHnl`v&fEQ_Wh+G) zEPQ^3&oV%}%;zF`AM|S%d>pM@1}33PN5*4SewROk_K$n^i8QjaYiRzwG8#OvVIF|{x85wH+?*P*%)woI zR538k@=(E`V;p1UwA|fqSh`$n_t;Sz4T)`_s~pRR4lbmWWSdxa-FqLZ%fLT)Bh?iye?COx~mO1wkn5)HNMg7`8~ z25VJhz&3Z7`M>6luJrEw$Jikft+6SxyIh?)PU1?DfrKMGC z=3T;;omE4H`PWqF8?0*dOA3o9y@~WK`S}{?tIHquEw?v`M^D%Lobpdrp%3}1=-&qk zqAtb1px-1Fy6}E8IUg4s%8B0~P<P5C;de%@n~XnDKF@fr$a+^@$^P|>vlw($aSK2lRtLt~8tRb`I0 znfI!G?K|<5ry*gk>y56rZy0NkK6)))6Mg1=K?7yS9p+#1Ij=W*%5Rt-mlc;#MOnE9 zoi`-+6oj@)`gq2Af!B+9%J#K9V=ji2dj2<_qaLSXOCeqQ&<0zMSb$5mAi;HU=v`v<>NYk}MbD!ewYVB+N-ctzn=l&bTwv)*7 zmY<+Y@SBbtl9PPk$HTR?ln@(T92XjTRj0Mx|Mzl;lW>Su_y^~fh?8(L?oz8h!cCpb zZG-OY=NJ3{>r*`U<(J%#zjFT-a9>u6+23H{=d(utkgqt7@^)C;pkb)fQ|Q=*8*SyT z;otKe+f8fEp)ZacKZDn3TNzs>_Kx+g*c_mr8LBhr8GnoEmAQk#%sR52`bdbW8Ms$!0u2bdt=T-lK3JbDW`F(Urt%Ob2seiN>7U`YN}aOdIiCC;eeufJC#m3S z9#|l2c?G@t*hH5y^76jkv)rs4H+;oiTuY5FQwRMN_7NUqeiD|b&RyxPXQz|3qC(_> zZJMwjC4F!1m2INXqzisQ4X^w=>&(+Ecdu&~IWEMn7f*YcYI&eWI(6hI#f114%aymM zyhlG6{q>XN7(LyGiMAS&qijR%d2rV|>AUT_sE&EKUSTCM26>aKzNxk0?K|utOcxl# zxIOwM#O!!H+QzbX*&p=QuKe4y;bS>&StQOE5AEGg_ubk8{;1yOVAJfE_Js-lL7rr9 z)CEuFIlkApj~uV^zJK7KocjT=4B zJP(}0x}|A7C$$5gIp>KBPZ|A#2Ew;$#g9Fk)r;Q~?G$>x<+JM)J3u>j zi68K=I;ld`JJ?Nq+^_B?C+Q%+x#m{9JF$tbaDeNIep%=^#>KHGtg=L)>m z_J&vaZTs2{qP!4Gdw5u5Kcf}5R4(q}Lebx%(J$7l*Q`Il#pCTM%!`y5y*-~zIVs}D z9;t+(xmV~R65^ZQXe+<5{$QW0O8MT~a{kdFLR)nfRMA9L(YU>x*DTltN#m-2km zC;T`cfb{c`mcx(z7o_a8bYJn8_^dz4Cq!DZ37{P6uF{@#519UWK1{>(9sZB1I^6MmNc39MJ-_|)!S8vO+O3&$MulU3Gc z_W{N*B(yneyl-oN_MKaJ{CZ6dv-~^8uPbLSh&0jfV@EfA{2Dc!_rOyfx`R0T@LonA z<*%O?-aa_Wm-z$s@K(ex7UhM0-?9C=PkYdk&d2n((E4>&(f4D`fOQY%CURMMyJyU` zVeJBAId&StHjw76tnwSqZs3e0683`L{a3k9JYdg#(ZVw4J`&CkV-2LFaDE1Z?CehVy%vZx$tM3tTax8E@2;N^QTrPcI?Ob8uK!DM0_sfE6ks2M?iw zPS4{(k-PF*-oY>S!d9;L+|xdTtLen9B2LvpL4k;#ScB< z$NP_7j~7)5eXuoYEk*dK_rSz9yT_C4B{r~^#^o}-VQI=Y?01|$aa!a7=UEm$|DsQQ zfLK1qmho2@)nwA?$1%T6jwO2HZ({6&;`s|OQOxI4S8*Hw=Qp!b(gNJR%SAj&wGa>^&2@x)Vj zhd^WfzJ^b0O{E^q82Pw({uT`E`MT2WnZ02{E%t*yRPN>?W>0vU^4@Vyh4;mLj918c z*s*papo?<}cQM{5lcgZScx}?usg{mS!KkH9U%@|^_33?{FI{1ss+8kXyFY&5M-e~f zM$){FF;_+z3sNJ)Er~{Beux$fEl{R4|7WKcpEsGtK57f+H0DJ$hI;U;JtF>+lG@sV zQI_;bQ^7XIJ>Bs?C32b1v;am;P4GUqAJ#zOHv}4SmV|xXX6~O9&e_~YCCpbT>s$`! k<4FtN!5 impl IntoView { + // Creates a reactive value to update the button + let count = RwSignal::new(0); + let on_click = move |_| *count.write() += 1; + + view! { +
    +

    "Welcome to Leptos!"

    + + "DISCLAIMER:" +

    "This isn't a design example! Its just proof of sabry's capabilities."

    +

    "Plz dont make websites/apps which look like this page :D"

    +
    + } +} diff --git a/examples/leptos-axum/src/routes/home.scss b/examples/leptos-axum/src/routes/home.scss new file mode 100644 index 0000000..67e7ec1 --- /dev/null +++ b/examples/leptos-axum/src/routes/home.scss @@ -0,0 +1,12 @@ +@use "tokens"; +@use "utils"; +@use "theme"; + +.btn { + @include tokens.clickable(accent); +} + +.table { + @include utils.flex(column, center, center); + @include theme.surface(primary); +} diff --git a/examples/leptos-axum/src/routes/mod.rs b/examples/leptos-axum/src/routes/mod.rs new file mode 100644 index 0000000..9b86bcf --- /dev/null +++ b/examples/leptos-axum/src/routes/mod.rs @@ -0,0 +1 @@ +pub mod home; diff --git a/examples/leptos-axum/src/shell.rs b/examples/leptos-axum/src/shell.rs new file mode 100644 index 0000000..125c90d --- /dev/null +++ b/examples/leptos-axum/src/shell.rs @@ -0,0 +1,43 @@ +use leptos::prelude::*; +use leptos_meta::{provide_meta_context, MetaTags, Stylesheet, Title}; +use leptos_router::{ + components::{Route, Router, Routes}, + StaticSegment, +}; + +use crate::routes; + +pub fn shell(options: LeptosOptions) -> impl IntoView { + view! { + + + + + + + + + + + + + + } +} + +#[component] +pub fn App() -> impl IntoView { + provide_meta_context(); + + view! { + + + <Router> + <main> + <Routes fallback=|| "Page not found.".into_view()> + <Route path=StaticSegment("") view=routes::home::Route/> + </Routes> + </main> + </Router> + } +} diff --git a/examples/use-styles/Cargo.lock b/examples/use-styles/Cargo.lock new file mode 100644 index 0000000..7e7c03c --- /dev/null +++ b/examples/use-styles/Cargo.lock @@ -0,0 +1,1491 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "anstream" +version = "0.6.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64-simd" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "781dd20c3aff0bd194fe7d2a977dd92f21c173891f3a03b677359e5fa457e5d5" +dependencies = [ + "simd-abstraction", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake3" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" + +[[package]] +name = "cc" +version = "1.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "codemap" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e769b5c8c8283982a987c6e948e540254f1058d5a74b8794914d4ef5fc2a24" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "const-str" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21077772762a1002bb421c3af42ac1725fa56066bfc53d9a55bb79905df2aaf3" +dependencies = [ + "const-str-proc-macro", +] + +[[package]] +name = "const-str-proc-macro" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1e0fdd2e5d3041e530e1b21158aeeef8b5d0e306bc5c1e3d6cf0930d10e25a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "const_format" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "cssparser" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be934d936a0fbed5bcdc01042b770de1398bf79d0e192f49fa7faea0e99281e" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf 0.11.2", + "smallvec", +] + +[[package]] +name = "cssparser-color" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556c099a61d85989d7af52b692e35a8d68a57e7df8c6d07563dc0778b3960c9f" +dependencies = [ + "cssparser", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.85", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "data-url" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a30bfce702bcfa94e906ef82421f2c0e61c076ad76030c16ee5d2e9a32fe193" +dependencies = [ + "matches", +] + +[[package]] +name = "define-styles" +version = "0.0.0" +dependencies = [ + "sabry", +] + +[[package]] +name = "dtoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "grass" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7a68216437ef68f0738e48d6c7bb9e6e6a92237e001b03d838314b068f33c94" +dependencies = [ + "clap", + "getrandom", + "grass_compiler", +] + +[[package]] +name = "grass_compiler" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d9e3df7f0222ce5184154973d247c591d9aadc28ce7a73c6cd31100c9facff6" +dependencies = [ + "codemap", + "indexmap", + "lasso", + "once_cell", + "phf 0.11.2", + "rand", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash 0.8.11", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.0", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lasso" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e14eda50a3494b3bf7b9ce51c52434a761e383d7238ce1dd5dcec2fbc13e9fb" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "lightningcss" +version = "1.0.0-alpha.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e225b3fa0a8bd5562c8833b1a32afa88761c4e661d3177b8cdc4e13cbf078e" +dependencies = [ + "ahash 0.8.11", + "bitflags", + "const-str", + "cssparser", + "cssparser-color", + "dashmap", + "data-encoding", + "getrandom", + "itertools", + "lazy_static", + "lightningcss-derive", + "parcel_selectors", + "parcel_sourcemap", + "paste", + "pathdiff", + "rayon", + "serde", + "smallvec", +] + +[[package]] +name = "lightningcss-derive" +version = "1.0.0-alpha.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12744d1279367caed41739ef094c325d53fb0ffcd4f9b84a368796f870252" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "outref" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4" + +[[package]] +name = "parcel_selectors" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4d26c18a8377a64728c04bf3b2e48ec43b0c77e687a18e03eb837d65e08a14" +dependencies = [ + "bitflags", + "cssparser", + "fxhash", + "log", + "phf 0.10.1", + "phf_codegen", + "precomputed-hash", + "smallvec", +] + +[[package]] +name = "parcel_sourcemap" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "485b74d7218068b2b7c0e3ff12fbc61ae11d57cb5d8224f525bd304c6be05bbb" +dependencies = [ + "base64-simd", + "data-url", + "rkyv", + "serde", + "serde_json", + "vlq", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pathdiff" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" + +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_shared 0.10.0", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator 0.11.2", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.85", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "raffia" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c36f58fa7ad2f26bca656054c902becddeac5582df2bb31d4b4d2a148c62cfd5" +dependencies = [ + "raffia_macro", + "smallvec", +] + +[[package]] +name = "raffia_macro" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fdb50eb5bf734fa5a770680a61876a6ec77b99c1e0e52d1f18ad6ebfa85759f" +dependencies = [ + "heck", + "quote", + "syn 2.0.85", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "rkyv" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "sabry" +version = "0.0.1" +dependencies = [ + "sabry_build", + "sabry_intrnl", + "sabry_procmacro", +] + +[[package]] +name = "sabry_build" +version = "0.0.0" +dependencies = [ + "proc-macro2", + "sabry_intrnl", + "sabry_procmacro_impl", + "syn 2.0.85", + "thiserror", + "walkdir", +] + +[[package]] +name = "sabry_intrnl" +version = "0.0.0" +dependencies = [ + "base64", + "blake3", + "const_format", + "grass", + "lightningcss", + "proc-macro2", + "raffia", + "regex", + "serde", + "syn 2.0.85", + "thiserror", + "toml", +] + +[[package]] +name = "sabry_procmacro" +version = "0.0.0" +dependencies = [ + "sabry_procmacro_impl", +] + +[[package]] +name = "sabry_procmacro_impl" +version = "0.0.0" +dependencies = [ + "proc-macro2", + "quote", + "raffia", + "regex", + "sabry_intrnl", + "syn 2.0.85", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "serde" +version = "1.0.213" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.213" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", +] + +[[package]] +name = "serde_json" +version = "1.0.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-abstraction" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cadb29c57caadc51ff8346233b5cec1d240b68ce55cf1afc764818791876987" +dependencies = [ + "outref", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "use-styles" +version = "0.0.0" +dependencies = [ + "define-styles", + "sabry", +] + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vlq" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65dd7eed29412da847b0f78bcec0ac98588165988a8cfe41d4ea1d429f8ccfff" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.85", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", +] diff --git a/examples/use-styles/Cargo.toml b/examples/use-styles/Cargo.toml new file mode 100644 index 0000000..77c0ca6 --- /dev/null +++ b/examples/use-styles/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "use-styles" +version = "0.0.0" +edition = "2021" +rust-version = "1.82" +publish = false + +[dependencies] +sabry = {path = "../../", features = ["sass"]} + +[build-dependencies] +sabry = {path = "../../", features = ["build", "sass"]} +define-styles = {path = "../define-styles"} + +[package.metadata.sabry] +css.bundle = "target/static/style.css" +css.scopes = "target/static/styles/" +css.bundle_prelude = ["assets/prelude.css"] + +hash.size = 6 +hash.collision = "error" + +[package.metadata.sabry.lightningcss] +targets = {chrome = "120", firefox = "120", ie = "8"} diff --git a/examples/use-styles/assets/prelude.css b/examples/use-styles/assets/prelude.css new file mode 100644 index 0000000..b889e82 --- /dev/null +++ b/examples/use-styles/assets/prelude.css @@ -0,0 +1,4 @@ +html { + box-sizing: border-box; + font-size: 10px; +} diff --git a/examples/use-styles/build.rs b/examples/use-styles/build.rs new file mode 100644 index 0000000..88a9998 --- /dev/null +++ b/examples/use-styles/build.rs @@ -0,0 +1,22 @@ +use define_styles::{theme, tokens, utils as utils_dup}; +use sabry::{sassy, usey}; + +// This module will have the same name as define_styles_example::utils +// and sabry is configured to merge them +sassy!(utils { + @mixin nonclickable(){ + display: none; + } +}); + +fn main(){ + /* Declare modules to use with sabry */ + sabry::buildy( + usey!( + theme!(), + tokens!(), + utils_dup!(), + utils!() + ) + ).expect("Failed to build sabry styles"); +} diff --git a/examples/use-styles/src/main.rs b/examples/use-styles/src/main.rs new file mode 100644 index 0000000..6751b2c --- /dev/null +++ b/examples/use-styles/src/main.rs @@ -0,0 +1,17 @@ +use sabry::styly; + +styly!(pub const bundlemod { + @use "tokens"; + .someth { + @include tokens.clickable; + background-color: black; + } +}); + +styly!(pub const filemod:sass "src/main.sass"); + +fn main(){ + println!("someth class codemod styles: {}", bundlemod::someth); + println!("someth class filemod styles: {}", filemod::someth); + println!("Thats how we used the styles! Good luck!!"); +} diff --git a/examples/use-styles/src/main.sass b/examples/use-styles/src/main.sass new file mode 100644 index 0000000..38596ed --- /dev/null +++ b/examples/use-styles/src/main.sass @@ -0,0 +1,12 @@ +@use "tokens" + +.someth + @include tokens.clickable + background: white + &-dark + background: none + border: 1px solid black + &[value] + &::after + content: "valued" + color: green diff --git a/sabry_build/Cargo.toml b/sabry_build/Cargo.toml new file mode 100644 index 0000000..05d7609 --- /dev/null +++ b/sabry_build/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "sabry_build" +description = "Sabry build magic as a separate crate" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true + +[dependencies] +sabry_intrnl = {workspace = true} +sabry_procmacro_impl = {workspace = true} +proc-macro2 = {workspace = true, features = ["span-locations"]} +syn = {workspace = true, features = ["visit", "derive", "parsing", "full"]} +thiserror = {workspace = true} + +walkdir = {version = "^2.5"} + +[features] +sass = [ + "sabry_procmacro_impl/sass", + "sabry_intrnl/sass" +] +scss = [ + "sabry_procmacro_impl/scss", + "sabry_intrnl/scss" +] +net-files = [] diff --git a/sabry_build/src/buildmagic.rs b/sabry_build/src/buildmagic.rs new file mode 100644 index 0000000..c3e6439 --- /dev/null +++ b/sabry_build/src/buildmagic.rs @@ -0,0 +1,305 @@ +use std::{ + collections::HashSet, + convert::Infallible, + fs::{self, OpenOptions}, + io::{self, Write}, + path::PathBuf, + str::FromStr, vec, +}; + +use sabry_intrnl::{ + compiler::{CompilerAdapter, SabryCompilerError}, + config::{ + manifest::ManifestError, + BehavHashCollision, BehavSassModCollision, SabryConfig, + }, + scoper::{hash::ScopeHash, ArbitraryScope, ScopeError}, +}; +use sabry_procmacro_impl::impls::styly; +use walkdir::WalkDir; + +use crate::filevisit::{self, FileVisitError}; + +type ModuleName = String; +type ModuleCode = String; +type StyleModule = (ModuleName, ModuleCode); +type BuilderResult = Result<(), SabryBuildError>; + +pub fn buildy(inline_side_modules: impl IntoIterator<Item = StyleModule>) -> BuilderResult { + println!("🧙: This is probably the stderr. Something went wrong:"); + + let config = SabryConfig::require()?; + let mut builder = SabryBuilder::new(config); + + println!("🧙 loading preludes"); + builder.load_preludes()?; + + println!("🧙 loading `buildy` modules"); + for (name, code) in inline_side_modules { + builder.load_side_module(name, code)?; + } + + println!("🧙 loading this crate"); + builder.load_styles_from_this_crate()?; + + println!("🧙 compiling CSS"); + builder.compile_everything()?; + + println!("🧙 writing an output"); + builder.generate_output()?; + + Ok(()) +} + +pub struct SabryBuilder { + config: SabryConfig, + css_compiler: CompilerAdapter, + state: SabryBuildState, +} + +//🧙 +impl SabryBuilder { + pub fn new(config: SabryConfig) -> Self { + let css_compiler = CompilerAdapter::new(config.clone()); + Self { + config, + css_compiler, + state: SabryBuildState::default(), + } + } + + /// Write all the loaded CSS + /// + /// - Bundle file (if configured) + /// - Scope chunks (if out-dir is configured) + pub fn generate_output(&mut self) -> BuilderResult { + // warn on empty loaded_css_modules + if self.state.loaded_css_modules.is_empty() { + println!("🧙 sabry didn't compile any CSS. Perhaps the crate has no styles? Lets write some!\nAlso you should check that you do use `styly!` macro properly - at the top level as an item."); + } + + if let Some(scope_dir) = &self.config.css.scopes { + println!("🧙 writing CSS files for each of loaded scopes into {scope_dir}"); + + fs::create_dir_all(scope_dir)?; + for (scope, code) in &self.state.loaded_css_modules { + let scope_path = format!("{}/{}.css", scope_dir, scope); + fs::write(scope_path, code)?; + } + } + + if let Some(bundle_file) = &self.config.css.bundle { + println!("🧙 writing merged CSS for the entire crate into {bundle_file}"); + + let path = PathBuf::from_str(bundle_file)?; + + if let Some(dir) = path.parent() { + fs::create_dir_all(dir)?; + } + + // remove the file to write new fresh tasty CSS + let _ = fs::remove_file(&path); + // and then reopen it + let mut file = OpenOptions::new() + .create_new(true) + .append(true) + .open(path)?; + + for (_, code) in &self.state.loaded_css_modules { + write!(file, " {}", self.state.css_prelude)?; + write!(file, " {code}")?; + } + } + + Ok(()) + } + + /// Compile all the loaded styles, SASS/SCSS/CSS, without actually writing them. + pub fn compile_everything(&mut self) -> BuilderResult { + // warn on empty known_side_modules and loaded_stylyses + if self.state.known_side_modules.is_empty() { + println!("🧙 sabry didn't load any side modules"); + } + if self.state.loaded_stylyses.is_empty() { + println!("🧙 sabry didn't load any usable styles"); + } + + for styly in &self.state.loaded_stylyses { + let scope = ArbitraryScope::from_source( + styly.syntax.into(), + styly.scope.clone(), + styly.code.code(), + )? + .hashed(&self.config.hash)?; + + match self.config.hash.collision { + BehavHashCollision::Ignore => {} + BehavHashCollision::Error => { + if self.state.known_scope_hashes.contains(&scope.hash) { + return Err(SabryBuildError::HashCollision { + scope: scope.original_scope.name.to_string(), + }); + } + self.state.known_scope_hashes.insert(scope.hash.clone()); + } + } + + let css = self.css_compiler.compile_module( + scope.original_scope.adapter().syntax.into(), + &scope.hashed_code, + )?; + self.state + .loaded_css_modules + .push((scope.original_scope.name.to_string(), css)); + } + + Ok(()) + } + + /// Visit all the source files in the current crate and look for code that may affect building process: + /// + /// - `styly!` macro calls + /// + /// Only files with an **.rs** extension are visited. + /// + /// All the gathered info is loaded into state + pub fn load_styles_from_this_crate(&mut self) -> BuilderResult { + println!("🧙 scanning the crate"); + + let root = WalkDir::new(&self.config.sass.scanroot); + + for entry in root { + let entry = entry?; + let metadata = entry.metadata()?; + + if metadata.is_file() { + let entry_path = entry.path(); + let ext = entry_path.extension().unwrap_or_default(); + if ext == "rs" { + let visitor = filevisit::visit_file(entry_path)?; + self.state.loaded_stylyses.extend(visitor.found_stylys); + } + } else if metadata.is_symlink() { + println!( + "🧙 sabry won't go through symlinks currently ('{}' is a symlink)", + entry.path().to_string_lossy() + ) + } + } + + Ok(()) + } + + /// Load up configured preludes as side modules + pub fn load_preludes(&mut self) -> BuilderResult { + // load sass modules from config + let mut modules: Vec<StyleModule> = vec![]; + if let Some(sass_pre) = &self.config.sass.modules { + for pre in sass_pre { + let pre_path = PathBuf::from_str(pre)?; + let pre_name = pre_path + .file_name() + .ok_or(SabryBuildError::FileName())? + .to_string_lossy() + .to_string(); + let code = fs::read_to_string(pre_path)?; + modules.push((pre_name, code)); + } + } + for (name, code) in modules { + self.load_side_module(name, code)?; + } + + // load css preludes + if let Some(css_pre) = &self.config.css.bundle_prelude { + for pre in css_pre { + let code = fs::read_to_string(pre)?; + self.state.css_prelude.push_str(&code); + } + } + + Ok(()) + } + + /// Load up the SASS module by its `name` and fill the according file by its `code` as-is + /// + /// Module "loading" is simply a file creation. File is created in the configured `intermediate_dir` + /// directory. + /// + /// Module `name` is not suffixed with syntax/extensions/whatever so it already should have necessary file extensions. + /// + /// This function will not overwrite the module file. Never. + /// + pub fn load_side_module(&mut self, name: ModuleName, code: ModuleCode) -> BuilderResult { + println!("🧙 loading side module '{}'", &name); + + let module_file_path = format!("{}/{}", &self.config.sass.intermediate_dir, &name); + let mut open_options = OpenOptions::new(); + let mut open_options = open_options.write(true); + + // prematurelly remove module file if the module is not yet known to be loaded + if !self.state.known_side_modules.contains(&name) { + let _ = fs::remove_file(&module_file_path); + } + + open_options = if self.state.known_side_modules.contains(&name) { + match &self.config.sass.module_name_collision { + BehavSassModCollision::Error => { + return Err(SabryBuildError::ModuleCollision { module: name }) + } + BehavSassModCollision::Merge => { + println!("🧙 sabry found duplicate module name '{name}': merging code, as configured"); + open_options.append(true) + } + } + } else { + open_options.create(true) + }; + + fs::create_dir_all(&self.config.sass.intermediate_dir)?; + let mut module_file = open_options.open(module_file_path)?; + + write!(module_file, "\n{code}\n")?; + + self.state.known_side_modules.insert(name); + + Ok(()) + } +} + +#[derive(Default)] +pub struct SabryBuildState { + known_scope_hashes: HashSet<ScopeHash>, + known_side_modules: HashSet<ModuleName>, + loaded_stylyses: Vec<styly::MacroSyntax>, + loaded_css_modules: Vec<StyleModule>, + css_prelude: String, +} + +#[derive(Debug, thiserror::Error)] +pub enum SabryBuildError { + #[error("Filesystem error")] + Fs(#[from] io::Error), + #[error("Failed to walk through the crate")] + CrateWalk(#[from] walkdir::Error), + #[error("Failed to load side SASS module")] + LoadSass(), + #[error( + "Module with the similar name was already loaded, and sabry is configured to raise an error" + )] + ModuleCollision { module: ModuleName }, + #[error("Sabry cant understand the file")] + FileVisit(#[from] FileVisitError), + #[error("Syntax of style can not be parsed")] + SyntaxParse(#[from] ScopeError), + #[error("Another scope has the same hash, and sabry is configured to raise an error. Try to adjust config, increase hash size, or change the style code")] + HashCollision { scope: ModuleName }, + #[error("Something's wrong with file path")] + Path(#[from] Infallible), + #[error("File name wasnt determined properly")] + FileName(), + #[error("Failed to compile CSS")] + CssCompile(#[from] SabryCompilerError), + #[error("Failed to load config/manifest")] + Manifest(#[from] ManifestError), +} diff --git a/sabry_build/src/filevisit.rs b/sabry_build/src/filevisit.rs new file mode 100644 index 0000000..2844469 --- /dev/null +++ b/sabry_build/src/filevisit.rs @@ -0,0 +1,51 @@ +use std::{fs, io, path::Path}; + +use proc_macro2::TokenStream; +use sabry_procmacro_impl::impls::styly; +use syn::{spanned::Spanned, visit::Visit}; + +#[derive(Debug, thiserror::Error)] +pub enum FileVisitError { + #[error("Could not read file")] + Read(#[from] io::Error), + #[error("styly! macro found, yet invalid")] + Styly(#[from] syn::Error), +} + +/// Visit file, returning either [StylyVisitor] or error +pub fn visit_file(path: &Path) -> Result<StylyVisitor, FileVisitError> { + let content = fs::read_to_string(path)?; + let code_file = syn::parse_file(&content)?; + + let mut styly_visitor = StylyVisitor { + found_stylys: vec![], + }; + styly_visitor.visit_file(&code_file); + + Ok(styly_visitor) +} + +/// Syn Visitor, which will look at every `styly!` macro, +/// parse its input tokenstream and avaluate it, capturing [styly::MacroSyntax] result +/// +/// ## Panics +/// +/// If either macro body is not a [TokenStream], or [styly::parse_macro_syntax] is not [Ok] +#[derive(Debug)] +pub struct StylyVisitor { + pub found_stylys: Vec<styly::MacroSyntax>, +} + +impl<'ast> Visit<'ast> for StylyVisitor { + fn visit_item_macro(&mut self, node: &'ast syn::ItemMacro) { + if node.mac.path.get_ident().is_some_and(|i| i == "styly") { + let body = node.mac.parse_body::<TokenStream>().unwrap_or_else(|_| { + panic!("could not parse `styly!` macro at {:?}", node.mac.span()) + }); + let macro_data = styly::parse_macro_syntax(body).unwrap_or_else(|_| { + panic!("could not parse `styly!` macro at {:?}", node.mac.span()) + }); + self.found_stylys.push(macro_data); + } + } +} diff --git a/sabry_build/src/lib.rs b/sabry_build/src/lib.rs new file mode 100644 index 0000000..180dbd0 --- /dev/null +++ b/sabry_build/src/lib.rs @@ -0,0 +1,3 @@ +pub mod buildmagic; +pub mod filevisit; +pub use buildmagic::*; diff --git a/sabry_intrnl/Cargo.toml b/sabry_intrnl/Cargo.toml new file mode 100644 index 0000000..5bf56e5 --- /dev/null +++ b/sabry_intrnl/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "sabry_intrnl" +description = "Sabry internal, yet still public library" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true + +[dependencies] +raffia = {workspace = true} +grass = {workspace = true} +lightningcss = {workspace = true} +blake3 = {workspace = true} +base64 = {workspace = true} + +syn = {workspace = true} +proc-macro2 = {workspace = true} +regex = {workspace = true} +const_format = {workspace = true} + +serde = {workspace = true, features = ["derive"]} +toml = {workspace = true} +thiserror = {workspace = true} + +[features] +sass = [] +scss = [] diff --git a/sabry_intrnl/src/compiler/mod.rs b/sabry_intrnl/src/compiler/mod.rs new file mode 100644 index 0000000..0c2df2b --- /dev/null +++ b/sabry_intrnl/src/compiler/mod.rs @@ -0,0 +1,120 @@ +use lightningcss::{printer::PrinterOptions, stylesheet::MinifyOptions, targets::Targets}; + +use crate::config::SabryConfig; + +/// Convenience wrapper on Grass and Lightningcss +pub struct CompilerAdapter { + config: SabryConfig, +} + +impl CompilerAdapter { + pub fn new(config: SabryConfig) -> Self { + Self { config } + } + + pub fn compile_module( + &self, + syntax: CompilerSyntax, + code: &str, + ) -> Result<String, SabryCompilerError> { + let options = grass::Options::from(&self.config).input_syntax(syntax.into()); + + let mut css = grass::from_string(code, &options)?; + + if self.config.css.minify { + //its lightningcss time! + let mut lightsheet = match lightningcss::stylesheet::StyleSheet::parse( + &css, + lightningcss::stylesheet::ParserOptions::default(), + ) { + Ok(s) => s, + Err(_) => return Err(SabryCompilerError::Lightningcss()), + }; + + let targets = Targets { + browsers: Some(self.config.lightningcss.targets.clone().into()), + ..Default::default() + }; + + let printer_options = PrinterOptions { + minify: self.config.css.minify, + targets, + ..Default::default() + }; + + let minify_options = MinifyOptions { + targets, + ..Default::default() + }; + + if lightsheet.minify(minify_options).is_err() { + return Err(SabryCompilerError::Lightningcss()); + } + + css = match lightsheet.to_css(printer_options) { + Ok(c) => { + drop(lightsheet); + c.code + } + Err(_) => return Err(SabryCompilerError::Lightningcss()), + }; + } + + Ok(css) + } +} + +impl From<&SabryConfig> for grass::Options<'_> { + fn from(config: &SabryConfig) -> Self { + let mut options = grass::Options::default(); + options = options.style(if config.css.minify { + grass::OutputStyle::Compressed + } else { + grass::OutputStyle::Expanded + }); + options = options.load_path(&config.sass.intermediate_dir); + + options + } +} + +#[derive(Debug, thiserror::Error)] +pub enum SabryCompilerError { + #[error("Could not compile into CSS with grass")] + GrassCompile(#[from] Box<grass::Error>), + #[error("Could not parse compiled CSS with lightningcss")] + Lightningcss(), +} + +/// Unification wrapper over all the Syntax enums +#[derive(Clone, Copy)] +pub enum CompilerSyntax { + #[cfg(feature = "sass")] + Sass, + #[cfg(feature = "scss")] + Scss, +} + +impl From<raffia::Syntax> for CompilerSyntax { + fn from(value: raffia::Syntax) -> Self { + match value { + #[cfg(feature = "sass")] + raffia::Syntax::Sass => Self::Sass, + #[cfg(feature = "scss")] + raffia::Syntax::Scss => Self::Scss, + // TODO: fallbacky error-prone + _ => Self::Scss, + } + } +} + +impl From<CompilerSyntax> for grass::InputSyntax { + fn from(value: CompilerSyntax) -> Self { + match value { + #[cfg(feature = "scss")] + CompilerSyntax::Scss => Self::Scss, + #[cfg(feature = "sass")] + CompilerSyntax::Sass => Self::Sass, + } + } +} diff --git a/sabry_intrnl/src/config/manifest.rs b/sabry_intrnl/src/config/manifest.rs new file mode 100644 index 0000000..ac0700f --- /dev/null +++ b/sabry_intrnl/src/config/manifest.rs @@ -0,0 +1,44 @@ +use std::{env, fs, io}; + +use serde::Deserialize; + +use super::SabryConfig; + +pub const MANIFEST: &str = "Cargo.toml"; +pub const MANIFEST_DIR_ENV: &str = "CARGO_MANIFEST_DIR"; + +pub fn read_manifest() -> Result<ValuableManifest, ManifestError> { + let manpath = format!("{}/{MANIFEST}", env::var(MANIFEST_DIR_ENV)?); + + Ok(toml::de::from_str(&fs::read_to_string(manpath)?)?) +} + +#[derive(Debug, thiserror::Error)] +pub enum ManifestError { + #[error("Could not read manifest path from env")] + ManifestDirEnv(#[from] env::VarError), + #[error("Could not read manifest file")] + ManifestRead(#[from] io::Error), + #[error("Could not deserialize manifest")] + ManifestDe(#[from] toml::de::Error), +} + +/// Manifest structure that makes sense for sabry +#[derive(Deserialize, Default)] +pub struct ValuableManifest { + pub package: Option<ValuableManifestPkg>, +} + +/// Manifest \[package.metadata\] structure that makes sense for sabry +#[derive(Deserialize, Default)] +pub struct ValuableManifestPkg { + pub metadata: Option<ValuableManifestPkgMeta>, +} + +/// Manifest \[package.metadata.sabry\] structure that makes sense for sabry +/// +/// Which is basically [SabryConfig] +#[derive(Deserialize, Default)] +pub struct ValuableManifestPkgMeta { + pub sabry: Option<SabryConfig>, +} diff --git a/sabry_intrnl/src/config/mod.rs b/sabry_intrnl/src/config/mod.rs new file mode 100644 index 0000000..0903929 --- /dev/null +++ b/sabry_intrnl/src/config/mod.rs @@ -0,0 +1,253 @@ +pub mod manifest; +use manifest::{ManifestError, ValuableManifest}; +use serde::Deserialize; + +/// Sabry configuration, as it is from package.metadata.sabry +#[derive(Default, Deserialize, Clone)] +pub struct SabryConfig { + #[serde(default = "SabryCssConfig::default")] + pub css: SabryCssConfig, + #[serde(default = "SabrySassConfig::default")] + pub sass: SabrySassConfig, + #[serde(default = "SabryHashConfig::default")] + pub hash: SabryHashConfig, + #[serde(default = "SabryGrassConfig::default")] + pub grass: SabryGrassConfig, + #[serde(default = "SabryLightCssConfig::default")] + pub lightningcss: SabryLightCssConfig, +} + +impl SabryConfig { + /// Require sabry configuration for the current project from every place in the code + pub fn require() -> Result<Self, ManifestError> { + let manifest = manifest::read_manifest()?; + Ok(Self::from(&manifest)) + } +} + +impl From<&ValuableManifest> for SabryConfig { + fn from(value: &ValuableManifest) -> Self { + value + .package + .as_ref() + .and_then(|p| p.metadata.as_ref()) + .and_then(|m| m.sabry.as_ref()) + .map_or(Self::default(), |sbr| sbr.clone()) + } +} + +/// Sabry `css` configuration table +#[derive(Deserialize, Clone)] +pub struct SabryCssConfig { + pub bundle: Option<String>, + pub scopes: Option<String>, + pub bundle_prelude: Option<Vec<String>>, + #[serde(default = "SabryCssConfig::default_minify")] + pub minify: bool, +} + +impl SabryCssConfig { + fn default_minify() -> bool { + true + } +} + +impl Default for SabryCssConfig { + fn default() -> Self { + Self { + bundle: None, + scopes: None, + bundle_prelude: None, + minify: Self::default_minify(), + } + } +} + +/// Sabry `sass` configuration table +/// +/// (SASS/SCSS related config) +#[derive(Deserialize, Clone)] +pub struct SabrySassConfig { + #[serde(default = "SabrySassConfig::default_scanroot")] + pub scanroot: String, + pub modules: Option<Vec<String>>, + #[serde(default = "SabrySassConfig::default_intermediate_dir")] + pub intermediate_dir: String, + #[serde(default = "SabrySassConfig::default_module_name_collision")] + pub module_name_collision: BehavSassModCollision, +} + +impl SabrySassConfig { + fn default_scanroot() -> String { + "src".into() + } + fn default_intermediate_dir() -> String { + "target/.sabry/sass".into() + } + fn default_module_name_collision() -> BehavSassModCollision { + BehavSassModCollision::default() + } +} + +impl Default for SabrySassConfig { + fn default() -> Self { + Self { + scanroot: Self::default_scanroot(), + modules: None, + intermediate_dir: Self::default_intermediate_dir(), + module_name_collision: Self::default_module_name_collision(), + } + } +} + +/// Sabry `hash` configuration table +#[derive(Deserialize, Clone)] +pub struct SabryHashConfig { + #[serde(default = "SabryHashConfig::default_size")] + pub size: usize, + #[serde(default = "SabryHashConfig::default_collision")] + pub collision: BehavHashCollision, + #[serde(default = "SabryHashConfig::default_use_scope_name")] + pub use_scope_name: bool, + #[serde(default = "SabryHashConfig::default_use_item_names")] + pub use_item_names: bool, + #[serde(default = "SabryHashConfig::default_use_code_size")] + pub use_code_size: bool, + #[serde(default = "SabryHashConfig::default_use_code_text")] + pub use_code_text: bool, +} + +impl SabryHashConfig { + fn default_size() -> usize { + 6 + } + fn default_collision() -> BehavHashCollision { + BehavHashCollision::default() + } + fn default_use_scope_name() -> bool { + true + } + fn default_use_item_names() -> bool { + false + } + fn default_use_code_size() -> bool { + true + } + fn default_use_code_text() -> bool { + false + } +} + +impl Default for SabryHashConfig { + fn default() -> Self { + Self { + size: Self::default_size(), + collision: Self::default_collision(), + use_scope_name: Self::default_use_scope_name(), + use_code_size: Self::default_use_code_size(), + use_code_text: Self::default_use_code_text(), + use_item_names: Self::default_use_item_names(), + } + } +} + +/// [grass] specific configuration for sabry +#[derive(Default, Deserialize, Clone)] +pub struct SabryGrassConfig {} + +/// [lightningcss] specific configuration for sabry +#[derive(Default, Deserialize, Clone)] +pub struct SabryLightCssConfig { + pub targets: SabryLightTargets, +} + +/// \[package.metadata.sabry.lightningcss.targets\] configuration. +/// +/// This is a convenience layer under [lightningcss::targets::Browsers] structure accepted +/// by lightningcss. +/// +/// This structure is a part of [SabryConfig], which faces developer with more convenient +/// `safari = "13.2"` syntax. +#[derive(Default, Deserialize, Clone)] +pub struct SabryLightTargets { + pub android: Option<String>, + pub chrome: Option<String>, + pub edge: Option<String>, + pub firefox: Option<String>, + pub ie: Option<String>, + pub ios_saf: Option<String>, + pub opera: Option<String>, + pub safari: Option<String>, + pub samsung: Option<String>, +} + +impl SabryLightTargets { + pub fn parse_ver(ver: &str) -> u32 { + let mut vercode: u32 = 0; + let vers = ver.split('.'); + for (i, dig) in vers.into_iter().enumerate() { + let dignum = dig + .parse::<u32>() + .unwrap_or_else(|_| panic!("Invalid browser specifier: '{dig}'")); + + let shift = 16 - 8 * i; + vercode |= dignum << shift; + } + vercode + } +} + +impl From<SabryLightTargets> for lightningcss::targets::Browsers { + fn from(value: SabryLightTargets) -> Self { + Self { + android: value.android.map(|s| SabryLightTargets::parse_ver(&s)), + chrome: value.chrome.map(|s| SabryLightTargets::parse_ver(&s)), + edge: value.edge.map(|s| SabryLightTargets::parse_ver(&s)), + firefox: value.firefox.map(|s| SabryLightTargets::parse_ver(&s)), + ie: value.ie.map(|s| SabryLightTargets::parse_ver(&s)), + ios_saf: value.ios_saf.map(|s| SabryLightTargets::parse_ver(&s)), + opera: value.opera.map(|s| SabryLightTargets::parse_ver(&s)), + safari: value.safari.map(|s| SabryLightTargets::parse_ver(&s)), + samsung: value.samsung.map(|s| SabryLightTargets::parse_ver(&s)), + } + } +} + +/// \[package.metadata.sabry.sass\].module_name_collision option +#[derive(Deserialize, Clone, Copy)] +#[serde(rename_all = "lowercase")] +pub enum BehavSassModCollision { + Merge, + Error, +} + +impl Default for BehavSassModCollision { + fn default() -> Self { + Self::Merge + } +} + +/// \[package.metadata.sabry.hash\].collision option +#[derive(Deserialize, Clone, Copy)] +#[serde(rename_all = "lowercase")] +pub enum BehavHashCollision { + Error, + Ignore, +} + +impl Default for BehavHashCollision { + fn default() -> Self { + Self::Ignore + } +} + +#[cfg(test)] +mod test { + use super::{manifest, SabryConfig}; + + #[test] + fn empty_manifest_still_worth_a_read() { + let manifest = manifest::read_manifest().unwrap(); + let _conf = SabryConfig::from(&manifest); + } +} diff --git a/sabry_intrnl/src/lib.rs b/sabry_intrnl/src/lib.rs new file mode 100644 index 0000000..ec12902 --- /dev/null +++ b/sabry_intrnl/src/lib.rs @@ -0,0 +1,4 @@ +pub mod compiler; +pub mod config; +pub mod scoper; +pub mod syntax; diff --git a/sabry_intrnl/src/scoper/hash.rs b/sabry_intrnl/src/scoper/hash.rs new file mode 100644 index 0000000..9f8a9e4 --- /dev/null +++ b/sabry_intrnl/src/scoper/hash.rs @@ -0,0 +1,97 @@ +use base64::Engine; + +use crate::config::SabryHashConfig; + +use super::ArbitraryScope; + +/// Convenience wrapper for String-being-a-hash +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ScopeHash(String); + +impl ScopeHash { + pub fn new(scope: &ArbitraryScope, config: &SabryHashConfig) -> Self { + let mut hasher = blake3::Hasher::new(); + + if config.use_scope_name { + hasher.update(scope.name.to_string().as_bytes()); + } + if config.use_code_text { + hasher.update(scope.adapter().source().as_bytes()); + } + if config.use_code_size { + hasher.update(&scope.adapter().source().len().to_ne_bytes()); + } + if config.use_item_names { + let classes = scope.adapter().class_selectors(); + let ids = scope.adapter().id_selectors(); + //# types/tags dont participate + //# child-parent dont participate + + let merged_items = classes + .iter() + .map(|s| &s.name) + .chain(ids.iter().map(|i| &i.name)) + .map(|ident| ident.as_literal()) + .filter_map(|mbl| mbl.map(|l| l.raw)) + .collect::<String>(); + + hasher.update(merged_items.as_bytes()); + } + + let size = if config.size >= blake3::OUT_LEN { + blake3::OUT_LEN + } else { + config.size + }; + + let hash = hasher.finalize(); + let hash = hash.as_bytes(); + + //? This isn't right. "size" is size of hash in symbols. + // naaah, its fine :D (Dan) + let hash = base64::prelude::BASE64_URL_SAFE_NO_PAD.encode(&hash[..size]); + + Self(hash) + } + + pub fn as_str(&self) -> &str { + &self.0 + } + + #[cfg(test)] + pub fn test_init(v: String) -> Self { + Self(v) + } +} + +#[cfg(test)] +mod test { + use syn::Ident; + + use crate::{config::SabryHashConfig, scoper::ArbitraryScope}; + + use super::ScopeHash; + + #[test] + fn hash_matches() { + let source = ".cls1{color:red; &-dark{color: black} #id1 {color:green;} div {color:blue;}} .cls3#id2{color: black;}"; + + let scope1 = ArbitraryScope::from_source( + raffia::Syntax::Scss, + syn::parse_str::<Ident>("lasifudm").unwrap(), + source, + ) + .unwrap(); + let hash1 = ScopeHash::new(&scope1, &SabryHashConfig::default()); + + let scope2 = ArbitraryScope::from_source( + raffia::Syntax::Scss, + syn::parse_str::<Ident>("lasifudm").unwrap(), + source, + ) + .unwrap(); + let hash2 = ScopeHash::new(&scope2, &SabryHashConfig::default()); + + assert_eq!(hash1, hash2); + } +} diff --git a/sabry_intrnl/src/scoper/mod.rs b/sabry_intrnl/src/scoper/mod.rs new file mode 100644 index 0000000..824aed7 --- /dev/null +++ b/sabry_intrnl/src/scoper/mod.rs @@ -0,0 +1,423 @@ +use hash::ScopeHash; +use raffia::Spanned; +use regex::Regex; + +use crate::{config::SabryHashConfig, syntax::StylesheetAdapter}; + +pub mod hash; + +#[derive(Debug, thiserror::Error)] +pub enum ScopeError { + #[error("Raffia reports parse error")] + Raffia(raffia::error::ErrorKind), +} + +impl From<raffia::error::Error> for ScopeError { + fn from(value: raffia::error::Error) -> Self { + Self::Raffia(value.kind) + } +} + +/// Struct which represents arbitrary style scope with known style syntax and name identifier +pub struct ArbitraryScope<'s> { + /// Ident name for the current scope + pub name: syn::Ident, + adapter: StylesheetAdapter<'s>, +} + +impl<'s> ArbitraryScope<'s> { + /// Parse given source code with given syntax and assign given name + pub fn from_source( + syntax: raffia::Syntax, + name: syn::Ident, + source: &'s str, + ) -> Result<Self, ScopeError> { + Ok(Self { + adapter: StylesheetAdapter::new(source, syntax)?, + name, + }) + } + + /// Consume arbitrary scope and create a [HashedScope] in its basis + /// + /// This function calls [HashedScope::new] under the hood + pub fn hashed(self, config: &SabryHashConfig) -> Result<HashedScope<'s>, ScopeError> { + let hash = ScopeHash::new(&self, config); + HashedScope::new(hash, self) + } + + /// Borrow the underlying [StylesheetAdapter] + pub fn adapter(&self) -> &StylesheetAdapter<'s> { + &self.adapter + } +} + +/// Hashed scope which holds hashed style code, +/// vector of hashed selectors and the calculated hash itself. +/// +/// Construction with [HashedScope::new] consumes [ArbitraryScope] and does all the job +pub struct HashedScope<'s> { + /// Original arbitrary scope + pub original_scope: ArbitraryScope<'s>, + /// Hashed style code + pub hashed_code: String, + /// Collection of hashed selectors + pub hashed_selectors: Vec<HashedSelector>, + + /// Given hash to the scope + pub hash: ScopeHash, +} + +impl<'s> HashedScope<'s> { + /// Consume [ArbitraryScope], + /// calculate the hash, + /// hash all the supported selectors + /// and construct hashed source code + /// + /// Heavy operation. + pub fn new(hash: ScopeHash, scope: ArbitraryScope<'s>) -> Result<Self, ScopeError> { + let origin_code = scope.adapter().source(); + let mut hashed_code = String::with_capacity(scope.adapter().source().len()); + + // get classes + let classes = scope.adapter().class_selectors(); + let classes = classes.iter().map(|c| HashedSelector::from_class(&hash, c)); + + // get ids + let ids = scope.adapter().id_selectors(); + let ids = ids.iter().map(|c| HashedSelector::from_id(&hash, c)); + + // get tags + let tags = scope.adapter().type_selectors(); + let tags = tags + .iter() + .filter_map(|t| t.as_tag_name()) + .map(|c| HashedSelector::from_tag(&hash, c)); + + let mut hashed_selectors = classes.chain(ids).chain(tags).collect::<Vec<_>>(); + + // sorting by span start is important because of how hashed code construction works + hashed_selectors.sort_by(|a, b| { + let astart = a.sel.as_arbitrary().span.start; + let bstart = b.sel.as_arbitrary().span.start; + + astart.cmp(&bstart) + }); + + let mut last_term_span: usize = 0; + for sel in &hashed_selectors { + let span = sel.sel.as_arbitrary().span.clone(); + hashed_code.push_str(&origin_code[last_term_span..span.start]); + hashed_code.push_str(&sel.css_ident); + last_term_span = span.end; + } + hashed_code.push_str(&origin_code[last_term_span..]); + + Ok(Self { + original_scope: scope, + hashed_code, + hashed_selectors, + hash, + }) + } +} + +/// Struct which represents hashed selector inside of [HashedScope]. +/// +/// Does not hold information about hash itself, as meant to be inside of scope. +pub struct HashedSelector { + /// Basic unrelated to hash info about this selector + pub sel: ScopedSelector, + /// CSS-ish identifier for this selector, which matches what's in the hashed style code + pub css_ident: String, + /// HTML-ish identifier for this selector, which will match [Self::css_ident] in browser + pub html_ident: Option<String>, +} + +impl HashedSelector { + /// Construct the [HashedSelector], with given hash and parsed class selector + pub fn from_class(hash: &ScopeHash, sel: &raffia::ast::ClassSelector) -> Self { + let sel = ScopedSelector::from_class(sel); + let css_ident = Self::make_hashed_css(&sel, hash); + let html_ident = Self::make_hashed_html(&sel, hash); + + Self { + sel, + css_ident, + html_ident, + } + } + + /// Construct the [HashedSelector], with given hash and parsed id selector + pub fn from_id(hash: &ScopeHash, sel: &raffia::ast::IdSelector) -> Self { + let sel = ScopedSelector::from_id(sel); + let css_ident = Self::make_hashed_css(&sel, hash); + let html_ident = Self::make_hashed_html(&sel, hash); + + Self { + sel, + css_ident, + html_ident, + } + } + + /// Construct the [HashedSelector], with given hash and parsed tagname selector + pub fn from_tag(hash: &ScopeHash, sel: &raffia::ast::TagNameSelector) -> Self { + let sel = ScopedSelector::from_tag(sel); + let css_ident = Self::make_hashed_css(&sel, hash); + let html_ident = Self::make_hashed_html(&sel, hash); + + Self { + sel, + css_ident, + html_ident, + } + } + + /// Transform this selector into hashed version for CSS-ish language + /// + /// Cooperates with the [HashedSelector::make_hashed_html], so + /// whats this function returns will be usable in HTML with to_hashed_html_def() + pub fn make_hashed_css(value: &ScopedSelector, hash: &ScopeHash) -> String { + match value { + // Class scoping is done with class composition + ScopedSelector::Class(a) => { + format!("{}.{}", hash.as_str(), a.ident) + } + // As we dont want to use two HTML props for a single ID, + // ID scoping is done with id modification + ScopedSelector::Id(a) => { + format!("{}-{}", hash.as_str(), a.ident) + } + ScopedSelector::Tag(a) => { + format!(".{} {}", hash.as_str(), a.ident) + } + } + } + + /// Transform this selector into hashed version valid for HTML-ish insertion + /// + /// Cooperates with the [HashedSelector::make_hashed_css], so + /// whats this function returns will be usable in CSS with to_hashed_code() + /// + /// Not every hashed selector is presentable for HTML-ish use: like `div`, in that case + /// returns [None] + pub fn make_hashed_html(value: &ScopedSelector, hash: &ScopeHash) -> Option<String> { + match value { + // Class scoping is done with class composition + ScopedSelector::Class(a) => Some(format!("{} {}", hash.as_str(), a.ident)), + // As we dont want to use two HTML props for a single ID, + // ID scoping is done with id modification + ScopedSelector::Id(a) => Some(format!("{}-{}", hash.as_str(), a.ident)), + ScopedSelector::Tag(_) => None, + } + } +} + +/// Just any unary CSS-ish selector +pub struct ArbitrarySelector { + /// CSS-ish identifier + pub ident: String, + /// Span in original CSS code where it comes from + pub span: raffia::Span, +} + +/// Any unary CSS-ish selector, that's able to be scoped, and then hashed +pub enum ScopedSelector { + Class(ArbitrarySelector), + Id(ArbitrarySelector), + Tag(ArbitrarySelector), +} + +impl ScopedSelector { + /// Borrow the underlying [ArbitrarySelector] + pub fn as_arbitrary(&self) -> &ArbitrarySelector { + match self { + Self::Class(a) => a, + Self::Id(a) => a, + Self::Tag(a) => a, + } + } + + /// Generate rusty member ident based on selector type and CSS ident + pub fn gen_rusty_ident(&self) -> syn::Ident { + let basic = apply_basic_rusty_member_gen_rules(&self.as_arbitrary().ident); + + let ready = match self { + Self::Class(_) => basic, + Self::Id(_) => { + format!("the{basic}") + } + Self::Tag(_) => { + format!("any{basic}") + } + }; + + syn::parse_str::<syn::Ident>(&ready).expect("BUG: formed ident is not Rust Ident") + } + + /// Construct this from class selector + pub fn from_class(s: &raffia::ast::ClassSelector) -> Self { + let lit = s + .name + .as_literal() + .expect("BUG: class selector is not a literal"); + Self::Class(ArbitrarySelector { + ident: lit.raw.to_string(), + span: lit.span().clone(), + }) + } + + /// Construct this from id selector + pub fn from_id(s: &raffia::ast::IdSelector) -> Self { + let lit = s + .name + .as_literal() + .expect("BUG: id selector is not a literal"); + Self::Id(ArbitrarySelector { + ident: lit.raw.to_string(), + span: lit.span().clone(), + }) + } + + /// Construct this from tagname selector + pub fn from_tag(s: &raffia::ast::TagNameSelector) -> Self { + let lit = s + .name + .name + .as_literal() + .expect("BUG: tag selector is not a literal"); + Self::Tag(ArbitrarySelector { + ident: lit.raw.to_string(), + span: lit.span().clone(), + }) + } +} + +fn apply_basic_rusty_member_gen_rules(source: &str) -> String { + let omit_regex = Regex::new(r"(^\-)|(\-$)|[^a-zA-Z0-9\-\_]") + .expect("BUG: can not build omition regex for rusty member generation"); + + // omit forbidden chars + let cleaned = omit_regex.replace_all(source, "").to_string(); + + // other not-so-obvious rules + let mut target = String::with_capacity(cleaned.len()); + let mut next_uppercase: bool = false; + for (i, c) in cleaned.chars().enumerate() { + // first gidit is prepended with 'n' + if i == 0 && c.is_numeric() { + target.push('n'); + target.push(c); + continue; + } + // dash is omitted and next is uppercase if may be + if c == '-' { + next_uppercase = true; + continue; + } + target.push(if next_uppercase { + next_uppercase = false; + c.to_ascii_uppercase() + } else { + c + }); + } + target +} + +#[cfg(test)] +mod test { + use std::collections::HashSet; + + use syn::Ident; + + use crate::{ + config::SabryHashConfig, + scoper::{hash::ScopeHash, HashedScope}, + }; + + use super::ArbitraryScope; + + #[test] + fn scope_hash_codegen() { + let code = + ".cls1{color:red; &-dark{color: black;} #id1 {color:green;} div {color:blue;}} .cls3#id2{color: black;}"; + let hash = ScopeHash::test_init("F2kf8nMs".into()); + + let expect_code = ".F2kf8nMs.cls1{color:red; &-dark{color: black;} #F2kf8nMs-id1 {color:green;} .F2kf8nMs div {color:blue;}} .F2kf8nMs.cls3#F2kf8nMs-id2{color: black;}"; + let expect_selector_htmls = HashSet::from([ + "F2kf8nMs cls1".to_string(), + "F2kf8nMs-id1".to_string(), + "F2kf8nMs cls3".to_string(), + "F2kf8nMs-id2".to_string(), + "".to_string(), // comes from `div` which has no html hashed code, still want to check presense + ]); + + let scope = ArbitraryScope::from_source( + raffia::Syntax::Scss, + syn::parse_str("scope1").unwrap(), + code, + ) + .unwrap(); + let scope = HashedScope::new(hash, scope).unwrap(); + let scope_selector_htmls = scope + .hashed_selectors + .iter() + .map(|hs| hs.html_ident.clone().unwrap_or_default()) + .collect::<HashSet<_>>(); + + // check that original is untouched + assert_eq!(code, scope.original_scope.adapter().source()); + // check that hashed matches what we expect + assert_eq!(expect_code, scope.hashed_code); + // check that HTML selector hashed code matches what we expect + assert_eq!(expect_selector_htmls, scope_selector_htmls); + } + + #[test] + fn rusty_idents() { + let code = " +.cls-1{ + color:red; + &-dark{ + color: black; + } + #id-1 { + color:green; + } + .-txt-of { + color:blue; + } +} +.-c_ls3#4id{ + color: black; +}"; + let expect_ident_names = HashSet::from([ + "cls1".to_string(), + "theid1".to_string(), + "c_ls3".to_string(), + "then4id".to_string(), + "txtOf".to_string(), + ]); + + let hash_cfg = SabryHashConfig::default(); + let scope = ArbitraryScope::from_source( + raffia::Syntax::Scss, + syn::parse_str::<Ident>("scope2oiej").unwrap(), + code, + ) + .unwrap() + .hashed(&hash_cfg) + .unwrap(); + + let sels = scope + .hashed_selectors + .iter() + .map(|s| s.sel.gen_rusty_ident()) + .map(|i| i.to_string()) + .collect::<HashSet<_>>(); + + assert_eq!(expect_ident_names, sels); + } +} diff --git a/sabry_intrnl/src/syntax/mod.rs b/sabry_intrnl/src/syntax/mod.rs new file mode 100644 index 0000000..a52d7d6 --- /dev/null +++ b/sabry_intrnl/src/syntax/mod.rs @@ -0,0 +1,226 @@ +use raffia::{ + ast::{ + ClassSelector, CompoundSelector, IdSelector, NestingSelector, SimpleSelector, Statement, + Stylesheet, TypeSelector, + }, + ParserBuilder, Syntax, +}; + +/// Convenience wrapper for [Stylesheet] +pub struct StylesheetAdapter<'s> { + pub syntax: Syntax, + source: &'s str, + stylesheet: Stylesheet<'s>, +} + +impl<'s> StylesheetAdapter<'s> { + pub fn new(source: &'s str, syntax: Syntax) -> Result<Self, raffia::error::Error> { + Ok(Self { + stylesheet: ParserBuilder::new(source) + .ignore_comments() + .syntax(syntax) + .build() + .parse()?, + syntax, + source, + }) + } + + pub fn source(&self) -> &str { + self.source + } + + pub fn selectors(&self) -> Vec<CompoundSelector<'s>> { + Self::selectors_of(self.stylesheet.statements.iter().cloned()).collect() + } + + pub fn class_selectors(&self) -> Vec<ClassSelector<'s>> { + self.selectors_by(|c| c.as_class().cloned()) + } + + pub fn id_selectors(&self) -> Vec<IdSelector<'s>> { + self.selectors_by(|c| c.as_id().cloned()) + } + + pub fn type_selectors(&self) -> Vec<TypeSelector<'s>> { + self.selectors_by(|c| c.as_type().cloned()) + } + + pub fn nesting_selectors(&self) -> Vec<NestingSelector<'s>> { + self.selectors_by(|c| c.as_nesting().cloned()) + } + + /// Return collected [Vec] of owned values modulo `T`, filtered by `F`. + /// + /// This is preferred way to apply custom filtering on selectors over + /// `selectors().iter().filter_map()` + /// as it does not allocate intermediate vector + pub fn selectors_by<T, F>(&self, form: F) -> Vec<T> + where + F: FnMut(SimpleSelector<'s>) -> Option<T>, + { + Self::selectors_of(self.stylesheet.statements.iter().cloned()) + .flat_map(|cs| cs.children) + .filter_map(form) + .collect() + } + + fn selectors_of( + c: impl Iterator<Item = Statement<'s>>, + ) -> impl Iterator<Item = CompoundSelector<'s>> { + // Hello. Its Dan. + // Im not proud of this, + // but more effective implementation + // was SO unreadable and SO infected with lifetimes + // I suck at those things + + // For everyone trying to make this MORE OPTIMAL: + // increment the hour-counter and post your name here: + // 4 - Danik + // 5 - Yiffy + // 8 - Danik + c.filter_map(|s| s.as_qualified_rule().cloned()) + .flat_map(|q| { + let thissels = q + .selector + .selectors + .iter() + .flat_map(|sel| &sel.children) + .filter_map(|sc| sc.as_compound_selector()) + .cloned(); + + let blockstmt = q.block.statements.iter().cloned(); + Self::selectors_of(blockstmt) + .chain(thissels) + .collect::<Vec<_>>() + }) + } +} + +#[cfg(test)] +mod test { + use std::collections::HashSet; + + use raffia::Spanned; + + use super::StylesheetAdapter; + + #[test] + fn sels() { + let source_scss = " +.r1{ + .r2.r3 { + color: red; + } + &-rod { + color: red; + &[value] { + color: red; + } + } +} +div#id2 { + & > span.seled { + color: red; + & + ul#id2[attr] { + color: red; + } + & + .uled[attr] { + color: red; + } + } + &::after{ + color: red; + } +} + "; + let source_sass = " +.r1 + .r2.r3 + color: red + &-rod + color: red + &[value] + color: red +div#id2 + & > span.seled + color: red + & + ul#id2[attr] + color: red + & + .uled[attr] + color: red + &::after + color: red + "; + let expect_classes = HashSet::from(["r2", "r3", "r1", "uled", "seled"]); + let expect_ids = HashSet::from(["id2", "id2"]); + let expect_tags = HashSet::from(["ul", "div", "span"]); + + //scss + let adp = StylesheetAdapter::new(source_scss, raffia::Syntax::Scss).unwrap(); + + let classes = adp + .class_selectors() + .iter() + .filter_map(|c| c.name.as_literal().map(|l| l.raw)) + .collect::<HashSet<_>>(); + + let ids = adp + .id_selectors() + .iter() + .filter_map(|i| i.name.as_literal().map(|l| l.raw)) + .collect::<HashSet<_>>(); + + let tags = adp + .type_selectors() + .iter() + .filter_map(|t| t.as_tag_name()) + .filter_map(|t| t.name.name.as_literal().map(|l| l.raw)) + .collect::<HashSet<_>>(); + + assert_eq!(expect_classes, classes); + assert_eq!(expect_ids, ids); + assert_eq!(expect_tags, tags); + + //sass + let adp = StylesheetAdapter::new(source_sass, raffia::Syntax::Sass).unwrap(); + + let classes = adp + .class_selectors() + .iter() + .filter_map(|c| c.name.as_literal().map(|l| l.raw)) + .collect::<HashSet<_>>(); + + let ids = adp + .id_selectors() + .iter() + .filter_map(|i| i.name.as_literal().map(|l| l.raw)) + .collect::<HashSet<_>>(); + + let tags = adp + .type_selectors() + .iter() + .filter_map(|t| t.as_tag_name()) + .filter_map(|t| t.name.name.as_literal().map(|l| l.raw)) + .collect::<HashSet<_>>(); + + assert_eq!(expect_classes, classes); + assert_eq!(expect_ids, ids); + assert_eq!(expect_tags, tags); + } + + #[test] + fn rename_class() { + let scss = ".cls1{color:red; .cls2{color:green;}}"; + let newname = "cls203-jg7ihgjhftyfhjh"; + let expect = ".cls1{color:red; .cls203-jg7ihgjhftyfhjh{color:green;}}"; + + let adp = StylesheetAdapter::new(scss, raffia::Syntax::Scss).unwrap(); + let classes = adp.class_selectors(); + let target_class = classes[0].clone(); + + let span = target_class.name.span(); + let renamed = format!("{}{}{}", &scss[..span.start], newname, &scss[span.end..]); + assert_eq!(renamed, expect); + } +} diff --git a/sabry_procmacro/Cargo.toml b/sabry_procmacro/Cargo.toml new file mode 100644 index 0000000..1ca3d35 --- /dev/null +++ b/sabry_procmacro/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "sabry_procmacro" +description = "Sabry proc-macro declarations" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true + +[lib] +proc-macro = true + +[dependencies] +sabry_procmacro_impl = {workspace = true} + +[features] +sass = [ + "sabry_procmacro_impl/sass" +] +scss = [ + "sabry_procmacro_impl/scss" +] diff --git a/sabry_procmacro/src/lib.rs b/sabry_procmacro/src/lib.rs new file mode 100644 index 0000000..d5ede42 --- /dev/null +++ b/sabry_procmacro/src/lib.rs @@ -0,0 +1,117 @@ +use proc_macro::TokenStream; +use sabry_procmacro_impl::impls::{ + sassy::sassy_macro_impl, styly::styly_macro_impl, usey::usey_macro_impl, +}; + +/// Macro that makes sass code rusty. +/// +/// Accepts arbitrary (yet valid) sass(wip)/scss code and +/// makes it available as rust macro +/// +/// ## Usage +/// +/// ```ignore +/// sassy!(scssmodule { +/// /* SCSS */ +/// }); +/// sassy!(sassmodule:sass { +/// /* SASS (WIP) */ +/// }); +/// sassy!(scssmod2:scss { +/// /* SCSS */ +/// }); +/// ``` +/// Or read code from file +/// ```ignore +/// sassy!(filemodule "src/styles/a.scss"); +/// sassy!(filemodule:sass "src/styles/b.sass"); +/// ``` +/// +/// \[SCSS syntax requires 'scss' feature\] +/// \[SASS syntax requires 'sass' feature (WIP)\] +/// +#[proc_macro] +pub fn sassy(input: TokenStream) -> TokenStream { + sassy_macro_impl(input.into()).into() +} + +/// Macro that brings sass code into app +/// +/// Accepts arbitrary (yet valid) sass(wip)/scss code +/// and creates public/private module with scoped(hashed) +/// selector members. +/// +/// Feel free to use it with qualified path, but dont alias it with `use sabry::styly as whetever`. +/// +/// ## Usage +/// +/// Write style in rusty code (rust-analyzer wont autocomplete your scope members) +/// ```ignore +/// styly!(scope1 { +/// /* SCSS */ +/// }); +/// styly!(scope2:sass { +/// /* SASS (WIP) */ +/// }); +/// styly!(scope3:scss { +/// /* SCSS */ +/// }); +/// styly!(pub scope4 { +/// /* SCSS which is available as <mod>::scope4 */ +/// }); +/// styly!(const scope5 { +/// /* SCSS which wount be bundled, instead SCOPE5_STYLE constant is introduced with CSS */ +/// }); +/// styly!(pub const scope6 { +/// /* SCSS, which is like 'const scope5' but publically available like 'pub scope4'*/ +/// }); +/// ``` +/// Or use SCSS file and get syntax highlighting and autocompletion: +/// ```ignore +/// styly!(penguin "src/components/penguin.scss"); +/// styly!(pub page "src/routes/page.scss"); +/// styly!(pub const embed:sass "src/embedded.sass"); +/// ``` +/// +/// \[SCSS syntax requires 'scss' feature\] +/// \[SASS syntax requires 'sass' feature (WIP)\] +/// +/// ### About `const` scope +/// +/// Const-flavored styly macro will generate SCOPENAME_CSS constant available in runtime, which contains +/// compiled CSS. Note, that only possibility to `@use` something - is to have sabry as build time, so that const styly +/// macro could read all modules. +/// +/// ### Not meant to be used, yet still available +/// +/// ```ignore +/// styly!(notascope { +/// /* produces machine-readable invalid rust code */ +/// }#); +/// ``` +#[proc_macro] +pub fn styly(input: TokenStream) -> TokenStream { + styly_macro_impl(input.into()).into() +} + +/// Macro that brings external sass code into app +/// +/// Intended to be used in tandem with `sabry::buildy` function in `build.rs` file +/// +/// ## Usage +/// +/// ```ignore +/// use sharedstyles::tokens; +/// use brandstyle::tokens as brand_tokens; +/// +/// usey!( +/// brandstyle::theme!(), +/// tokens!(), +/// brand_tokens!(), +/// ); +/// ``` +/// +#[proc_macro] +pub fn usey(input: TokenStream) -> TokenStream { + usey_macro_impl(input.into()).into() +} diff --git a/sabry_procmacro_impl/Cargo.toml b/sabry_procmacro_impl/Cargo.toml new file mode 100644 index 0000000..c5e0e5b --- /dev/null +++ b/sabry_procmacro_impl/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "sabry_procmacro_impl" +description = "Sabry proc-macro internals reusable outside of proc-macro context" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true + +[dependencies] +sabry_intrnl = {workspace = true} + +proc-macro2 = {workspace = true, features = ["span-locations"]} +syn = {workspace = true, features = ["parsing"]} +quote = {workspace = true} +regex = {workspace = true} + +raffia = {workspace = true} + +[features] +sass = [ + "sabry_intrnl/sass" +] +scss = [ + "sabry_intrnl/scss" +] diff --git a/sabry_procmacro_impl/src/impls/mod.rs b/sabry_procmacro_impl/src/impls/mod.rs new file mode 100644 index 0000000..e5f9cc5 --- /dev/null +++ b/sabry_procmacro_impl/src/impls/mod.rs @@ -0,0 +1,202 @@ +use std::{fmt::Debug, fs}; + +use proc_macro2::{Span, TokenStream}; +use quote::{quote, ToTokens, TokenStreamExt}; +use sabry_intrnl::compiler::CompilerSyntax; +use syn::{braced, parse::Parse, spanned::Spanned, Ident, LitStr, Token}; + +pub mod sassy; +pub mod styly; +pub mod usey; + +/// Macro input for arbitrary style code +/// +/// Also supports string literal token instead of braces, +/// in which mode will look for relative file +/// +/// Does not work nice with rust-analyzer though +#[derive(Clone, Debug)] +pub struct ArbitraryStyleBlock { + code: String, + span: Span, +} + +impl ArbitraryStyleBlock { + pub fn span(&self) -> Span { + self.span + } + + pub fn code(&self) -> &str { + &self.code + } +} + +impl Parse for ArbitraryStyleBlock { + fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { + let (code, span) = if let Ok(path_tok) = input.parse::<LitStr>() { + let path = path_tok.value(); + + let iofile = match fs::read(&path) { + Ok(bf) => bf, + Err(_) => return Err(syn::Error::new(path_tok.span(), format!("Could not read file '{path}'. Perhaps its relative? Thats not currently supported :("))) + }; + let code = String::from_utf8_lossy(&iofile).to_string(); + + (code, path_tok.span()) + } else { + // Does not work on stable! + // We're on nightly though + // So what? + // Then is works. + let _s; + braced!(_s in input); + let stream = _s.parse::<TokenStream>()?; + + let c = match stream.span().source_text() { + Some(stx) => stx, + // TODO: rust-analyzer does fall into this even if all is fine + None => "".to_string(), //return Err(syn::Error::new(stream.span(), "Source code expected")), + }; + + (c, stream.span()) + }; + + Ok(Self { code, span }) + } +} + +#[allow(clippy::to_string_trait_impl)] +impl ToString for ArbitraryStyleBlock { + fn to_string(&self) -> String { + self.code.clone() + } +} + +#[derive(Clone, Copy)] +pub enum ArbitraryStyleSyntax { + #[cfg(feature = "scss")] + Scss, + #[cfg(feature = "sass")] + Sass, +} + +impl From<ArbitraryStyleSyntax> for CompilerSyntax { + fn from(value: ArbitraryStyleSyntax) -> Self { + match value { + #[cfg(feature = "sass")] + ArbitraryStyleSyntax::Sass => Self::Sass, + #[cfg(feature = "scss")] + ArbitraryStyleSyntax::Scss => Self::Scss, + } + } +} + +impl ToTokens for ArbitraryStyleSyntax { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + #[cfg(feature = "sass")] + Self::Sass => tokens.append_all(quote! {"sass"}), + #[cfg(feature = "scss")] + Self::Scss => tokens.append_all(quote! {"scss"}), + } + } +} + +impl Parse for ArbitraryStyleSyntax { + fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { + match input.parse::<Token![:]>() { + Ok(_) => { /* Syntax is set */ } + Err(_) => { + /* Syntax is not set, falling to default */ + return Ok(Self::default()); + } + } + let ident = input.parse::<Ident>()?; + + match ident.to_string().as_str() { + #[cfg(feature = "sass")] + "sass" => Ok(Self::Sass), + #[cfg(feature = "scss")] + "scss" => Ok(Self::Scss), + _ => Err(syn::Error::new( + ident.span(), + format!( + "Available syntax are `sass` (WIP) and `scss`, each of them requires feature flag. Omit to use default {:?} syntax", + Self::default() + ), + )), + } + } +} + +impl Debug for ArbitraryStyleSyntax { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let name = match self { + #[cfg(feature = "sass")] + Self::Sass => "sass", + #[cfg(feature = "scss")] + Self::Scss => "scss", + }; + write!(f, "{name}") + } +} + +impl Default for ArbitraryStyleSyntax { + #[cfg(feature = "scss")] + fn default() -> Self { + Self::Scss + } + + #[cfg(all(feature = "sass", not(feature = "scss")))] + fn default() -> Self { + Self::Sass + } +} + +impl From<ArbitraryStyleSyntax> for raffia::Syntax { + fn from(value: ArbitraryStyleSyntax) -> Self { + match value { + #[cfg(feature = "sass")] + ArbitraryStyleSyntax::Sass => Self::Sass, + #[cfg(feature = "scss")] + ArbitraryStyleSyntax::Scss => Self::Scss, + } + } +} + +#[cfg(test)] +mod test { + #[cfg(feature = "sass")] + #[test] + fn arbitrary_style_block_sass() { + use super::ArbitraryStyleBlock; + + let code = "#a + co:d + .sel + di: pi + .sel,div > sel + f: \"into\""; + let braced_code = format!("{{{code}}}"); + let block = syn::parse_str::<ArbitraryStyleBlock>(&braced_code).unwrap(); + + assert_eq!(code, block.code); + } + + #[cfg(feature = "scss")] + #[test] + fn arbitrary_style_block_scss() { + use super::ArbitraryStyleBlock; + + let code = "#a { + c:r; + } + .b.c{ + c:\"into\"; + }"; + let braced_code = format!("{{{code}}}"); + let block = syn::parse_str::<ArbitraryStyleBlock>(&braced_code).unwrap(); + + assert_eq!(code, block.code) + } +} diff --git a/sabry_procmacro_impl/src/impls/sassy.rs b/sabry_procmacro_impl/src/impls/sassy.rs new file mode 100644 index 0000000..6221449 --- /dev/null +++ b/sabry_procmacro_impl/src/impls/sassy.rs @@ -0,0 +1,68 @@ +use proc_macro2::TokenStream; +use quote::quote; +use syn::{parse::Parse, Ident}; + +use super::{ArbitraryStyleBlock, ArbitraryStyleSyntax}; + +/// Syntax: +/// `#ident(:$syntax)? { $code }` +/// +/// `$syntax`: sass/scss +/// +/// `$code`: intended to be valid based on $syntax +pub fn sassy_macro_impl(input: TokenStream) -> TokenStream { + let MacroSyntax { + ident, + syntax: mode, + code, + } = match syn::parse2::<MacroSyntax>(input) { + Ok(m) => m, + Err(e) => return e.to_compile_error(), + }; + + let sourcesass = code.to_string(); + let identname = ident.to_string(); + let macro_doc = format!("Arbitrary {:?} code declared with `sassy!`. Pretty usable in tandem with `usey!` and `magic()` at build time", mode); + + quote! { + #[doc = #macro_doc] + #[macro_export] + macro_rules! #ident { + () => {#sourcesass}; + (module) => {#identname}; + (syntax) => {#mode}; + } + } +} + +pub struct MacroSyntax { + ident: Ident, + syntax: ArbitraryStyleSyntax, + code: ArbitraryStyleBlock, +} + +impl Parse for MacroSyntax { + fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { + #[cfg(feature = "sass")] + use regex::Regex; + + let ident = input.parse::<Ident>()?; + let mode = input.parse::<ArbitraryStyleSyntax>()?; + let mut code = input.parse::<ArbitraryStyleBlock>()?; + + // this is because of how parsing works. Need to find more elegant way though + // TODO: find a more elegant way + code.code = Regex::new("\n ").expect("BUG: failed to build regex for indentation SASS").replace_all(&code.code, "\n").to_string(); + + Ok(Self { + ident, + syntax: mode, + code, + }) + } +} + +#[cfg(test)] +mod test { + +} diff --git a/sabry_procmacro_impl/src/impls/styly.rs b/sabry_procmacro_impl/src/impls/styly.rs new file mode 100644 index 0000000..9d6b0ed --- /dev/null +++ b/sabry_procmacro_impl/src/impls/styly.rs @@ -0,0 +1,209 @@ +use proc_macro2::{Span, TokenStream}; +use quote::quote; +use sabry_intrnl::{ + compiler::CompilerAdapter, + config::SabryConfig, + scoper::{ArbitraryScope, ScopedSelector}, +}; +use syn::{parse::Parse, Ident, Token}; + +use super::{ArbitraryStyleBlock, ArbitraryStyleSyntax}; + +/// Syntax: +/// `pub? #ident(:$syntax)? { $code } \#?` +/// +/// `$syntax`: sass/scss +/// +/// `$code`: intended to be valid based on $syntax +/// +/// `pub` modifier makes scope public +/// +/// `const` modifier completely changes the behaviour of styling, and +/// makes CSS exposed as constant +/// +/// `#` shebang generates machine-readable and well-parsible but invalid rust code for building purposes +/// instead of scope module. +/// +/// The machine-readable output may also be forced by use `machine_readable: true` arg on `parse_macro_syntax` function +/// without modifying tokenstream +pub fn styly_macro_impl(input: TokenStream) -> TokenStream { + let config = match SabryConfig::require() { + Ok(c) => c, + Err(e) => { + return syn::Error::new( + Span::call_site(), + format!( + "Could not read sabry configuration required by this macro: {:?}", + e + ), + ) + .to_compile_error() + } + }; + let ms = match parse_macro_syntax(input) { + Ok(ms) => ms, + Err(e) => return e.to_compile_error(), + }; + + let scope = match ArbitraryScope::from_source(ms.syntax.into(), ms.scope.clone(), &ms.code.code) + { + Ok(s) => match s.hashed(&config.hash) { + Ok(hs) => Ok(hs), + Err(e) => Err(e), + }, + Err(e) => Err(e), + }; + let scope = match scope { + Ok(s) => s, + Err(e) => { + return syn::Error::new( + Span::call_site(), + format!("Could not generate scope: {:?}", e), + ) + .to_compile_error() + } + }; + + match ms.generator { + ScopeGenerator::Module { public, constant } => { + let scope_hash = scope.hash.as_str(); + let scope_ident = scope.original_scope.name; + let scope_wrapper_ident = + syn::parse_str::<Ident>(&scope_ident.to_string().to_uppercase()) + .expect("BUG: We just converted valid Ident to string and uppercased"); + let scope_vis = if public { + quote! {pub} + } else { + quote! {} + }; + + let scope_members = scope + .hashed_selectors + .iter() + .filter_map(|hs| { + hs.html_ident.clone().map(|html| { + let name = match hs.sel { + ScopedSelector::Class(_) => "class", + ScopedSelector::Id(_) => "id", + ScopedSelector::Tag(_) => "tagname", + }; + + (name, hs.sel.gen_rusty_ident(), html, hs.css_ident.clone()) + }) + }) + .map(|(name, ident, html, css)| { + let docs = format!("'{}' {}. CSS selector '{}'", ident, name, css); + quote! { + #[doc = #docs] + #[allow(non_upper_case_globals)] + pub const #ident : &str = #html ; + } + }); + + let mod_docs = format!( + "'{}' style scope. The wrapper class for scoped tagnames is {}", + &scope_ident, &scope_wrapper_ident + ); + let wrp_docs = format!("wrapper class for '{}' scope. If you have any tagname selectors - they should live as children of element with this class applied.", &scope_ident); + + if constant { + let compiler = CompilerAdapter::new(config.clone()); + let css = match compiler.compile_module(ms.syntax.into(), &ms.code.code) { + Ok(c) => c, + Err(e) => { + return syn::Error::new( + ms.code.span, + format!("Could not compile const inline: {e:?}"), + ) + .to_compile_error() + } + }; + + let const_docs = format!("The compiled CSS style for {} scope", &scope_ident); + let const_wrapper_ident = syn::parse_str::<Ident>( + format!("{}_CSS", &scope_ident.to_string().to_uppercase()).as_str(), + ) + .expect("BUG: We just converted valid Ident to string and uppercased"); + + quote! { + #[doc = #const_docs] + #scope_vis const #const_wrapper_ident: &str = #css ; + #[doc = #wrp_docs] + #scope_vis const #scope_wrapper_ident : &str = #scope_hash ; + #[doc = #mod_docs] + #scope_vis mod #scope_ident { + #(#scope_members)* + } + } + } else { + quote! { + #[doc = #wrp_docs] + #scope_vis const #scope_wrapper_ident : &str = #scope_hash ; + #[doc = #mod_docs] + #scope_vis mod #scope_ident { + #(#scope_members)* + } + } + } + } + ScopeGenerator::MachineReadable => { + quote! {} + } + } +} + +// reusable function, that does not return tokenstream for machine-processing at build time +pub fn parse_macro_syntax(input: TokenStream) -> Result<MacroSyntax, syn::Error> { + syn::parse2::<MacroSyntax>(input) +} + +#[derive(Debug)] +pub enum ScopeGenerator { + Module { public: bool, constant: bool }, + MachineReadable, +} + +impl Parse for ScopeGenerator { + fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { + let public = input.parse::<Token![pub]>().is_ok(); + let constant = input.parse::<Token![const]>().is_ok(); + + // would be nice to implement compile-time CSS compilation to const + // with `const` modifier, so I'll leave it this way for now + let this = Self::Module { public, constant }; + + Ok(this) + } +} + +#[derive(Debug)] +pub struct MacroSyntax { + /// The way macro should be expanded + pub generator: ScopeGenerator, + /// Scope identifier + pub scope: Ident, + /// Used stytax + pub syntax: ArbitraryStyleSyntax, + /// Style code, either from rust or read from file + pub code: ArbitraryStyleBlock, +} + +impl Parse for MacroSyntax { + fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { + let mut generator = input.parse::<ScopeGenerator>()?; + let scope = input.parse::<Ident>()?; + let syntax = input.parse::<ArbitraryStyleSyntax>()?; + let code = input.parse::<ArbitraryStyleBlock>()?; + + if input.parse::<Token![#]>().is_ok() { + generator = ScopeGenerator::MachineReadable + } + + Ok(Self { + generator, + scope, + syntax, + code, + }) + } +} diff --git a/sabry_procmacro_impl/src/impls/usey.rs b/sabry_procmacro_impl/src/impls/usey.rs new file mode 100644 index 0000000..730bb4e --- /dev/null +++ b/sabry_procmacro_impl/src/impls/usey.rs @@ -0,0 +1,71 @@ +use proc_macro2::TokenStream; +use quote::quote; +use syn::{parse::Parse, punctuated::Punctuated, Macro, Token}; + +/// Syntax: +/// `#(pub? #macro,)*` +pub fn usey_macro_impl(input: TokenStream) -> TokenStream { + let MacroSyntax { stylecalls } = match syn::parse2(input) { + Ok(ms) => ms, + Err(e) => return e.to_compile_error(), + }; + + let stylecall_pairs = stylecalls + .iter() + .map(|c| c.to_contract_pair("__sabry_pub_module")); + + quote! { + vec![ + #(#stylecall_pairs,)* + ] + } +} + +#[derive(Clone)] +pub struct StyleCall { + vis_pub: bool, + call: Macro, +} + +impl StyleCall { + pub fn to_contract_pair(&self, pub_module: &str) -> TokenStream { + let call_code = &self.call; + let call_path = &self.call.path; + let call_bang = &self.call.bang_token; + // the following calls are expected by macro genereted by `sassy!` + let call_syntax = quote! {#call_path #call_bang (syntax)}; + let call_file = quote! {#call_path #call_bang (module)}; + + if self.vis_pub { + quote! { + (format!("{}.{}", #pub_module, #call_syntax), #call_code .to_string()) + } + } else { + quote! { + (format!("{}.{}", #call_file, #call_syntax), #call_code .to_string()) + } + } + } +} + +impl Parse for StyleCall { + fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { + let vis_pub = input.parse::<Token![pub]>().is_ok(); + let call = input.parse::<Macro>()?; + + Ok(Self { vis_pub, call }) + } +} + +pub struct MacroSyntax { + stylecalls: Vec<StyleCall>, +} + +impl Parse for MacroSyntax { + fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { + let calls = Punctuated::<StyleCall, Token![,]>::parse_separated_nonempty(input)?; + + let stylecalls = calls.iter().cloned().collect(); + Ok(Self { stylecalls }) + } +} diff --git a/sabry_procmacro_impl/src/lib.rs b/sabry_procmacro_impl/src/lib.rs new file mode 100644 index 0000000..daad739 --- /dev/null +++ b/sabry_procmacro_impl/src/lib.rs @@ -0,0 +1,4 @@ +// Moving this to separate crate, cuz I don't wanna to reimplement that parsing again for build magic +// Also, because I can. + +pub mod impls; diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..71317c6 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,6 @@ +#![doc = include_str!("../README.md")] + +#[cfg(feature = "build")] +pub use sabry_build::*; +#[cfg(feature = "procmacro")] +pub use sabry_procmacro::*;