From 8c56a0e5aa025938ce67ede3251d44c5009e4dbc Mon Sep 17 00:00:00 2001 From: Connor K Date: Fri, 31 May 2024 06:29:26 -0400 Subject: [PATCH 1/6] Add support for Fuse.js search format (#2507) * inital "just barely works" Fuse.js support * implement FuseJavascript; refactor index_for_lang * support search config * move fuse index building to it's own file * update doc of Search.index_format * update config docs * update search documentation * use &str where possible * use libs::serde_json remmeber to commit Cargo.lock * move extension logic to IndexFormat * move the entire filename logic inside IndexFormat * move elasticlunr to it's own module * only create elasticlunr.min.js if we're actually using elasticlunr * move ELASTICLUNR_JS to elasticlunr.js * hide the details of search's submodules * optionally include path * explain include_path better * remove references to stork * replace if with match * support include_description * specify "permalink" * move body cleaning and truncation to a function * update truncate_content_length docs to specify *code points* --- Cargo.lock | 161 +++++------ components/config/src/config/search.rs | 21 +- components/search/Cargo.toml | 1 + components/search/src/elasticlunr.rs | 236 ++++++++++++++++ components/search/src/fuse.rs | 76 +++++ components/search/src/lib.rs | 261 ++---------------- components/site/src/lib.rs | 36 ++- components/utils/src/fs.rs | 5 +- docs/content/documentation/content/search.md | 39 ++- .../getting-started/configuration.md | 8 +- 10 files changed, 496 insertions(+), 348 deletions(-) create mode 100644 components/search/src/elasticlunr.rs create mode 100644 components/search/src/fuse.rs diff --git a/Cargo.lock b/Cargo.lock index fc1cfce7e5..44eb1db4a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -150,9 +150,9 @@ checksum = "70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e" [[package]] name = "anyhow" -version = "1.0.83" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "arbitrary" @@ -168,7 +168,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.65", ] [[package]] @@ -402,9 +402,9 @@ checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" [[package]] name = "bytemuck" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" +checksum = "78834c15cb5d5efe3452d58b1e8ba890dd62d21907f867f383358198e56ebca5" [[package]] name = "byteorder" @@ -436,9 +436,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "camino" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" dependencies = [ "serde", ] @@ -467,9 +467,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" dependencies = [ "jobserver", "libc", @@ -618,7 +618,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.65", ] [[package]] @@ -765,9 +765,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if 1.0.0", ] @@ -802,9 +802,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -851,7 +851,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.61", + "syn 2.0.65", ] [[package]] @@ -924,9 +924,9 @@ dependencies = [ [[package]] name = "deunicode" -version = "1.4.4" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322ef0094744e63628e6f0eb2295517f79276a5b342a4c2ff3042566ca181d4e" +checksum = "339544cc9e2c4dc3fc7149fd630c5f22263a4fdf18a98afd0075784968b5cf00" [[package]] name = "digest" @@ -955,7 +955,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.65", ] [[package]] @@ -981,9 +981,9 @@ dependencies = [ [[package]] name = "either" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] name = "elasticlunr-rs" @@ -1367,8 +1367,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if 1.0.0", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -1429,18 +1431,19 @@ dependencies = [ [[package]] name = "grass" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b89786a806d5b192cf4e573f9831c847a455a142d000c922bdfc1e5edad14303" +checksum = "a46def7216d331efa51a6aa796ef777bfdfe9605378382827a553344b7e5eefc" dependencies = [ + "getrandom 0.2.15", "grass_compiler", ] [[package]] name = "grass_compiler" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cf7d155dd7cef20195016d01005033a5521aad307033f0f8e8bf0a02f5f7554" +checksum = "f39216c1843182f78541276fec96f88406861f16aa19cc9f8add70f8e67b7577" dependencies = [ "codemap", "indexmap 2.2.6", @@ -1536,7 +1539,7 @@ dependencies = [ "markup5ever", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.65", ] [[package]] @@ -1782,9 +1785,9 @@ dependencies = [ [[package]] name = "insta" -version = "1.38.0" +version = "1.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eab73f58e59ca6526037208f0e98851159ec1633cf17b6cd2e1f2c3fd5d53cc" +checksum = "810ae6042d48e2c9e9215043563a58a80b877bc863228a74cf10c49d4620a6f5" dependencies = [ "console 0.15.8", "lazy_static", @@ -1800,7 +1803,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.65", ] [[package]] @@ -1983,9 +1986,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.154" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libfuzzer-sys" @@ -2042,7 +2045,7 @@ dependencies = [ "tera", "termcolor", "time", - "toml 0.8.12", + "toml 0.8.13", "unic-langid", "unicode-segmentation", "url", @@ -2062,9 +2065,9 @@ dependencies = [ [[package]] name = "lightningcss" -version = "1.0.0-alpha.55" +version = "1.0.0-alpha.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bd5bed3814fb631bfc1e24c2be6f7e86a9837c660909acab79a38374dcb8798" +checksum = "668e9f1774a4dda9e2233ad0f78c6987878bcf4201d2085bc3517a7f84d0ee92" dependencies = [ "ahash 0.8.11", "bitflags 2.5.0", @@ -2074,6 +2077,7 @@ dependencies = [ "dashmap", "data-encoding", "getrandom 0.2.15", + "indexmap 2.2.6", "itertools 0.10.5", "lazy_static", "parcel_selectors", @@ -2267,9 +2271,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" @@ -2443,9 +2447,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" dependencies = [ "adler", "simd-adler32", @@ -2694,7 +2698,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.65", ] [[package]] @@ -2790,9 +2794,9 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "open" -version = "5.1.2" +version = "5.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "449f0ff855d85ddbf1edd5b646d65249ead3f5e422aaa86b7d2d0b049b103e32" +checksum = "2eb49fbd5616580e9974662cb96a3463da4476e649a7e4b258df0de065db0657" dependencies = [ "is-wsl", "libc", @@ -2822,7 +2826,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.65", ] [[package]] @@ -2857,9 +2861,9 @@ checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4" [[package]] name = "parcel_selectors" -version = "0.26.4" +version = "0.26.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d74befe2d076330d9a58bf9ca2da424568724ab278adf15fb5718253133887" +checksum = "ce9c47a67c66fee4a5a42756f9784d92941bd0ab2b653539a9e90521a44b66f0" dependencies = [ "bitflags 2.5.0", "cssparser", @@ -2985,7 +2989,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.65", ] [[package]] @@ -3068,7 +3072,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.65", ] [[package]] @@ -3178,9 +3182,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" dependencies = [ "unicode-ident", ] @@ -3201,7 +3205,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd" dependencies = [ "quote", - "syn 2.0.61", + "syn 2.0.65", ] [[package]] @@ -3749,6 +3753,7 @@ dependencies = [ "content", "errors", "libs", + "serde", ] [[package]] @@ -3785,22 +3790,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.201" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" +checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.201" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" +checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.65", ] [[package]] @@ -3817,9 +3822,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" dependencies = [ "serde", ] @@ -4056,9 +4061,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.61" +version = "2.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" +checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" dependencies = [ "proc-macro2", "quote", @@ -4123,7 +4128,7 @@ dependencies = [ "cfg-expr", "heck 0.5.0", "pkg-config", - "toml 0.8.12", + "toml 0.8.13", "version-compare", ] @@ -4237,7 +4242,7 @@ dependencies = [ "cfg-if 1.0.0", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.65", ] [[package]] @@ -4248,7 +4253,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.65", "test-case-core", ] @@ -4260,22 +4265,22 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.65", ] [[package]] @@ -4405,9 +4410,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.12" +version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" dependencies = [ "serde", "serde_spanned", @@ -4417,18 +4422,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.12" +version = "0.22.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" +checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" dependencies = [ "indexmap 2.2.6", "serde", @@ -4503,18 +4508,18 @@ checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" [[package]] name = "unic-langid" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238722e6d794ed130f91f4ea33e01fcff4f188d92337a21297892521c72df516" +checksum = "23dd9d1e72a73b25e07123a80776aae3e7b0ec461ef94f9151eed6ec88005a44" dependencies = [ "unic-langid-impl", ] [[package]] name = "unic-langid-impl" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd55a2063fdea4ef1f8633243a7b0524cbeef1905ae04c31a1c9b9775c55bc6" +checksum = "0a5422c1f65949306c99240b81de9f3f15929f5a8bfe05bb44b034cc8bf593e5" dependencies = [ "tinystr", ] @@ -4722,7 +4727,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.65", "wasm-bindgen-shared", ] @@ -4756,7 +4761,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.65", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5104,7 +5109,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.65", ] [[package]] diff --git a/components/config/src/config/search.rs b/components/config/src/config/search.rs index 3ce6878cd2..e259b57bf9 100644 --- a/components/config/src/config/search.rs +++ b/components/config/src/config/search.rs @@ -7,6 +7,23 @@ pub enum IndexFormat { ElasticlunrJson, #[default] ElasticlunrJavascript, + FuseJson, + FuseJavascript, +} + +impl IndexFormat { + /// file extension which ought to be used for this index format. + fn extension(&self) -> &'static str { + match *self { + IndexFormat::ElasticlunrJavascript | IndexFormat::FuseJavascript => "js", + IndexFormat::ElasticlunrJson | IndexFormat::FuseJson => "json", + } + } + + /// the filename which ought to be used for this format and language `lang` + pub fn filename(&self, lang: &str) -> String { + format!("search_index.{}.{}", lang, self.extension()) + } } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] @@ -17,7 +34,7 @@ pub struct Search { /// Includes the whole content in the search index. Ok for small sites but becomes /// too big on large sites. `true` by default. pub include_content: bool, - /// Optionally truncate the content down to `n` chars. This might cut content in a word + /// Optionally truncate the content down to `n` code points. This might cut content in a word pub truncate_content_length: Option, /// Includes the description in the search index. When the site becomes too large, you can switch /// to that instead. `false` by default @@ -26,7 +43,7 @@ pub struct Search { pub include_date: bool, /// Include the path of the page in the search index. `false` by default. pub include_path: bool, - /// Foramt of the search index to be produced. Javascript by default + /// Foramt of the search index to be produced. 'elasticlunr_javascript' by default. pub index_format: IndexFormat, } diff --git a/components/search/Cargo.toml b/components/search/Cargo.toml index d2b26b528f..eb12f7e533 100644 --- a/components/search/Cargo.toml +++ b/components/search/Cargo.toml @@ -8,3 +8,4 @@ errors = { path = "../errors" } content = { path = "../content" } config = { path = "../config" } libs = { path = "../libs" } +serde = { version = "1.0", features = ["derive"] } diff --git a/components/search/src/elasticlunr.rs b/components/search/src/elasticlunr.rs new file mode 100644 index 0000000000..af7583ef8a --- /dev/null +++ b/components/search/src/elasticlunr.rs @@ -0,0 +1,236 @@ +use config::{Config, Search}; +use content::{Library, Section}; +use errors::{bail, Result}; +use libs::elasticlunr::{lang, Index, IndexBuilder}; +use libs::time::format_description::well_known::Rfc3339; +use libs::time::OffsetDateTime; + +use crate::clean_and_truncate_body; + +pub const ELASTICLUNR_JS: &str = include_str!("elasticlunr.min.js"); + +fn build_fields(search_config: &Search, mut index: IndexBuilder) -> IndexBuilder { + if search_config.include_title { + index = index.add_field("title"); + } + + if search_config.include_description { + index = index.add_field("description"); + } + + if search_config.include_date { + index = index.add_field("date") + } + + if search_config.include_path { + index = index.add_field_with_tokenizer("path", Box::new(path_tokenizer)); + } + + if search_config.include_content { + index = index.add_field("body") + } + + index +} + +fn path_tokenizer(text: &str) -> Vec { + text.split(|c: char| c.is_whitespace() || c == '-' || c == '/') + .filter(|s| !s.is_empty()) + .map(|s| s.trim().to_lowercase()) + .collect() +} + +fn fill_index( + search_config: &Search, + title: &Option, + description: &Option, + datetime: &Option, + path: &str, + content: &str, +) -> Vec { + let mut row = vec![]; + + if search_config.include_title { + row.push(title.clone().unwrap_or_default()); + } + + if search_config.include_description { + row.push(description.clone().unwrap_or_default()); + } + + if search_config.include_date { + if let Some(date) = datetime { + if let Ok(d) = date.format(&Rfc3339) { + row.push(d); + } + } + } + + if search_config.include_path { + row.push(path.to_string()); + } + + if search_config.include_content { + row.push(clean_and_truncate_body(search_config.truncate_content_length, content)); + } + row +} + +/// Returns the generated JSON index with all the documents of the site added using +/// the language given +/// Errors if the language given is not available in Elasticlunr +/// TODO: is making `in_search_index` apply to subsections of a `false` section useful? +pub fn build_index(lang: &str, library: &Library, config: &Config) -> Result { + let language = match lang::from_code(lang) { + Some(l) => l, + None => { + bail!("Tried to build search index for language {} which is not supported", lang); + } + }; + let language_options = &config.languages[lang]; + let mut index = IndexBuilder::with_language(language); + index = build_fields(&language_options.search, index); + let mut index = index.build(); + + for (_, section) in &library.sections { + if section.lang == lang { + add_section_to_index(&mut index, section, library, &language_options.search); + } + } + + Ok(index.to_json()) +} + +fn add_section_to_index( + index: &mut Index, + section: &Section, + library: &Library, + search_config: &Search, +) { + if !section.meta.in_search_index { + return; + } + + // Don't index redirecting sections + if section.meta.redirect_to.is_none() { + index.add_doc( + §ion.permalink, + &fill_index( + search_config, + §ion.meta.title, + §ion.meta.description, + &None, + §ion.path, + §ion.content, + ), + ); + } + + for key in §ion.pages { + let page = &library.pages[key]; + if !page.meta.in_search_index { + continue; + } + + index.add_doc( + &page.permalink, + &fill_index( + search_config, + &page.meta.title, + &page.meta.description, + &page.meta.datetime, + &page.path, + &page.content, + ), + ); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use config::Config; + use libs::elasticlunr::IndexBuilder; + + #[test] + fn can_build_fields() { + let mut config = Config::default(); + let index = build_fields(&config.search, IndexBuilder::new()).build(); + assert_eq!(index.get_fields(), vec!["title", "body"]); + + config.search.include_content = false; + config.search.include_description = true; + let index = build_fields(&config.search, IndexBuilder::new()).build(); + assert_eq!(index.get_fields(), vec!["title", "description"]); + + config.search.include_content = true; + let index = build_fields(&config.search, IndexBuilder::new()).build(); + assert_eq!(index.get_fields(), vec!["title", "description", "body"]); + + config.search.include_title = false; + let index = build_fields(&config.search, IndexBuilder::new()).build(); + assert_eq!(index.get_fields(), vec!["description", "body"]); + } + + #[test] + fn can_fill_index_default() { + let config = Config::default(); + let title = Some("A title".to_string()); + let description = Some("A description".to_string()); + let path = "/a/page/".to_string(); + let content = "Some content".to_string(); + + let res = fill_index(&config.search, &title, &description, &None, &path, &content); + assert_eq!(res.len(), 2); + assert_eq!(res[0], title.unwrap()); + assert_eq!(res[1], content); + } + + #[test] + fn can_fill_index_description() { + let mut config = Config::default(); + config.search.include_description = true; + let title = Some("A title".to_string()); + let description = Some("A description".to_string()); + let path = "/a/page/".to_string(); + let content = "Some content".to_string(); + + let res = fill_index(&config.search, &title, &description, &None, &path, &content); + assert_eq!(res.len(), 3); + assert_eq!(res[0], title.unwrap()); + assert_eq!(res[1], description.unwrap()); + assert_eq!(res[2], content); + } + + #[test] + fn can_fill_index_truncated_content() { + let mut config = Config::default(); + config.search.truncate_content_length = Some(5); + let title = Some("A title".to_string()); + let description = Some("A description".to_string()); + let path = "/a/page/".to_string(); + let content = "Some content".to_string(); + + let res = fill_index(&config.search, &title, &description, &None, &path, &content); + assert_eq!(res.len(), 2); + assert_eq!(res[0], title.unwrap()); + assert_eq!(res[1], content[..5]); + } + + #[test] + fn can_fill_index_date() { + let mut config = Config::default(); + config.search.include_date = true; + let title = Some("A title".to_string()); + let description = Some("A description".to_string()); + let path = "/a/page/".to_string(); + let content = "Some content".to_string(); + let datetime = Some(OffsetDateTime::parse("2023-01-31T00:00:00Z", &Rfc3339).unwrap()); + + let res = fill_index(&config.search, &title, &description, &datetime, &path, &content); + assert_eq!(res.len(), 3); + assert_eq!(res[0], title.unwrap()); + assert_eq!(res[1], "2023-01-31T00:00:00Z"); + assert_eq!(res[2], content); + } +} diff --git a/components/search/src/fuse.rs b/components/search/src/fuse.rs new file mode 100644 index 0000000000..604a0d9fcd --- /dev/null +++ b/components/search/src/fuse.rs @@ -0,0 +1,76 @@ +use config::Search; +use content::Library; +use errors::Result; +use libs::serde_json; + +use crate::clean_and_truncate_body; + +/// build index in Fuse.js format. +pub fn build_index(lang: &str, library: &Library, config: &Search) -> Result { + #[derive(serde::Serialize)] + struct Item<'a> { + url: &'a str, + title: Option<&'a str>, + description: Option<&'a str>, + body: Option, // AMMONIA.clean has to allocate anyway + path: Option<&'a str>, + } + let mut items: Vec = Vec::new(); + for (_, section) in &library.sections { + if section.lang == lang + && section.meta.redirect_to.is_none() + && section.meta.in_search_index + { + items.push(Item { + url: §ion.permalink, + title: match config.include_title { + true => Some(§ion.meta.title.as_deref().unwrap_or_default()), + false => None, + }, + description: match config.include_description { + true => Some(§ion.meta.description.as_deref().unwrap_or_default()), + false => None, + }, + body: match config.include_content { + true => Some(clean_and_truncate_body( + config.truncate_content_length, + §ion.content, + )), + false => None, + }, + path: match config.include_path { + true => Some(§ion.path), + false => None, + }, + }); + for page in §ion.pages { + let page = &library.pages[page]; + if page.meta.in_search_index { + items.push(Item { + url: &page.permalink, + title: match config.include_title { + true => Some(&page.meta.title.as_deref().unwrap_or_default()), + false => None, + }, + description: match config.include_description { + true => Some(&page.meta.description.as_deref().unwrap_or_default()), + false => None, + }, + body: match config.include_content { + true => Some(super::clean_and_truncate_body( + config.truncate_content_length, + &page.content, + )), + false => None, + }, + path: match config.include_path { + true => Some(&page.path), + false => None, + }, + }) + } + } + } + } + Ok(serde_json::to_string(&items)?) +} diff --git a/components/search/src/lib.rs b/components/search/src/lib.rs index 51d25579d2..cf2908bbdb 100644 --- a/components/search/src/lib.rs +++ b/components/search/src/lib.rs @@ -1,16 +1,12 @@ -use std::collections::{HashMap, HashSet}; +mod elasticlunr; +mod fuse; use libs::ammonia; -use libs::elasticlunr::{lang, Index, IndexBuilder}; use libs::once_cell::sync::Lazy; -use libs::time::format_description::well_known::Rfc3339; -use libs::time::OffsetDateTime; - -use config::{Config, Search}; -use content::{Library, Section}; -use errors::{bail, Result}; +use std::collections::{HashMap, HashSet}; -pub const ELASTICLUNR_JS: &str = include_str!("elasticlunr.min.js"); +pub use elasticlunr::{build_index as build_elasticlunr, ELASTICLUNR_JS}; +pub use fuse::build_index as build_fuse; static AMMONIA: Lazy> = Lazy::new(|| { let mut clean_content = HashSet::new(); @@ -28,238 +24,25 @@ static AMMONIA: Lazy> = Lazy::new(|| { builder }); -fn build_fields(search_config: &Search, mut index: IndexBuilder) -> IndexBuilder { - if search_config.include_title { - index = index.add_field("title"); - } - - if search_config.include_description { - index = index.add_field("description"); - } - - if search_config.include_date { - index = index.add_field("date") - } - - if search_config.include_path { - index = index.add_field_with_tokenizer("path", Box::new(path_tokenizer)); - } - - if search_config.include_content { - index = index.add_field("body") - } - - index -} - -fn path_tokenizer(text: &str) -> Vec { - text.split(|c: char| c.is_whitespace() || c == '-' || c == '/') - .filter(|s| !s.is_empty()) - .map(|s| s.trim().to_lowercase()) - .collect() -} - -fn fill_index( - search_config: &Search, - title: &Option, - description: &Option, - datetime: &Option, - path: &str, - content: &str, -) -> Vec { - let mut row = vec![]; - - if search_config.include_title { - row.push(title.clone().unwrap_or_default()); - } - - if search_config.include_description { - row.push(description.clone().unwrap_or_default()); - } - - if search_config.include_date { - if let Some(date) = datetime { - if let Ok(d) = date.format(&Rfc3339) { - row.push(d); - } - } - } - - if search_config.include_path { - row.push(path.to_string()); - } - - if search_config.include_content { - let body = AMMONIA.clean(content).to_string(); - if let Some(truncate_len) = search_config.truncate_content_length { - // Not great for unicode - // TODO: fix it like the truncate in Tera - match body.char_indices().nth(truncate_len) { - None => row.push(body), - Some((idx, _)) => row.push((body[..idx]).to_string()), - }; - } else { - row.push(body); - }; - } - row -} - -/// Returns the generated JSON index with all the documents of the site added using -/// the language given -/// Errors if the language given is not available in Elasticlunr -/// TODO: is making `in_search_index` apply to subsections of a `false` section useful? -pub fn build_index(lang: &str, library: &Library, config: &Config) -> Result { - let language = match lang::from_code(lang) { - Some(l) => l, - None => { - bail!("Tried to build search index for language {} which is not supported", lang); - } - }; - let language_options = &config.languages[lang]; - let mut index = IndexBuilder::with_language(language); - index = build_fields(&language_options.search, index); - let mut index = index.build(); - - for (_, section) in &library.sections { - if section.lang == lang { - add_section_to_index(&mut index, section, library, &language_options.search); - } - } - - Ok(index.to_json()) -} - -fn add_section_to_index( - index: &mut Index, - section: &Section, - library: &Library, - search_config: &Search, -) { - if !section.meta.in_search_index { - return; - } - - // Don't index redirecting sections - if section.meta.redirect_to.is_none() { - index.add_doc( - §ion.permalink, - &fill_index( - search_config, - §ion.meta.title, - §ion.meta.description, - &None, - §ion.path, - §ion.content, - ), - ); - } - - for key in §ion.pages { - let page = &library.pages[key]; - if !page.meta.in_search_index { - continue; - } - - index.add_doc( - &page.permalink, - &fill_index( - search_config, - &page.meta.title, - &page.meta.description, - &page.meta.datetime, - &page.path, - &page.content, - ), - ); +/// uses ammonia to clean the body, and truncates it to `truncate_content_length` +pub fn clean_and_truncate_body(truncate_content_length: Option, body: &str) -> String { + let mut clean = AMMONIA.clean(body).to_string(); + if let Some(new_len) = truncate_content_length { + clean.truncate(clean.char_indices().nth(new_len).map(|(i, _)| i).unwrap_or(clean.len())) } + clean } #[cfg(test)] -mod tests { - use super::*; - - use config::Config; - - #[test] - fn can_build_fields() { - let mut config = Config::default(); - let index = build_fields(&config.search, IndexBuilder::new()).build(); - assert_eq!(index.get_fields(), vec!["title", "body"]); - - config.search.include_content = false; - config.search.include_description = true; - let index = build_fields(&config.search, IndexBuilder::new()).build(); - assert_eq!(index.get_fields(), vec!["title", "description"]); - - config.search.include_content = true; - let index = build_fields(&config.search, IndexBuilder::new()).build(); - assert_eq!(index.get_fields(), vec!["title", "description", "body"]); - - config.search.include_title = false; - let index = build_fields(&config.search, IndexBuilder::new()).build(); - assert_eq!(index.get_fields(), vec!["description", "body"]); - } - - #[test] - fn can_fill_index_default() { - let config = Config::default(); - let title = Some("A title".to_string()); - let description = Some("A description".to_string()); - let path = "/a/page/".to_string(); - let content = "Some content".to_string(); - - let res = fill_index(&config.search, &title, &description, &None, &path, &content); - assert_eq!(res.len(), 2); - assert_eq!(res[0], title.unwrap()); - assert_eq!(res[1], content); - } - - #[test] - fn can_fill_index_description() { - let mut config = Config::default(); - config.search.include_description = true; - let title = Some("A title".to_string()); - let description = Some("A description".to_string()); - let path = "/a/page/".to_string(); - let content = "Some content".to_string(); - - let res = fill_index(&config.search, &title, &description, &None, &path, &content); - assert_eq!(res.len(), 3); - assert_eq!(res[0], title.unwrap()); - assert_eq!(res[1], description.unwrap()); - assert_eq!(res[2], content); - } - - #[test] - fn can_fill_index_truncated_content() { - let mut config = Config::default(); - config.search.truncate_content_length = Some(5); - let title = Some("A title".to_string()); - let description = Some("A description".to_string()); - let path = "/a/page/".to_string(); - let content = "Some content".to_string(); - - let res = fill_index(&config.search, &title, &description, &None, &path, &content); - assert_eq!(res.len(), 2); - assert_eq!(res[0], title.unwrap()); - assert_eq!(res[1], content[..5]); - } - - #[test] - fn can_fill_index_date() { - let mut config = Config::default(); - config.search.include_date = true; - let title = Some("A title".to_string()); - let description = Some("A description".to_string()); - let path = "/a/page/".to_string(); - let content = "Some content".to_string(); - let datetime = Some(OffsetDateTime::parse("2023-01-31T00:00:00Z", &Rfc3339).unwrap()); - - let res = fill_index(&config.search, &title, &description, &datetime, &path, &content); - assert_eq!(res.len(), 3); - assert_eq!(res[0], title.unwrap()); - assert_eq!(res[1], "2023-01-31T00:00:00Z"); - assert_eq!(res[2], content); - } +#[test] +fn clean_and_truncate_body_test() { + assert_eq!(clean_and_truncate_body(None, "hello world"), "hello world"); + assert_eq!( + clean_and_truncate_body(None, "hello world"), + "hello world" + ); + assert_eq!(clean_and_truncate_body(Some(100), "hello"), "hello"); + assert_eq!(clean_and_truncate_body(Some(2), "hello"), "he"); + assert_eq!(clean_and_truncate_body(Some(6), "hello \u{202E} world"), "hello "); + assert_eq!(clean_and_truncate_body(Some(7), "hello \u{202E} world"), "hello \u{202e}"); } diff --git a/components/site/src/lib.rs b/components/site/src/lib.rs index a84ca526fd..2d3d578c21 100644 --- a/components/site/src/lib.rs +++ b/components/site/src/lib.rs @@ -799,19 +799,26 @@ impl Site { } fn index_for_lang(&self, lang: &str) -> Result<()> { - let index_json = search::build_index(lang, &self.library.read().unwrap(), &self.config)?; - let (path, content) = match &self.config.search.index_format { - IndexFormat::ElasticlunrJson => { - let path = self.output_path.join(format!("search_index.{}.json", lang)); - (path, index_json) + let path = &self.output_path.join(self.config.search.index_format.filename(lang)); + let library = self.library.read().unwrap(); + let content = match &self.config.search.index_format { + IndexFormat::ElasticlunrJavascript | IndexFormat::ElasticlunrJson => { + search::build_elasticlunr(lang, &library, &self.config)? } - IndexFormat::ElasticlunrJavascript => { - let path = self.output_path.join(format!("search_index.{}.js", lang)); - let content = format!("window.searchIndex = {};", index_json); - (path, content) + IndexFormat::FuseJson | IndexFormat::FuseJavascript => { + search::build_fuse(lang, &library, &self.config.search)? } }; - create_file(&path, &content) + drop(library); // no need to hold on to this guard while writing + create_file( + path, + match self.config.search.index_format { + IndexFormat::ElasticlunrJson | IndexFormat::FuseJson => content, + IndexFormat::ElasticlunrJavascript | IndexFormat::FuseJavascript => { + format!("window.searchIndex = {}", content) + } + }, + ) } pub fn build_search_index(&self) -> Result<()> { @@ -827,8 +834,13 @@ impl Site { } } - // then elasticlunr.min.js - create_file(&self.output_path.join("elasticlunr.min.js"), search::ELASTICLUNR_JS)?; + match self.config.search.index_format { + IndexFormat::ElasticlunrJavascript | IndexFormat::ElasticlunrJson => { + // then elasticlunr.min.js + create_file(&self.output_path.join("elasticlunr.min.js"), search::ELASTICLUNR_JS)?; + } + _ => {} + } Ok(()) } diff --git a/components/utils/src/fs.rs b/components/utils/src/fs.rs index 2b1557068a..4aa13994b8 100644 --- a/components/utils/src/fs.rs +++ b/components/utils/src/fs.rs @@ -28,11 +28,12 @@ fn create_parent(path: &Path) -> Result<()> { } /// Create a file with the content given -pub fn create_file(path: &Path, content: &str) -> Result<()> { +/// `content`` can be `&str`, `String`, or `&String` (and probably others) +pub fn create_file(path: &Path, content: impl AsRef) -> Result<()> { create_parent(path)?; let mut file = File::create(path).with_context(|| format!("Failed to create file {}", path.display()))?; - file.write_all(content.as_bytes())?; + file.write_all(content.as_ref().as_bytes())?; Ok(()) } diff --git a/docs/content/documentation/content/search.md b/docs/content/documentation/content/search.md index c57c1fc114..b66aa06f7a 100644 --- a/docs/content/documentation/content/search.md +++ b/docs/content/documentation/content/search.md @@ -4,7 +4,7 @@ weight = 100 +++ Zola can build a search index from the sections and pages content to -be used by a JavaScript library such as [elasticlunr](http://elasticlunr.com/). +be used by a JavaScript library such as [elasticlunr](http://elasticlunr.com/) or [fuse](https://www.fusejs.io). To enable it, you only need to set `build_search_index = true` in your `config.toml` and Zola will generate an index for the `default_language` set for all pages not excluded from the search index. @@ -12,21 +12,36 @@ generate an index for the `default_language` set for all pages not excluded from It is very important to set the `default_language` in your `config.toml` if you are writing a site not in English; the index building pipelines are very different depending on the language. -After `zola build` or `zola serve`, you should see two files in your public directory: - -- `search_index.${default_language}.js`: so `search_index.en.js` for a default setup -- `elasticlunr.min.js` - -If you set `index_format = "elasticlunr_json"` in your `config.toml`, a `search_index.${default_language}.json` is generated -instead of the default `search_index.${default_language}.js`. - As each site will be different, Zola makes no assumptions about your search function and doesn't provide the JavaScript/CSS code to do an actual search and display results. You can look at how this site -implements it to get an idea: [search.js](https://github.com/getzola/zola/tree/master/docs/static/search.js). +implements it (using elasticlunr) to get an idea: [search.js](https://github.com/getzola/zola/tree/master/docs/static/search.js). -If you are using a language other than English, you will also need to include the corresponding JavaScript stemmer file. -See for details. ## Configuring the search index In some cases, the default indexing strategy is not suitable. You can customize which fields to include and whether to truncate the content in the [search configuration](@/documentation/getting-started/configuration.md). + +## Index Formats + +### Elasticlunr + +Compatible with [elasticlunr](http://elasticlunr.com/). Also produces `elasticlunr.min.js`. + +```toml +# config.toml +[search] +index_format = "elasticlunr_javascript" # or "elasticlunr_json" +``` + +If you are using a language other than English, you will also need to include the corresponding JavaScript stemmer file. +See for details. + +### Fuse + +Compatible with [fuse.js](https://www.fusejs.io/) and [tinysearch](https://github.com/tinysearch/tinysearch). + +```toml +# config.toml +[search] +index_format = "fuse_javascript" # or "fuse_json" +``` diff --git a/docs/content/documentation/getting-started/configuration.md b/docs/content/documentation/getting-started/configuration.md index dce920ce8d..1130cecbfe 100644 --- a/docs/content/documentation/getting-started/configuration.md +++ b/docs/content/documentation/getting-started/configuration.md @@ -174,16 +174,18 @@ include_title = true include_description = false # Whether to include the RFC3339 datetime of the page in the search index include_date = false -# Whether to include the path of the page/section in the index +# Whether to include the path of the page/section in the index (the permalink is always included) include_path = false # Whether to include the rendered content of the page/section in the index include_content = true -# At which character to truncate the content to. Useful if you have a lot of pages and the index would +# At which code point to truncate the content to. Useful if you have a lot of pages and the index would # become too big to load on the site. Defaults to not being set. # truncate_content_length = 100 # Wether to produce the search index as a javascript file or as a JSON file -# Accepted value "elasticlunr_javascript" or "elasticlunr_json" +# Accepted values: +# - "elasticlunr_javascript", "elasticlunr_json" +# - "fuse_javascript", "fuse_json" index_format = "elasticlunr_javascript" # Optional translation object for the default language From 0b54cfca68d5ab1fd353a2db7c8f6ddd4428e894 Mon Sep 17 00:00:00 2001 From: Tanishq Date: Wed, 12 Jun 2024 22:08:51 +0530 Subject: [PATCH 2/6] fix ignore links to #top when checking anchors (#2519) * fix ignore links to #top when checking anchors * move logic to check internal links --------- Co-authored-by: Tanishq --- components/site/src/link_checking.rs | 2 ++ components/utils/src/anchors.rs | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/components/site/src/link_checking.rs b/components/site/src/link_checking.rs index c7e4678195..aff8879b73 100644 --- a/components/site/src/link_checking.rs +++ b/components/site/src/link_checking.rs @@ -10,6 +10,7 @@ use crate::Site; use errors::{bail, Result}; use libs::rayon; use libs::url::Url; +use utils::anchors::is_special_anchor; /// Check whether all internal links pointing to explicit anchor fragments are valid. /// @@ -40,6 +41,7 @@ pub fn check_internal_links_with_anchors(site: &Site) -> Vec { (md_path, Some(anchor)) => Some((page_path, md_path, anchor)), _ => None, }) + .filter(|(_, _, anchor)| !is_special_anchor(anchor)) .inspect(|_| anchors_total = anchors_total.saturating_add(1)); // Check for targets existence (including anchors), then keep only the faulty diff --git a/components/utils/src/anchors.rs b/components/utils/src/anchors.rs index a5706e79d9..5c1bd2d16c 100644 --- a/components/utils/src/anchors.rs +++ b/components/utils/src/anchors.rs @@ -10,9 +10,15 @@ fn anchor_id_checks(anchor: &str) -> Regex { Regex::new(&format!(r#"\s(?i)(id|name) *= *("|')*{}("|'| |>)+"#, escape(anchor))).unwrap() } +/// Checks if anchor has a special meaning in HTML +/// https://html.spec.whatwg.org/#select-the-indicated-part +pub fn is_special_anchor(anchor: &str) -> bool { + anchor.is_empty() || anchor.eq_ignore_ascii_case("top") +} + #[cfg(test)] mod tests { - use super::anchor_id_checks; + use super::{anchor_id_checks, is_special_anchor}; fn check(anchor: &str, content: &str) -> bool { anchor_id_checks(anchor).is_match(content) @@ -52,4 +58,12 @@ id="fred">"#)); // Non matchers assert!(!m(r#""#)); } + + #[test] + fn test_is_special_anchor() { + assert!(is_special_anchor("")); + assert!(is_special_anchor("top")); + assert!(is_special_anchor("Top")); + assert!(!is_special_anchor("anchor")); + } } From 1f6edc5ccc28c0e08e0f1693908fc5a58b9fc198 Mon Sep 17 00:00:00 2001 From: endesigner Date: Sun, 24 Sep 2023 22:30:12 +0200 Subject: [PATCH 3/6] Prevent generating folder & index.html for a specific page --- CHANGELOG.md | 1 + components/content/src/front_matter/page.rs | 5 +++++ components/content/src/library.rs | 8 ++++--- components/content/src/page.rs | 25 +++++++++++++++++++++ components/content/src/pagination.rs | 3 +++ components/site/src/sitemap.rs | 3 +++ components/site/tests/site.rs | 7 ++++-- docs/content/documentation/content/page.md | 3 +++ test_site/content/posts/render.md | 8 +++++++ 9 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 test_site/content/posts/render.md diff --git a/CHANGELOG.md b/CHANGELOG.md index bde1892eb8..bf5a52544d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Fix resizing for images with EXIF orientation - Add MIME type to get_image_metadata - Fix hot loading for config.toml in some cases +- Add `render = false` capability to pages ## 0.18.0 (2023-12-18) diff --git a/components/content/src/front_matter/page.rs b/components/content/src/front_matter/page.rs index 4d2ed5ebfb..b4bacd307c 100644 --- a/components/content/src/front_matter/page.rs +++ b/components/content/src/front_matter/page.rs @@ -39,6 +39,10 @@ pub struct PageFrontMatter { pub datetime_tuple: Option<(i32, u8, u8)>, /// Whether this page is a draft pub draft: bool, + /// Prevent generation of a folder for current page + /// Defaults to `true` + #[serde(skip_serializing)] + pub render: bool, /// The page slug. Will be used instead of the filename if present /// Can't be an empty string if present pub slug: Option, @@ -151,6 +155,7 @@ impl Default for PageFrontMatter { datetime: None, datetime_tuple: None, draft: false, + render: true, slug: None, path: None, taxonomies: HashMap::new(), diff --git a/components/content/src/library.rs b/components/content/src/library.rs index 2ab6fdbfa3..c2adb9410d 100644 --- a/components/content/src/library.rs +++ b/components/content/src/library.rs @@ -82,9 +82,11 @@ impl Library { pub fn insert_page(&mut self, page: Page) { let file_path = page.file.path.clone(); - let mut entries = vec![page.path.clone()]; - entries.extend(page.meta.aliases.to_vec()); - self.insert_reverse_aliases(&file_path, entries); + if page.meta.render { + let mut entries = vec![page.path.clone()]; + entries.extend(page.meta.aliases.to_vec()); + self.insert_reverse_aliases(&file_path, entries); + } for (taxa_name, terms) in &page.meta.taxonomies { for term in terms { diff --git a/components/content/src/page.rs b/components/content/src/page.rs index 94672b2bd2..e0ea0f9bef 100644 --- a/components/content/src/page.rs +++ b/components/content/src/page.rs @@ -115,6 +115,10 @@ impl Page { page.word_count = Some(word_count); page.reading_time = Some(reading_time); + if !page.meta.render { + return Ok(page); + } + let mut slug_from_dated_filename = None; let file_path_for_slug = if page.file.name == "index" { @@ -923,4 +927,25 @@ Bonjour le monde"# assert_eq!(page.slug, "hello"); assert_eq!(page.permalink, "http://a-website.com/bonjour/"); } + + #[test] + fn page_without_physical_path() { + let config = Config::default(); + let content = r#" ++++ +render = false ++++ +Hello world +"# + .to_string(); + + let res = Page::parse(Path::new("hello.md"), &content, &config, &PathBuf::new()); + assert!(res.is_ok()); + let page = res.unwrap(); + println!("{:#?}", page); + assert_eq!(page.slug, ""); + assert_eq!(page.path, ""); + assert_eq!(page.permalink, ""); + assert_eq!(page.raw_content, "Hello world\n".to_string()); + } } diff --git a/components/content/src/pagination.rs b/components/content/src/pagination.rs index 88a09462ed..c620bb3a72 100644 --- a/components/content/src/pagination.rs +++ b/components/content/src/pagination.rs @@ -130,6 +130,9 @@ impl<'a> Paginator<'a> { for p in &*self.all_pages { let page = &library.pages[p]; + if !page.meta.render { + continue; + } current_page.push(SerializingPage::new(page, Some(library), false)); if current_page.len() == self.paginate_by { diff --git a/components/site/src/sitemap.rs b/components/site/src/sitemap.rs index 0f07176749..2d9960741b 100644 --- a/components/site/src/sitemap.rs +++ b/components/site/src/sitemap.rs @@ -64,6 +64,9 @@ pub fn find_entries<'a>( let mut entries = HashSet::new(); for p in library.pages.values() { + if !p.meta.render { + continue; + } let mut entry = SitemapEntry::new( Cow::Borrowed(&p.permalink), if p.meta.updated.is_some() { &p.meta.updated } else { &p.meta.date }, diff --git a/components/site/tests/site.rs b/components/site/tests/site.rs index baca868e2b..ec8694a138 100644 --- a/components/site/tests/site.rs +++ b/components/site/tests/site.rs @@ -21,7 +21,7 @@ fn can_parse_site() { let library = site.library.read().unwrap(); // Correct number of pages (sections do not count as pages, draft are ignored) - assert_eq!(library.pages.len(), 35); + assert_eq!(library.pages.len(), 36); let posts_path = path.join("content").join("posts"); // Make sure the page with a url doesn't have any sections @@ -44,7 +44,7 @@ fn can_parse_site() { let posts_section = library.sections.get(&posts_path.join("_index.md")).unwrap(); assert_eq!(posts_section.subsections.len(), 2); - assert_eq!(posts_section.pages.len(), 10); // 11 with 1 draft == 10 + assert_eq!(posts_section.pages.len(), 11); // 12 with 1 draft == 11 assert_eq!(posts_section.ancestors, vec![index_section.file.relative.clone()]); // Make sure we remove all the pwd + content from the sections @@ -136,6 +136,9 @@ fn can_build_site_without_live_reload() { assert!(file_exists!(public, "posts/with-assets/index.html")); assert!(file_exists!(public, "posts/no-section/simple/index.html")); + // "render = false" should not generate an index.html + assert!(!file_exists!(public, "posts/render/index.html")); + // Sections assert!(file_exists!(public, "posts/index.html")); assert!(file_exists!(public, "posts/tutorials/index.html")); diff --git a/docs/content/documentation/content/page.md b/docs/content/documentation/content/page.md index 98197808ee..30f2af581e 100644 --- a/docs/content/documentation/content/page.md +++ b/docs/content/documentation/content/page.md @@ -112,6 +112,9 @@ weight = 0 # A draft page is only loaded if the `--drafts` flag is passed to `zola build`, `zola serve` or `zola check`. draft = false +# When set to "false" Zola will not create a separate folder with index.html inside for this page. +render = false + # If set, this slug will be used instead of the filename to make the URL. # The section path will still be used. slug = "" diff --git a/test_site/content/posts/render.md b/test_site/content/posts/render.md new file mode 100644 index 0000000000..63af6b7568 --- /dev/null +++ b/test_site/content/posts/render.md @@ -0,0 +1,8 @@ ++++ +title = "Page with content but without generated folder" +description = "" +date = 2017-04-01 +render = false ++++ + +Don't generate a folder for this page From f57dd63308b13c26724e092c204e609e5d38f9be Mon Sep 17 00:00:00 2001 From: Vincent Prouillet Date: Sun, 16 Jun 2024 00:05:01 +0200 Subject: [PATCH 4/6] Fix tests --- components/content/src/library.rs | 3 +++ components/content/src/page.rs | 25 ------------------------- components/site/src/lib.rs | 6 +++++- components/site/tests/site.rs | 2 +- 4 files changed, 9 insertions(+), 27 deletions(-) diff --git a/components/content/src/library.rs b/components/content/src/library.rs index c2adb9410d..990de93eac 100644 --- a/components/content/src/library.rs +++ b/components/content/src/library.rs @@ -295,6 +295,9 @@ impl Library { // Then once we took care of the sections, we find the pages of each section for (path, page) in self.pages.iter_mut() { + if !page.meta.render { + continue; + } let parent_filename = &index_filename_by_lang[&page.lang]; add_translation(&page.file.canonical, path); let mut parent_section_path = page.file.parent.join(parent_filename); diff --git a/components/content/src/page.rs b/components/content/src/page.rs index e0ea0f9bef..94672b2bd2 100644 --- a/components/content/src/page.rs +++ b/components/content/src/page.rs @@ -115,10 +115,6 @@ impl Page { page.word_count = Some(word_count); page.reading_time = Some(reading_time); - if !page.meta.render { - return Ok(page); - } - let mut slug_from_dated_filename = None; let file_path_for_slug = if page.file.name == "index" { @@ -927,25 +923,4 @@ Bonjour le monde"# assert_eq!(page.slug, "hello"); assert_eq!(page.permalink, "http://a-website.com/bonjour/"); } - - #[test] - fn page_without_physical_path() { - let config = Config::default(); - let content = r#" -+++ -render = false -+++ -Hello world -"# - .to_string(); - - let res = Page::parse(Path::new("hello.md"), &content, &config, &PathBuf::new()); - assert!(res.is_ok()); - let page = res.unwrap(); - println!("{:#?}", page); - assert_eq!(page.slug, ""); - assert_eq!(page.path, ""); - assert_eq!(page.permalink, ""); - assert_eq!(page.raw_content, "Hello world\n".to_string()); - } } diff --git a/components/site/src/lib.rs b/components/site/src/lib.rs index 2d3d578c21..10729437b0 100644 --- a/components/site/src/lib.rs +++ b/components/site/src/lib.rs @@ -692,6 +692,10 @@ impl Site { /// Renders a single content page pub fn render_page(&self, page: &Page) -> Result<()> { + if !page.meta.render { + return Ok(()); + } + let output = page.render_html(&self.tera, &self.config, &self.library.read().unwrap())?; let content = self.inject_livereload(output); let components: Vec<&str> = page.path.split('/').collect(); @@ -1087,7 +1091,7 @@ impl Site { } // Copy any asset we found previously into the same directory as the index.html - self.copy_assets(§ion.file.path.parent().unwrap(), §ion.assets, &output_path)?; + self.copy_assets(section.file.path.parent().unwrap(), §ion.assets, &output_path)?; if render_pages { section diff --git a/components/site/tests/site.rs b/components/site/tests/site.rs index ec8694a138..bf0811e15a 100644 --- a/components/site/tests/site.rs +++ b/components/site/tests/site.rs @@ -44,7 +44,7 @@ fn can_parse_site() { let posts_section = library.sections.get(&posts_path.join("_index.md")).unwrap(); assert_eq!(posts_section.subsections.len(), 2); - assert_eq!(posts_section.pages.len(), 11); // 12 with 1 draft == 11 + assert_eq!(posts_section.pages.len(), 10); // 11 with 1 draft == 10 assert_eq!(posts_section.ancestors, vec![index_section.file.relative.clone()]); // Make sure we remove all the pwd + content from the sections From c042697a5e4e1dc33174039396275bffd42e5b7a Mon Sep 17 00:00:00 2001 From: Andrew Langmeier Date: Mon, 17 Jun 2024 08:00:44 -0400 Subject: [PATCH 5/6] Add support for yaml datetimes (#2208) * Add support for yaml datetimes * cargo fmt * Wire things up; Add more tests * cargo fmt --- Cargo.lock | 1 + components/content/src/front_matter/page.rs | 37 ++++- components/utils/Cargo.toml | 1 + components/utils/src/de.rs | 149 +++++++++++++++++++- 4 files changed, 180 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 44eb1db4a7..7374b167f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4632,6 +4632,7 @@ dependencies = [ "libs", "serde", "tempfile", + "time", ] [[package]] diff --git a/components/content/src/front_matter/page.rs b/components/content/src/front_matter/page.rs index b4bacd307c..bdc0491572 100644 --- a/components/content/src/front_matter/page.rs +++ b/components/content/src/front_matter/page.rs @@ -7,7 +7,7 @@ use time::macros::{format_description, time}; use time::{Date, OffsetDateTime, PrimitiveDateTime}; use errors::{bail, Result}; -use utils::de::{fix_toml_dates, from_toml_datetime}; +use utils::de::{fix_toml_dates, from_unknown_datetime}; use crate::front_matter::split::RawFrontMatter; @@ -20,7 +20,7 @@ pub struct PageFrontMatter { /// Description in that appears when linked, e.g. on twitter pub description: Option, /// Updated date - #[serde(default, deserialize_with = "from_toml_datetime")] + #[serde(default, deserialize_with = "from_unknown_datetime")] pub updated: Option, /// Datetime content was last updated #[serde(default, skip_deserializing)] @@ -29,7 +29,7 @@ pub struct PageFrontMatter { #[serde(default, skip_deserializing)] pub updated_datetime_tuple: Option<(i32, u8, u8)>, /// Date if we want to order pages (ie blog post) - #[serde(default, deserialize_with = "from_toml_datetime")] + #[serde(default, deserialize_with = "from_unknown_datetime")] pub date: Option, /// Datetime content was created #[serde(default, skip_deserializing)] @@ -129,6 +129,7 @@ impl PageFrontMatter { /// Converts the TOML datetime to a time::OffsetDateTime /// Also grabs the year/month/day tuple that will be used in serialization pub fn date_to_datetime(&mut self) { + println!("{:?}", self.date); self.datetime = self.date.as_ref().map(|s| s.as_ref()).and_then(parse_datetime); self.datetime_tuple = self.datetime.map(|dt| (dt.year(), dt.month().into(), dt.day())); @@ -333,6 +334,36 @@ date: 2002-10-02T15:00:00.123456Z assert_eq!(res.datetime.unwrap(), datetime!(2002 - 10 - 02 15:00:00.123456 UTC)); } + #[test_case(&RawFrontMatter::Yaml(r#" +title: Hello +description: hey there +date: 2001-12-15T02:59:43.1Z +"#); "canonical")] + #[test_case(&RawFrontMatter::Yaml(r#" +title: Hello +description: hey there +date: 2001-12-14t21:59:43.10-05:00 +"#); "iso8601")] + #[test_case(&RawFrontMatter::Yaml(r#" +title: Hello +description: hey there +date: 2001-12-14 21:59:43.10 -5 +"#); "space separated")] + #[test_case(&RawFrontMatter::Yaml(r#" +title: Hello +description: hey there +date: 2001-12-15 2:59:43.10 +"#); "no time zone")] + #[test_case(&RawFrontMatter::Yaml(r#" +title: Hello +description: hey there +date: 2001-12-15 +"#); "date only")] + fn can_parse_yaml_dates(content: &RawFrontMatter) { + let res = PageFrontMatter::parse(content).unwrap(); + assert!(res.datetime.is_some()); + } + #[test_case(&RawFrontMatter::Toml(r#" title = "Hello" description = "hey there" diff --git a/components/utils/Cargo.toml b/components/utils/Cargo.toml index 65c4513381..73c2f86845 100644 --- a/components/utils/Cargo.toml +++ b/components/utils/Cargo.toml @@ -13,3 +13,4 @@ libs = { path = "../libs" } [dev-dependencies] tempfile = "3" +time = { version = "0.3", features = ["macros"] } diff --git a/components/utils/src/de.rs b/components/utils/src/de.rs index 983b31d9da..c257fd0e04 100644 --- a/components/utils/src/de.rs +++ b/components/utils/src/de.rs @@ -1,12 +1,83 @@ +use core::convert::TryFrom; +use errors::{anyhow, Result}; +use libs::regex::Regex; use libs::tera::{Map, Value}; +use libs::time; +use libs::time::format_description::well_known::Rfc3339; use libs::toml; use serde::{Deserialize, Deserializer}; +pub fn parse_yaml_datetime(date_string: &str) -> Result { + // See https://github.com/getzola/zola/issues/2071#issuecomment-1530610650 + let re = Regex::new(r#"^"?([0-9]{4})-([0-9][0-9]?)-([0-9][0-9]?)([Tt]|[ \t]+)([0-9][0-9]?):([0-9]{2}):([0-9]{2})\.([0-9]*)?Z?([ \t]([-+][0-9][0-9]?)(:([0-9][0-9]?))?Z?|([-+][0-9]{2})?:([0-9]{2})?)?|([0-9]{4})-([0-9]{2})-([0-9]{2})"?$"#).unwrap(); + let captures = if let Some(captures_) = re.captures(date_string) { + Ok(captures_) + } else { + Err(anyhow!("Error parsing YAML datetime")) + }?; + let year = + if let Some(cap) = captures.get(1) { cap } else { captures.get(15).unwrap() }.as_str(); + let month = + if let Some(cap) = captures.get(2) { cap } else { captures.get(16).unwrap() }.as_str(); + let day = + if let Some(cap) = captures.get(3) { cap } else { captures.get(17).unwrap() }.as_str(); + let hours = if let Some(hours_) = captures.get(5) { hours_.as_str() } else { "0" }; + let minutes = if let Some(minutes_) = captures.get(6) { minutes_.as_str() } else { "0" }; + let seconds = if let Some(seconds_) = captures.get(7) { seconds_.as_str() } else { "0" }; + let fractional_seconds_raw = + if let Some(fractionals) = captures.get(8) { fractionals.as_str() } else { "" }; + let fractional_seconds_intermediate = fractional_seconds_raw.trim_end_matches("0"); + // + // Prepare for eventual conversion into nanoseconds + let fractional_seconds = if fractional_seconds_intermediate.len() > 0 + && fractional_seconds_intermediate.len() <= 9 + { + fractional_seconds_intermediate + } else { + "0" + }; + let maybe_timezone_hour_1 = captures.get(10); + let maybe_timezone_minute_1 = captures.get(12); + let maybe_timezone_hour_2 = captures.get(13); + let maybe_timezone_minute_2 = captures.get(14); + let maybe_timezone_hour; + let maybe_timezone_minute; + if maybe_timezone_hour_2.is_some() { + maybe_timezone_hour = maybe_timezone_hour_2; + maybe_timezone_minute = maybe_timezone_minute_2; + } else { + maybe_timezone_hour = maybe_timezone_hour_1; + maybe_timezone_minute = maybe_timezone_minute_1; + } + + let mut offset_datetime = time::OffsetDateTime::UNIX_EPOCH; + + if let Some(hour) = maybe_timezone_hour { + let minute_str = + if let Some(minute_) = maybe_timezone_minute { minute_.as_str() } else { "0" }; + offset_datetime = offset_datetime.to_offset(time::UtcOffset::from_hms( + hour.as_str().parse()?, + minute_str.parse()?, + 0, + )?); + } + + // Free parse unwraps since we know everything is a digit courtesy of prior regex. + Ok(offset_datetime + .replace_year(year.parse().unwrap())? + .replace_month(time::Month::try_from(month.parse::().unwrap())?)? + .replace_day(day.parse().unwrap())? + .replace_hour(hours.parse().unwrap())? + .replace_minute(minutes.parse().unwrap())? + .replace_second(seconds.parse().unwrap())? + .replace_nanosecond(fractional_seconds.parse::().unwrap() * 100_000_000)?) +} + /// Used as an attribute when we want to convert from TOML to a string date /// If a TOML datetime isn't present, it will accept a string and push it through /// TOML's date time parser to ensure only valid dates are accepted. /// Inspired by this proposal: -pub fn from_toml_datetime<'de, D>(deserializer: D) -> Result, D::Error> +pub fn from_unknown_datetime<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { @@ -22,10 +93,19 @@ where match MaybeDatetime::deserialize(deserializer)? { MaybeDatetime::Datetime(d) => Ok(Some(d.to_string())), - MaybeDatetime::String(s) => match toml::value::Datetime::from_str(&s) { - Ok(d) => Ok(Some(d.to_string())), - Err(e) => Err(D::Error::custom(e)), - }, + MaybeDatetime::String(s) => { + if let Ok(d) = toml::value::Datetime::from_str(&s) { + Ok(Some(d.to_string())) + } else if let Ok(d) = parse_yaml_datetime(&s) { + // Ensure that the resulting string is easily reparseable down the line. + // In content::front_matter::page.rs where these strings are currently used, + // Rfc3339 works with the explicit demands in that code but not always with the result of + // _to_string. + Ok(Some(d.format(&Rfc3339).unwrap())) + } else { + Err(D::Error::custom("Unable to parse datetime")) + } + } } } @@ -80,3 +160,62 @@ pub fn fix_toml_dates(table: Map) -> Value { Value::Object(new) } + +#[cfg(test)] +mod tests { + use super::parse_yaml_datetime; + use time::macros::datetime; + + #[test] + fn yaml_spec_examples_pass() { + let canonical = "2001-12-15T02:59:43.1Z"; + let valid_iso8601 = "2001-12-14t21:59:43.10-05:00"; + let space_separated = "2001-12-14 21:59:43.10 -5"; + let no_time_zone = "2001-12-15 2:59:43.10"; + let date = "2002-12-14"; + assert_eq!(parse_yaml_datetime(canonical).unwrap(), datetime!(2001-12-15 2:59:43.1 +0)); + assert_eq!( + parse_yaml_datetime(valid_iso8601).unwrap(), + datetime!(2001-12-14 21:59:43.1 -5) + ); + assert_eq!( + parse_yaml_datetime(space_separated).unwrap(), + datetime!(2001-12-14 21:59:43.1 -5) + ); + assert_eq!(parse_yaml_datetime(no_time_zone).unwrap(), datetime!(2001-12-15 2:59:43.1 +0)); + assert_eq!(parse_yaml_datetime(date).unwrap(), datetime!(2002-12-14 0:00:00 +0)); + } + + #[test] + fn yaml_spec_invalid_dates_fail() { + let invalid_month = "2001-13-15"; + assert!(parse_yaml_datetime(invalid_month).is_err()); + + let invalid_month = "2001-13-15T02:59:43.1Z"; + assert!(parse_yaml_datetime(invalid_month).is_err()); + + let no_digits_in_year = "xxxx-12-15"; + assert!(parse_yaml_datetime(no_digits_in_year).is_err()); + + let no_digits_in_year = "xxxx-12-15T02:59:43.1Z"; + assert!(parse_yaml_datetime(no_digits_in_year).is_err()); + + let no_digits_in_month = "2001-xx-15"; + assert!(parse_yaml_datetime(no_digits_in_month).is_err()); + + let no_digits_in_month = "2001-xx-15T02:59:43.1Z"; + assert!(parse_yaml_datetime(no_digits_in_month).is_err()); + + let no_digits_in_day = "2001-12-xx"; + assert!(parse_yaml_datetime(no_digits_in_day).is_err()); + + let no_digits_in_day = "2001-12-xx:59:43.1Z"; + assert!(parse_yaml_datetime(no_digits_in_day).is_err()); + + let unparseable_time = "2001-12-15:69:43.1Z"; + assert!(parse_yaml_datetime(unparseable_time).is_err()); + + let unparseable_time = "2001-12-15:59:4x.1Z"; + assert!(parse_yaml_datetime(unparseable_time).is_err()); + } +} From 659f349da71316df557a21cbbdf1b243e32e2229 Mon Sep 17 00:00:00 2001 From: Vincent Prouillet Date: Mon, 17 Jun 2024 14:12:08 +0200 Subject: [PATCH 6/6] Update deps --- CHANGELOG.md | 4 +- Cargo.lock | 587 ++++++++++++-------- azure-pipelines.yml | 2 +- components/content/src/front_matter/page.rs | 1 - components/libs/Cargo.toml | 4 +- snapcraft.yaml | 4 +- 6 files changed, 368 insertions(+), 234 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf5a52544d..75950a3d0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,15 @@ ## 0.19.0 (unreleased) -- Updates the pulldown-cmark dependency to v0.10.0. This improves footnote handling, and may also introduce some minor behavior changes such as reducing the amount of unnecessary HTML-escaping of text content. +- Updates the pulldown-cmark dependency to v0.11.0. This improves footnote handling, and may also introduce some minor behavior changes such as reducing the amount of unnecessary HTML-escaping of text content. - Add bottom footnotes with backreference option - Fix link check report inconsistency - Fix resizing for images with EXIF orientation - Add MIME type to get_image_metadata - Fix hot loading for config.toml in some cases - Add `render = false` capability to pages +- Handle string dates in YAML front-matter +- Add support for fuse.js search format ## 0.18.0 (2023-12-18) diff --git a/Cargo.lock b/Cargo.lock index 7374b167f4..615e5de760 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -125,9 +125,9 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" dependencies = [ "windows-sys 0.52.0", ] @@ -168,7 +168,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -229,9 +229,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -292,9 +292,9 @@ checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "bitstream-io" -version = "2.3.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c12d1856e42f0d817a835fe55853957c85c8c8a470114029143d3f12671446e" +checksum = "eac55ccd165b210af261b1812cf29a0b9e6303b480ff0df603c037129ff357fe" [[package]] name = "bitvec" @@ -356,9 +356,9 @@ checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" [[package]] name = "built" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41bfbdb21256b87a8b5e80fab81a8eed158178e812fd7ba451907518b2742f16" +checksum = "c6a6c0b39c38fd754ac338b00a88066436389c0f029da5d37d1e01091d9b7c17" [[package]] name = "bumpalo" @@ -434,42 +434,11 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" -[[package]] -name = "camino" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", -] - [[package]] name = "cc" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" dependencies = [ "jobserver", "libc", @@ -528,9 +497,9 @@ dependencies = [ [[package]] name = "chrono-tz" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59ae0466b83e838b81a54256c39d5d7c20b9d7daa10510a242d9b75abd5936e" +checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" dependencies = [ "chrono", "chrono-tz-build", @@ -539,9 +508,9 @@ dependencies = [ [[package]] name = "chrono-tz-build" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433e39f13c9a060046954e0592a8d0a4bcb1040125cbf91cb8ee58964cfb350f" +checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1" dependencies = [ "parse-zoneinfo", "phf 0.11.2", @@ -567,33 +536,33 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" dependencies = [ "clap_builder", - "clap_derive 4.5.4", + "clap_derive 4.5.5", ] [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" dependencies = [ "anstream", "anstyle", - "clap_lex 0.7.0", + "clap_lex 0.7.1", "strsim 0.11.1", ] [[package]] name = "clap_complete" -version = "4.5.2" +version = "4.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79504325bf38b10165b02e89b4347300f855f273c4cb30c4a3209e6583275e" +checksum = "d2020fa13af48afc65a9a87335bda648309ab3d154cd03c7ff95b378c7ed39c4" dependencies = [ - "clap 4.5.4", + "clap 4.5.7", ] [[package]] @@ -611,14 +580,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -632,9 +601,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "codemap" @@ -774,9 +743,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ "crossbeam-utils", ] @@ -851,7 +820,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -955,7 +924,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -972,9 +941,9 @@ checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" [[package]] name = "dtoa-short" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" dependencies = [ "dtoa", ] @@ -1109,15 +1078,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "error-chain" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" -dependencies = [ - "version_check", -] - [[package]] name = "errors" version = "0.1.0" @@ -1395,9 +1355,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "glob" @@ -1420,11 +1380,11 @@ dependencies = [ [[package]] name = "globwalk" -version = "0.8.1" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" +checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "ignore", "walkdir", ] @@ -1539,7 +1499,7 @@ dependencies = [ "markup5ever", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -1566,9 +1526,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "d0e7a4dd27b9476dc40cb050d3632d3bba3a70ddbff012285f7f8559a1e7e545" [[package]] name = "httpdate" @@ -1593,9 +1553,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.28" +version = "0.14.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" dependencies = [ "bytes 1.6.0", "futures-channel", @@ -1665,14 +1625,134 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f8ac670d7422d7f76b32e17a5db556510825b29ec9154f235977c9caba61036" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "idna" -version = "0.5.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "4716a3a0933a1d01c2f72450e89596eb51dd34ef3c211ccd875acdf1f8fe47ed" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", + "smallvec", + "utf8_iter", ] [[package]] @@ -1803,7 +1883,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -2029,7 +2109,7 @@ dependencies = [ "num-format", "once_cell", "percent-encoding", - "pulldown-cmark 0.10.3", + "pulldown-cmark", "pulldown-cmark-escape", "quickxml_to_serde", "rayon", @@ -2045,7 +2125,7 @@ dependencies = [ "tera", "termcolor", "time", - "toml 0.8.13", + "toml 0.8.14", "unic-langid", "unicode-segmentation", "url", @@ -2065,9 +2145,9 @@ dependencies = [ [[package]] name = "lightningcss" -version = "1.0.0-alpha.56" +version = "1.0.0-alpha.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668e9f1774a4dda9e2233ad0f78c6987878bcf4201d2085bc3517a7f84d0ee92" +checksum = "10bc10261f46b8df263b80e7779d1748b1880488cd951fbb9e096430cead10e6" dependencies = [ "ahash 0.8.11", "bitflags 2.5.0", @@ -2077,7 +2157,6 @@ dependencies = [ "dashmap", "data-encoding", "getrandom 0.2.15", - "indexmap 2.2.6", "itertools 0.10.5", "lazy_static", "parcel_selectors", @@ -2275,6 +2354,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + [[package]] name = "lock_api" version = "0.4.12" @@ -2369,9 +2454,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "mime" @@ -2536,11 +2621,10 @@ checksum = "16cf681a23b4d0a43fc35024c176437f9dcd818db34e0f42ab456a0ee5ad497b" [[package]] name = "native-tls" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" dependencies = [ - "lazy_static", "libc", "log", "openssl", @@ -2698,7 +2782,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -2751,9 +2835,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" dependencies = [ "memchr", ] @@ -2794,9 +2878,9 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "open" -version = "5.1.3" +version = "5.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb49fbd5616580e9974662cb96a3463da4476e649a7e4b258df0de065db0657" +checksum = "b5ca541f22b1c46d4bb9801014f234758ab4297e7870b904b6a8415b980a7388" dependencies = [ "is-wsl", "libc", @@ -2826,7 +2910,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -2891,9 +2975,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -2907,7 +2991,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "smallvec", "windows-targets 0.52.5", ] @@ -2989,7 +3073,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -3072,7 +3156,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -3182,9 +3266,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.83" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] @@ -3205,7 +3289,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd" dependencies = [ "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -3230,20 +3314,9 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" -dependencies = [ - "bitflags 2.5.0", - "memchr", - "unicase", -] - -[[package]] -name = "pulldown-cmark" -version = "0.10.3" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" +checksum = "8746739f11d39ce5ad5c2520a9b75285310dbfe78c541ccf832d38615765aec0" dependencies = [ "bitflags 2.5.0", "memchr", @@ -3253,9 +3326,9 @@ dependencies = [ [[package]] name = "pulldown-cmark-escape" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3" +checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" [[package]] name = "pure-rust-locales" @@ -3432,9 +3505,9 @@ dependencies = [ [[package]] name = "ravif" -version = "0.11.5" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc13288f5ab39e6d7c9d501759712e6969fcc9734220846fc9ed26cae2cc4234" +checksum = "67376f469e7e7840d0040bbf4b9b3334005bb167f814621326e4c7ab8cd6e944" dependencies = [ "avif-serialize", "imgref", @@ -3476,18 +3549,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ "bitflags 2.5.0", ] [[package]] name = "regex" -version = "1.10.4" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick 1.1.3", "memchr", @@ -3497,9 +3570,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick 1.1.3", "memchr", @@ -3508,9 +3581,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "relative-path" @@ -3626,12 +3699,9 @@ dependencies = [ [[package]] name = "roxmltree" -version = "0.18.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862340e351ce1b271a378ec53f304a5558f7db87f3769dc655a8f6ecbb68b302" -dependencies = [ - "xmlparser", -] +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" [[package]] name = "rust-stemmers" @@ -3779,33 +3849,24 @@ dependencies = [ "libc", ] -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" -dependencies = [ - "serde", -] - [[package]] name = "serde" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -3938,21 +3999,6 @@ dependencies = [ "utils", ] -[[package]] -name = "skeptic" -version = "0.13.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" -dependencies = [ - "bytecount", - "cargo_metadata", - "error-chain", - "glob", - "pulldown-cmark 0.9.6", - "tempfile", - "walkdir", -] - [[package]] name = "slab" version = "0.4.9" @@ -3997,6 +4043,12 @@ dependencies = [ "lock_api", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "string_cache" version = "0.8.7" @@ -4037,15 +4089,14 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "svg_metadata" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda36a3fa423e97b25e5432fb6eb2f17accf0b5cd5cda7bd84f8be0e06f97c34" +checksum = "274c7cbc78c2e2cdc104ea7d98db4d2416d2433dfaa3f2ae6fb8c8f9c9e2271c" dependencies = [ "doc-comment", "once_cell", "regex", "roxmltree", - "skeptic", ] [[package]] @@ -4061,9 +4112,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.65" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -4076,6 +4127,17 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "syntect" version = "5.2.0" @@ -4128,7 +4190,7 @@ dependencies = [ "cfg-expr", "heck 0.5.0", "pkg-config", - "toml 0.8.13", + "toml 0.8.14", "version-compare", ] @@ -4140,9 +4202,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" dependencies = [ "filetime", "libc", @@ -4195,9 +4257,9 @@ dependencies = [ [[package]] name = "tera" -version = "1.19.1" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "970dff17c11e884a4a09bc76e3a17ef71e01bb13447a11e85226e254fe6d10b8" +checksum = "ab9d851b45e865f178319da0abdbfe6acbc4328759ff18dafc3a41c16b4cd2ee" dependencies = [ "chrono", "chrono-tz", @@ -4242,7 +4304,7 @@ dependencies = [ "cfg-if 1.0.0", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -4253,7 +4315,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", "test-case-core", ] @@ -4280,7 +4342,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", ] [[package]] @@ -4329,11 +4391,12 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c02bf3c538ab32ba913408224323915f4ef9a6d61c0e85d493f355921c0ece" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ "displaydoc", + "zerovec", ] [[package]] @@ -4353,9 +4416,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes 1.6.0", @@ -4410,9 +4473,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.13" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" dependencies = [ "serde", "serde_spanned", @@ -4431,9 +4494,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.13" +version = "0.22.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" dependencies = [ "indexmap 2.2.6", "serde", @@ -4562,27 +4625,12 @@ dependencies = [ "version_check", ] -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-segmentation" version = "1.11.0" @@ -4603,9 +4651,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "f7c25da092f0a868cdf09e8674cd3b7ef3a7d92a24253e663a2fb85e2496de56" dependencies = [ "form_urlencoded", "idna", @@ -4618,11 +4666,23 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "utils" @@ -4728,7 +4788,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", "wasm-bindgen-shared", ] @@ -4762,7 +4822,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4998,9 +5058,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" -version = "0.6.8" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" dependencies = [ "memchr", ] @@ -5024,6 +5084,18 @@ dependencies = [ "toml 0.5.11", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "ws" version = "0.9.2" @@ -5072,12 +5144,6 @@ dependencies = [ "rustix", ] -[[package]] -name = "xmlparser" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" - [[package]] name = "yada" version = "0.5.1" @@ -5093,6 +5159,30 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.34" @@ -5110,14 +5200,57 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.65", + "syn 2.0.66", +] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2cc8827d6c0994478a15c53f374f46fbd41bea663d809b14744bc42e6b109c" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", ] [[package]] name = "zola" version = "0.18.0" dependencies = [ - "clap 4.5.4", + "clap 4.5.7", "clap_complete", "console 0.1.0", "ctrlc", diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2ac2cae6d2..6640b79ade 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -21,7 +21,7 @@ stages: rustup_toolchain: stable linux-pinned: imageName: 'ubuntu-20.04' - rustup_toolchain: 1.74.0 + rustup_toolchain: 1.79.0 pool: vmImage: $(imageName) steps: diff --git a/components/content/src/front_matter/page.rs b/components/content/src/front_matter/page.rs index bdc0491572..4615ef6618 100644 --- a/components/content/src/front_matter/page.rs +++ b/components/content/src/front_matter/page.rs @@ -129,7 +129,6 @@ impl PageFrontMatter { /// Converts the TOML datetime to a time::OffsetDateTime /// Also grabs the year/month/day tuple that will be used in serialization pub fn date_to_datetime(&mut self) { - println!("{:?}", self.date); self.datetime = self.date.as_ref().map(|s| s.as_ref()).and_then(parse_datetime); self.datetime_tuple = self.datetime.map(|dt| (dt.year(), dt.month().into(), dt.day())); diff --git a/components/libs/Cargo.toml b/components/libs/Cargo.toml index 7c23ff3127..ea3c82463c 100644 --- a/components/libs/Cargo.toml +++ b/components/libs/Cargo.toml @@ -21,8 +21,8 @@ nom-bibtex = "0.5" num-format = "0.4" once_cell = "1" percent-encoding = "2" -pulldown-cmark = { version = "0.10", default-features = false, features = ["html", "simd"] } -pulldown-cmark-escape = { version = "0.10", default-features = false } +pulldown-cmark = { version = "0.11", default-features = false, features = ["html", "simd"] } +pulldown-cmark-escape = { version = "0.11", default-features = false } quickxml_to_serde = "0.6" rayon = "1" regex = "1" diff --git a/snapcraft.yaml b/snapcraft.yaml index e589dc752c..6de6651043 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -1,5 +1,5 @@ name: zola -version: 0.18.0 +version: 0.19.0 summary: A fast static site generator in a single binary with everything built-in. description: | A fast static site generator in a single binary with everything built-in. @@ -21,7 +21,7 @@ parts: zola: source-type: git source: https://github.com/getzola/zola.git - source-tag: v0.18.0 + source-tag: v0.19.0 plugin: rust rust-channel: stable build-packages: