From e3ab6b8893a548456143335a9b22ff44f7e4b8d4 Mon Sep 17 00:00:00 2001 From: sakex Date: Tue, 26 Sep 2023 21:15:35 +0200 Subject: [PATCH 01/17] Create renderer --- Cargo.lock | 726 +++++++++++++++++- Cargo.toml | 2 +- mdbook-tera-backend/Cargo.toml | 22 + mdbook-tera-backend/src/main.rs | 29 + .../src/tera_renderer/custom_component.rs | 133 ++++ .../src/tera_renderer/error.rs | 25 + mdbook-tera-backend/src/tera_renderer/mod.rs | 7 + .../src/tera_renderer/renderer.rs | 158 ++++ 8 files changed, 1063 insertions(+), 39 deletions(-) create mode 100644 mdbook-tera-backend/Cargo.toml create mode 100644 mdbook-tera-backend/src/main.rs create mode 100644 mdbook-tera-backend/src/tera_renderer/custom_component.rs create mode 100644 mdbook-tera-backend/src/tera_renderer/error.rs create mode 100644 mdbook-tera-backend/src/tera_renderer/mod.rs create mode 100644 mdbook-tera-backend/src/tera_renderer/renderer.rs diff --git a/Cargo.lock b/Cargo.lock index 4cd8b2d7..796f844f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,8 +3,19 @@ version = 3 [[package]] -name = "adler" -version = "1.0.2" +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" @@ -145,6 +156,12 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "cc" version = "1.0.83" @@ -172,6 +189,28 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "chrono-tz" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1369bc6b9e9a7dfdae2055f6ec151fe9c554a9d23d357c0237cee2e25eaabb7" +dependencies = [ + "chrono", + "chrono-tz-build", + "phf 0.11.2", +] + +[[package]] +name = "chrono-tz-build" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2f5ebdc942f57ed96d560a6d1a459bae5851102a25d5bf89dc04ae453e31ecf" +dependencies = [ + "parse-zoneinfo", + "phf 0.11.2", + "phf_codegen 0.11.2", +] + [[package]] name = "clap" version = "4.4.7" @@ -215,6 +254,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -250,14 +295,51 @@ dependencies = [ ] [[package]] -name = "deranged" -version = "0.3.9" +name = "cssparser" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" dependencies = [ - "powerfmt", + "cssparser-macros", + "dtoa-short", + "itoa 0.4.8", + "matches", + "phf 0.8.0", + "proc-macro2", + "quote", + "smallvec", + "syn 1.0.109", ] +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.37", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "deunicode" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95203a6a50906215a502507c0f879a0ce7ff205a6111e2db2a5ef8e4bb92e43" + [[package]] name = "diff" version = "0.1.13" @@ -274,6 +356,30 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "dtoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + +[[package]] +name = "dtoa-short" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74" +dependencies = [ + "dtoa", +] + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + [[package]] name = "env_logger" version = "0.10.0" @@ -325,6 +431,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -335,6 +456,52 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "globset" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "globwalk" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" +dependencies = [ + "bitflags 1.3.2", + "ignore", + "walkdir", +] + [[package]] name = "handlebars" version = "4.4.0" @@ -351,7 +518,16 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.2" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hermit-abi" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" @@ -361,6 +537,15 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +[[package]] +name = "humansize" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm", +] + [[package]] name = "humantime" version = "2.1.0" @@ -391,13 +576,20 @@ dependencies = [ ] [[package]] -name = "indexmap" -version = "2.1.0" +name = "ignore" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" dependencies = [ - "equivalent", - "hashbrown", + "globset", + "lazy_static", + "log", + "memchr", + "regex", + "same-file", + "thread_local", + "walkdir", + "winapi-util", ] [[package]] @@ -411,6 +603,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + [[package]] name = "itoa" version = "1.0.9" @@ -426,6 +624,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.150" @@ -441,6 +651,12 @@ dependencies = [ "safemem", ] +[[package]] +name = "libm" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" + [[package]] name = "linereader" version = "0.4.0" @@ -468,6 +684,32 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "lol_html" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10662f7aad081ec900fd735be33076da75e0389400277dc3734e2b0aa02bb115" +dependencies = [ + "bitflags 2.4.0", + "cfg-if", + "cssparser", + "encoding_rs", + "hashbrown", + "lazy_static", + "lazycell", + "memchr", + "mime", + "safemem", + "selectors", + "thiserror", +] + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + [[package]] name = "mdbook" version = "0.4.35" @@ -513,6 +755,20 @@ dependencies = [ "textwrap", ] +[[package]] +name = "mdbook-tera-backend" +version = "0.0.1" +dependencies = [ + "chrono", + "lol_html", + "mdbook", + "serde", + "serde_json", + "tempfile", + "tera", + "thiserror", +] + [[package]] name = "memchr" version = "2.6.4" @@ -528,6 +784,18 @@ dependencies = [ "adler", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + [[package]] name = "normpath" version = "1.1.1" @@ -585,6 +853,21 @@ dependencies = [ "winapi", ] +[[package]] +name = "parse-zoneinfo" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" +dependencies = [ + "regex", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + [[package]] name = "pest" version = "2.7.5" @@ -616,7 +899,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn", + "syn 2.0.37", ] [[package]] @@ -631,23 +914,95 @@ dependencies = [ ] [[package]] -name = "pkg-config" -version = "0.3.27" +name = "phf" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +dependencies = [ + "phf_macros", + "phf_shared 0.8.0", + "proc-macro-hack", +] [[package]] -name = "plist" -version = "1.6.0" +name = "phf" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ - "base64", - "indexmap", - "line-wrap", - "quick-xml", - "serde", - "time", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", +] + +[[package]] +name = "phf_codegen" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +dependencies = [ + "phf_generator 0.11.2", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_generator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +dependencies = [ + "phf_shared 0.8.0", + "rand 0.7.3", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", ] [[package]] @@ -660,10 +1015,16 @@ dependencies = [ ] [[package]] -name = "powerfmt" -version = "0.2.0" +name = "ppv-lite86" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "pretty_assertions" @@ -675,6 +1036,12 @@ dependencies = [ "yansi", ] +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + [[package]] name = "proc-macro2" version = "1.0.69" @@ -722,6 +1089,87 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", + "rand_pcg", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.10", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core 0.5.1", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -761,8 +1209,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] -name = "regex-syntax" -version = "0.8.2" +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" @@ -800,6 +1257,41 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "selectors" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" +dependencies = [ + "bitflags 1.3.2", + "cssparser", + "derive_more", + "fxhash", + "log", + "matches", + "phf 0.8.0", + "phf_codegen 0.8.0", + "precomputed-hash", + "servo_arc", + "smallvec", + "thin-slice", +] + +[[package]] +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "semver" version = "1.0.20" @@ -823,7 +1315,7 @@ checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.37", ] [[package]] @@ -832,11 +1324,21 @@ version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ - "itoa", + "itoa 1.0.9", "ryu", "serde", ] +[[package]] +name = "servo_arc" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" +dependencies = [ + "nodrop", + "stable_deref_trait", +] + [[package]] name = "sha2" version = "0.10.8" @@ -854,6 +1356,33 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slug" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" +dependencies = [ + "deunicode", +] + +[[package]] +name = "smallvec" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strsim" version = "0.10.0" @@ -862,7 +1391,18 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "2.0.39" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ @@ -905,6 +1445,28 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "tera" +version = "1.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "970dff17c11e884a4a09bc76e3a17ef71e01bb13447a11e85226e254fe6d10b8" +dependencies = [ + "chrono", + "chrono-tz", + "globwalk", + "humansize", + "lazy_static", + "percent-encoding", + "pest", + "pest_derive", + "rand 0.8.5", + "regex", + "serde", + "serde_json", + "slug", + "unic-segment", +] + [[package]] name = "termcolor" version = "1.3.0" @@ -925,8 +1487,14 @@ dependencies = [ ] [[package]] -name = "textwrap" -version = "0.16.0" +name = "thin-slice" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" + +[[package]] +name = "thiserror" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" @@ -947,7 +1515,17 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.37", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", ] [[package]] @@ -1006,6 +1584,56 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-segment" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" +dependencies = [ + "unic-ucd-segment", +] + +[[package]] +name = "unic-ucd-segment" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + [[package]] name = "unicase" version = "2.7.0" @@ -1043,6 +1671,28 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasm-bindgen" version = "0.2.88" @@ -1064,7 +1714,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.37", "wasm-bindgen-shared", ] @@ -1086,7 +1736,7 @@ checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.37", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 2cbe95fd..caa9b4c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,4 @@ [workspace] -members = ["i18n-helpers"] +members = ["i18n-helpers", "mdbook-tera-backend"] default-members = ["i18n-helpers"] resolver = "2" diff --git a/mdbook-tera-backend/Cargo.toml b/mdbook-tera-backend/Cargo.toml new file mode 100644 index 00000000..61410513 --- /dev/null +++ b/mdbook-tera-backend/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "mdbook-tera-backend" +version = "0.0.1" +authors = ["Martin Geisler "] +categories = ["template-engine"] +edition = "2021" +keywords = ["mdbook", "tera", "renderer", "template"] +license = "Apache-2.0" +repository = "https://github.com/google/mdbook-i18n-helpers" +description = "Plugins for a mdbook translation workflow based on Gettext." + +[dependencies] +chrono = { version = "0.4.31", default-features = false, features = ["alloc"] } +lol_html = "1.2.0" +mdbook = { version = "0.4.25", default-features = false } +serde = "1.0" +serde_json = "1.0.91" +tera = "1.19.1" +thiserror = "1.0.48" + +[dev-dependencies] +tempfile = "3.5.0" diff --git a/mdbook-tera-backend/src/main.rs b/mdbook-tera-backend/src/main.rs new file mode 100644 index 00000000..7b48b740 --- /dev/null +++ b/mdbook-tera-backend/src/main.rs @@ -0,0 +1,29 @@ +mod tera_renderer; + +use mdbook::renderer::RenderContext; +use std::io; + +use crate::tera_renderer::*; + +fn main() { + let mut stdin = io::stdin(); + // Get the configs + let ctx = RenderContext::from_json(&mut stdin).unwrap(); + let config: TeraRendererConfig = ctx + .config + .get_deserialized_opt("output.tera-backend") + .expect("Failed to get Gaia config") + .unwrap(); + + let components = config + .create_components(&ctx.root) + .expect("Failed to create components"); + + let mut renderer = Renderer::new(ctx).expect("Failed to create renderer"); + + for component in components { + renderer.add_component(component); + } + + renderer.render_book().expect("Failed to render book"); +} diff --git a/mdbook-tera-backend/src/tera_renderer/custom_component.rs b/mdbook-tera-backend/src/tera_renderer/custom_component.rs new file mode 100644 index 00000000..d800a232 --- /dev/null +++ b/mdbook-tera-backend/src/tera_renderer/custom_component.rs @@ -0,0 +1,133 @@ +use serde::Deserialize; +use std::cell::RefCell; +use std::collections::{BTreeMap, HashMap}; +use std::path::{Path, PathBuf}; + +use tera::Tera; + +use crate::{RendererError, Result}; + +use super::RenderingContext; + +fn make_strip_prefix_function() -> impl tera::Function { + move |args: &HashMap| -> tera::Result { + let string = args + .get("s") + .ok_or_else(|| tera::Error::from(format!("No s argument provided")))? + .as_str() + .ok_or_else(|| tera::Error::from(format!("S has invalid type, expected string")))?; + let prefix = args + .get("prefix") + .ok_or_else(|| tera::Error::from(format!("No prefix argument provided")))? + .as_str() + .ok_or_else(|| { + tera::Error::from(format!("Prefix has invalid type, expected string")) + })?; + string + .strip_prefix(prefix) + .map(|s| tera::Value::String(s.to_owned())) + .ok_or_else(|| tera::Error::from(format!("Could not strip prefix"))) + } +} + +pub struct CustomComponent { + template: Tera, + name: String, + /// Used to generate unique ids for each component to prevent collisions in javascript with query selectors. + counter: RefCell, +} + +impl CustomComponent { + pub fn new(name: &str, template_str: &str, dependencies: &[&Self]) -> Result { + let mut template = Tera::default(); + for dep in dependencies { + template.extend(&dep.template)?; + } + template.add_raw_template(name, template_str)?; + template.register_function("strip_prefix", make_strip_prefix_function()); + + Ok(CustomComponent { + name: String::from(name), + counter: RefCell::new(0), + template, + }) + } + + pub fn register_function(&mut self, name: &str, function: impl tera::Function + 'static) { + self.template.register_function(name, function); + } + + fn create_context( + &self, + rendering_context: &RenderingContext, + attributes: BTreeMap, + ) -> tera::Context { + let counter = self.counter.replace_with(|&mut counter| counter + 1); + let mut context = tera::Context::new(); + context.insert("counter", &counter); + context.insert("language", &rendering_context.language); + context.insert("path", &rendering_context.path); + context.insert("ctx", &rendering_context.serialized_ctx); + context.insert( + "book_dir", + &rendering_context.ctx.destination.parent().unwrap(), + ); + context.insert("attributes", &attributes); + + context + } + + pub fn render( + &self, + rendering_context: &RenderingContext, + attributes: BTreeMap, + ) -> Result { + let context = self.create_context(rendering_context, attributes); + let output = self.template.render(&self.name, &context)?; + Ok(output) + } + + pub fn component_name(&self) -> String { + self.name.clone() + } +} + +#[derive(Deserialize)] +pub struct TeraComponentConfig { + pub name: String, + pub path: PathBuf, + + #[serde(default)] + pub dependencies: Vec, +} + +#[derive(Deserialize)] +pub struct TeraRendererConfig { + pub components: Vec, +} + +impl TeraRendererConfig { + pub fn create_components(&self, current_dir: &Path) -> Result> { + let mut name_to_component = HashMap::new(); + for component in &self.components { + let component_path = current_dir.join(&component.path); + let template_str = std::fs::read_to_string(&component_path)?; + let dependencies = component + .dependencies + .iter() + .map(|name| { + name_to_component.get(name).ok_or_else(|| { + RendererError::DependencyNotFound(format!( + "Could not find depdendency {}", + name + )) + }) + }) + .collect::>>()?; + let new_component = + CustomComponent::new(&component.name, &template_str, &dependencies)?; + name_to_component.insert(component.name.clone(), new_component); + } + Ok(name_to_component.into_values().collect()) + } +} diff --git a/mdbook-tera-backend/src/tera_renderer/error.rs b/mdbook-tera-backend/src/tera_renderer/error.rs new file mode 100644 index 00000000..7b64b226 --- /dev/null +++ b/mdbook-tera-backend/src/tera_renderer/error.rs @@ -0,0 +1,25 @@ +use std::path::StripPrefixError; + +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum RendererError { + #[error("IO Error: {0}")] + IoError(#[from] std::io::Error), + #[error("Invalid path: {0}")] + InvalidPath(String), + #[error("Error rendering tera template: {0}")] + TeraError(#[from] tera::Error), + #[error("HTML Error: {0}")] + HtmlRewritingError(#[from] lol_html::errors::RewritingError), + #[error("Mdbook Error: {0}")] + Mdbook(#[from] mdbook::errors::Error), + #[error("Error in strip_prefix call: {0}")] + StripPrefixError(#[from] StripPrefixError), + #[error("Serde error: {0}")] + SerdeError(#[from] serde_json::Error), + #[error("Serde error: {0}")] + DependencyNotFound(String), +} + +pub type Result = std::result::Result; diff --git a/mdbook-tera-backend/src/tera_renderer/mod.rs b/mdbook-tera-backend/src/tera_renderer/mod.rs new file mode 100644 index 00000000..0a5d101b --- /dev/null +++ b/mdbook-tera-backend/src/tera_renderer/mod.rs @@ -0,0 +1,7 @@ +mod custom_component; +mod error; +mod renderer; + +pub(crate) use custom_component::*; +pub(crate) use error::*; +pub(crate) use renderer::*; diff --git a/mdbook-tera-backend/src/tera_renderer/renderer.rs b/mdbook-tera-backend/src/tera_renderer/renderer.rs new file mode 100644 index 00000000..17256630 --- /dev/null +++ b/mdbook-tera-backend/src/tera_renderer/renderer.rs @@ -0,0 +1,158 @@ +use super::error::RendererError; +use super::CustomComponent; +use crate::tera_renderer::error::Result; +use lol_html::html_content::ContentType; +use lol_html::{element, RewriteStrSettings}; +use mdbook::renderer::RenderContext; +use serde_json::to_value; +use std::collections::{BTreeMap, HashMap}; +use std::fs; +use std::io::{Read, Write}; +use std::path::{Path, PathBuf}; +use std::sync::Arc; + +pub struct RenderingContext<'a> { + pub path: PathBuf, + pub language: Option, + pub serialized_ctx: &'a serde_json::Value, + pub ctx: &'a RenderContext, +} + +impl<'a> RenderingContext<'a> { + fn new( + path: PathBuf, + language: Option, + serialized_ctx: &'a serde_json::Value, + ctx: &'a RenderContext, + ) -> Result { + Ok(RenderingContext { + path, + language, + serialized_ctx, + ctx, + }) + } +} + +pub(crate) struct Renderer { + ctx: Arc, + serialized_ctx: serde_json::Value, + components: Vec, +} + +impl Renderer { + pub(crate) fn new(ctx: RenderContext) -> Result { + Ok(Renderer { + serialized_ctx: serde_json::to_value(&ctx)?, + ctx: Arc::new(ctx), + components: Vec::new(), + }) + } + + pub(crate) fn add_component(&mut self, mut component: CustomComponent) { + component.register_function("get_context", self.create_get_context_function()); + self.components.push(component); + } + + fn create_get_context_function(&self) -> impl tera::Function { + let ctx_rx = Arc::clone(&self.ctx); + move |args: &HashMap| -> tera::Result { + let key = args + .get("key") + .ok_or_else(|| tera::Error::from(format!("No key argument provided")))? + .as_str() + .ok_or_else(|| { + tera::Error::from(format!("Key has invalid type, expected string")) + })?; + let value = ctx_rx + .config + .get(key) + .ok_or_else(|| tera::Error::from(format!("Could not find key {key} in config")))?; + let value = to_value(value)?; + Ok(value) + } + } + + pub(crate) fn render_book(&mut self) -> Result<()> { + let dest_dir = &self + .ctx + .destination + .parent() + .ok_or_else(|| { + RendererError::InvalidPath(format!( + "Destination directory {:?} has no parent", + self.ctx.destination + )) + })? + .to_owned(); + if !dest_dir.is_dir() { + return Err(RendererError::InvalidPath(format!( + "{:?} is not a directory", + dest_dir + ))); + } + self.render_book_directory(&dest_dir) + } + + fn render_book_directory(&mut self, path: &Path) -> Result<()> { + for entry in path.read_dir()? { + let entry = entry?; + let path = entry.path(); + if path.is_dir() { + self.render_book_directory(&path)?; + } else { + self.process_file(&path)?; + } + } + Ok(()) + } + + fn process_file(&mut self, path: &Path) -> Result<()> { + if path.extension().unwrap_or_default() != "html" { + return Ok(()); + } + let mut file_content = String::new(); + { + let mut file = fs::File::open(path)?; + file.read_to_string(&mut file_content)?; + } + + let output = self.render_components(&file_content, path)?; + let mut output_file = fs::File::create(path)?; + output_file.write_all(output.as_bytes())?; + Ok(()) + } + + fn render_components(&mut self, file_content: &str, path: &Path) -> Result { + let rendering_context = RenderingContext::new( + path.to_owned(), + self.ctx.config.book.language.clone(), + &self.serialized_ctx, + &self.ctx, + )?; + let custom_components_handlers = self + .components + .iter() + .map(|component| { + element!(component.component_name(), |el| { + let attributes: BTreeMap = el + .attributes() + .iter() + .map(|attribute| (attribute.name(), attribute.value())) + .collect(); + let rendered = component.render(&rendering_context, attributes)?; + el.replace(&rendered, ContentType::Html); + Ok(()) + }) + }) + .collect(); + let output = lol_html::rewrite_str( + file_content, + RewriteStrSettings { + element_content_handlers: custom_components_handlers, + ..RewriteStrSettings::default() + }, + )?; + Ok(output) + } +} From ef30e5febe15f3ef8f30e3ee6bb7d3dbfbd93a8e Mon Sep 17 00:00:00 2001 From: sakex Date: Sun, 8 Oct 2023 13:25:27 +0200 Subject: [PATCH 02/17] Load templates from directory --- Cargo.lock | 2 +- mdbook-tera-backend/Cargo.toml | 6 +- mdbook-tera-backend/src/main.rs | 6 +- .../src/tera_renderer/custom_component.rs | 152 ++++++++---------- .../src/tera_renderer/error.rs | 25 --- mdbook-tera-backend/src/tera_renderer/mod.rs | 2 - .../src/tera_renderer/renderer.rs | 35 ++-- 7 files changed, 97 insertions(+), 131 deletions(-) delete mode 100644 mdbook-tera-backend/src/tera_renderer/error.rs diff --git a/Cargo.lock b/Cargo.lock index 796f844f..3f544e30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -759,6 +759,7 @@ dependencies = [ name = "mdbook-tera-backend" version = "0.0.1" dependencies = [ + "anyhow", "chrono", "lol_html", "mdbook", @@ -766,7 +767,6 @@ dependencies = [ "serde_json", "tempfile", "tera", - "thiserror", ] [[package]] diff --git a/mdbook-tera-backend/Cargo.toml b/mdbook-tera-backend/Cargo.toml index 61410513..b5dffed9 100644 --- a/mdbook-tera-backend/Cargo.toml +++ b/mdbook-tera-backend/Cargo.toml @@ -1,22 +1,22 @@ [package] name = "mdbook-tera-backend" version = "0.0.1" -authors = ["Martin Geisler "] +authors = ["Martin Geisler ", "Alexandre Senges "] categories = ["template-engine"] edition = "2021" keywords = ["mdbook", "tera", "renderer", "template"] license = "Apache-2.0" repository = "https://github.com/google/mdbook-i18n-helpers" -description = "Plugins for a mdbook translation workflow based on Gettext." +description = "Plugin to extend mdbook with Tera templates and custom HTML components." [dependencies] +anyhow = "1.0.75" chrono = { version = "0.4.31", default-features = false, features = ["alloc"] } lol_html = "1.2.0" mdbook = { version = "0.4.25", default-features = false } serde = "1.0" serde_json = "1.0.91" tera = "1.19.1" -thiserror = "1.0.48" [dev-dependencies] tempfile = "3.5.0" diff --git a/mdbook-tera-backend/src/main.rs b/mdbook-tera-backend/src/main.rs index 7b48b740..ac3f1713 100644 --- a/mdbook-tera-backend/src/main.rs +++ b/mdbook-tera-backend/src/main.rs @@ -15,11 +15,11 @@ fn main() { .expect("Failed to get Gaia config") .unwrap(); - let components = config - .create_components(&ctx.root) + let (tera_template, components) = config + .create_template_and_components(&ctx.root) .expect("Failed to create components"); - let mut renderer = Renderer::new(ctx).expect("Failed to create renderer"); + let mut renderer = Renderer::new(ctx, tera_template).expect("Failed to create renderer"); for component in components { renderer.add_component(component); diff --git a/mdbook-tera-backend/src/tera_renderer/custom_component.rs b/mdbook-tera-backend/src/tera_renderer/custom_component.rs index d800a232..a8074d21 100644 --- a/mdbook-tera-backend/src/tera_renderer/custom_component.rs +++ b/mdbook-tera-backend/src/tera_renderer/custom_component.rs @@ -1,35 +1,10 @@ +use anyhow::Result; use serde::Deserialize; use std::cell::RefCell; -use std::collections::{BTreeMap, HashMap}; +use std::collections::BTreeMap; use std::path::{Path, PathBuf}; - use tera::Tera; -use crate::{RendererError, Result}; - -use super::RenderingContext; - -fn make_strip_prefix_function() -> impl tera::Function { - move |args: &HashMap| -> tera::Result { - let string = args - .get("s") - .ok_or_else(|| tera::Error::from(format!("No s argument provided")))? - .as_str() - .ok_or_else(|| tera::Error::from(format!("S has invalid type, expected string")))?; - let prefix = args - .get("prefix") - .ok_or_else(|| tera::Error::from(format!("No prefix argument provided")))? - .as_str() - .ok_or_else(|| { - tera::Error::from(format!("Prefix has invalid type, expected string")) - })?; - string - .strip_prefix(prefix) - .map(|s| tera::Value::String(s.to_owned())) - .ok_or_else(|| tera::Error::from(format!("Could not strip prefix"))) - } -} - pub struct CustomComponent { template: Tera, name: String, @@ -38,14 +13,7 @@ pub struct CustomComponent { } impl CustomComponent { - pub fn new(name: &str, template_str: &str, dependencies: &[&Self]) -> Result { - let mut template = Tera::default(); - for dep in dependencies { - template.extend(&dep.template)?; - } - template.add_raw_template(name, template_str)?; - template.register_function("strip_prefix", make_strip_prefix_function()); - + pub fn new(name: &str, template: Tera) -> Result { Ok(CustomComponent { name: String::from(name), counter: RefCell::new(0), @@ -57,33 +25,17 @@ impl CustomComponent { self.template.register_function(name, function); } - fn create_context( - &self, - rendering_context: &RenderingContext, - attributes: BTreeMap, - ) -> tera::Context { - let counter = self.counter.replace_with(|&mut counter| counter + 1); - let mut context = tera::Context::new(); - context.insert("counter", &counter); - context.insert("language", &rendering_context.language); - context.insert("path", &rendering_context.path); - context.insert("ctx", &rendering_context.serialized_ctx); - context.insert( - "book_dir", - &rendering_context.ctx.destination.parent().unwrap(), - ); - context.insert("attributes", &attributes); - - context - } - pub fn render( &self, - rendering_context: &RenderingContext, + tera_context: &tera::Context, attributes: BTreeMap, ) -> Result { - let context = self.create_context(rendering_context, attributes); - let output = self.template.render(&self.name, &context)?; + let counter = self.counter.replace_with(|&mut counter| counter + 1); + let mut tera_context = tera_context.clone(); + tera_context.insert("count", &counter); + tera_context.insert("attributes", &attributes); + + let output = self.template.render(&self.name, &tera_context)?; Ok(output) } @@ -93,41 +45,69 @@ impl CustomComponent { } #[derive(Deserialize)] -pub struct TeraComponentConfig { - pub name: String, - pub path: PathBuf, - - #[serde(default)] - pub dependencies: Vec, +pub enum Component { + Named { name: String, path: PathBuf }, + Anonymous(PathBuf), } +/// Configuration in `book.toml` `[output.tera-renderer]`. #[derive(Deserialize)] pub struct TeraRendererConfig { - pub components: Vec, + /// Relative path to the templates directory. + pub templates_dir: PathBuf, + /// Custom HTML components to register. + #[serde(default)] + pub html_components: Vec, } impl TeraRendererConfig { - pub fn create_components(&self, current_dir: &Path) -> Result> { - let mut name_to_component = HashMap::new(); - for component in &self.components { - let component_path = current_dir.join(&component.path); - let template_str = std::fs::read_to_string(&component_path)?; - let dependencies = component - .dependencies - .iter() - .map(|name| { - name_to_component.get(name).ok_or_else(|| { - RendererError::DependencyNotFound(format!( - "Could not find depdendency {}", - name - )) - }) - }) - .collect::>>()?; - let new_component = - CustomComponent::new(&component.name, &template_str, &dependencies)?; - name_to_component.insert(component.name.clone(), new_component); + fn add_templates_recursively(tera_template: &mut Tera, directory: &Path) -> Result<()> { + for entry in std::fs::read_dir(directory)? { + let entry = entry?; + let path = entry.path(); + if path.is_dir() { + Self::add_templates_recursively(tera_template, &path)?; + } else { + tera_template.add_template_file(&path, path.file_name().unwrap().to_str())?; + } } - Ok(name_to_component.into_values().collect()) + Ok(()) + } + + fn create_custom_components(&self, tera_template: &Tera) -> Result> { + self.html_components + .iter() + .map(|component| { + Ok(match component { + Component::Named { name, path } => { + let mut template = tera_template.clone(); + template.add_template_file(path, Some(name))?; + CustomComponent::new(name, template)? + } + Component::Anonymous(path) => { + let name = path + .file_name() + .unwrap_or_default() + .to_str() + .unwrap_or_default(); + CustomComponent::new(name, tera_template.clone())? + } + }) + }) + .collect() + } + + pub fn create_template_and_components( + &self, + current_dir: &Path, + ) -> Result<(Tera, Vec)> { + let mut tera_template = Tera::default(); + Self::add_templates_recursively( + &mut tera_template, + ¤t_dir.join(&self.templates_dir), + )?; + let components = self.create_custom_components(&tera_template)?; + + Ok((tera_template, components)) } } diff --git a/mdbook-tera-backend/src/tera_renderer/error.rs b/mdbook-tera-backend/src/tera_renderer/error.rs deleted file mode 100644 index 7b64b226..00000000 --- a/mdbook-tera-backend/src/tera_renderer/error.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::path::StripPrefixError; - -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum RendererError { - #[error("IO Error: {0}")] - IoError(#[from] std::io::Error), - #[error("Invalid path: {0}")] - InvalidPath(String), - #[error("Error rendering tera template: {0}")] - TeraError(#[from] tera::Error), - #[error("HTML Error: {0}")] - HtmlRewritingError(#[from] lol_html::errors::RewritingError), - #[error("Mdbook Error: {0}")] - Mdbook(#[from] mdbook::errors::Error), - #[error("Error in strip_prefix call: {0}")] - StripPrefixError(#[from] StripPrefixError), - #[error("Serde error: {0}")] - SerdeError(#[from] serde_json::Error), - #[error("Serde error: {0}")] - DependencyNotFound(String), -} - -pub type Result = std::result::Result; diff --git a/mdbook-tera-backend/src/tera_renderer/mod.rs b/mdbook-tera-backend/src/tera_renderer/mod.rs index 0a5d101b..cf9da0a8 100644 --- a/mdbook-tera-backend/src/tera_renderer/mod.rs +++ b/mdbook-tera-backend/src/tera_renderer/mod.rs @@ -1,7 +1,5 @@ mod custom_component; -mod error; mod renderer; pub(crate) use custom_component::*; -pub(crate) use error::*; pub(crate) use renderer::*; diff --git a/mdbook-tera-backend/src/tera_renderer/renderer.rs b/mdbook-tera-backend/src/tera_renderer/renderer.rs index 17256630..077ebee8 100644 --- a/mdbook-tera-backend/src/tera_renderer/renderer.rs +++ b/mdbook-tera-backend/src/tera_renderer/renderer.rs @@ -1,6 +1,5 @@ -use super::error::RendererError; use super::CustomComponent; -use crate::tera_renderer::error::Result; +use anyhow::{anyhow, Result}; use lol_html::html_content::ContentType; use lol_html::{element, RewriteStrSettings}; use mdbook::renderer::RenderContext; @@ -10,6 +9,7 @@ use std::fs; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; use std::sync::Arc; +use tera::Tera; pub struct RenderingContext<'a> { pub path: PathBuf, @@ -38,14 +38,16 @@ pub(crate) struct Renderer { ctx: Arc, serialized_ctx: serde_json::Value, components: Vec, + tera_template: Tera, } impl Renderer { - pub(crate) fn new(ctx: RenderContext) -> Result { + pub(crate) fn new(ctx: RenderContext, tera_template: Tera) -> Result { Ok(Renderer { serialized_ctx: serde_json::to_value(&ctx)?, ctx: Arc::new(ctx), components: Vec::new(), + tera_template, }) } @@ -79,17 +81,14 @@ impl Renderer { .destination .parent() .ok_or_else(|| { - RendererError::InvalidPath(format!( + anyhow!( "Destination directory {:?} has no parent", self.ctx.destination - )) + ) })? .to_owned(); if !dest_dir.is_dir() { - return Err(RendererError::InvalidPath(format!( - "{:?} is not a directory", - dest_dir - ))); + return Err(anyhow!("{:?} is not a directory", dest_dir)); } self.render_book_directory(&dest_dir) } @@ -123,6 +122,18 @@ impl Renderer { Ok(()) } + fn create_context(&self, rendering_context: &RenderingContext) -> tera::Context { + let mut context = tera::Context::new(); + context.insert("path", &rendering_context.path); + context.insert("ctx", &rendering_context.serialized_ctx); + context.insert( + "book_dir", + &rendering_context.ctx.destination.parent().unwrap(), + ); + + context + } + fn render_components(&mut self, file_content: &str, path: &Path) -> Result { let rendering_context = RenderingContext::new( path.to_owned(), @@ -130,6 +141,8 @@ impl Renderer { &self.serialized_ctx, &self.ctx, )?; + let tera_context = self.create_context(&rendering_context); + let rendered_file = self.tera_template.render_str(file_content, &tera_context)?; let custom_components_handlers = self .components .iter() @@ -140,14 +153,14 @@ impl Renderer { .iter() .map(|attribute| (attribute.name(), attribute.value())) .collect(); - let rendered = component.render(&rendering_context, attributes)?; + let rendered = component.render(&tera_context, attributes)?; el.replace(&rendered, ContentType::Html); Ok(()) }) }) .collect(); let output = lol_html::rewrite_str( - file_content, + &rendered_file, RewriteStrSettings { element_content_handlers: custom_components_handlers, ..RewriteStrSettings::default() From 04629deee2cf91d686830ba1b6edfb9f8595a867 Mon Sep 17 00:00:00 2001 From: sakex Date: Sun, 8 Oct 2023 14:43:57 +0200 Subject: [PATCH 03/17] Fix --- mdbook-tera-backend/src/main.rs | 6 +- .../src/tera_renderer/custom_component.rs | 31 +++--- mdbook-tera-backend/src/tera_renderer/mod.rs | 7 +- .../src/tera_renderer/renderer.rs | 94 ++++++------------- 4 files changed, 53 insertions(+), 85 deletions(-) diff --git a/mdbook-tera-backend/src/main.rs b/mdbook-tera-backend/src/main.rs index ac3f1713..64c7009e 100644 --- a/mdbook-tera-backend/src/main.rs +++ b/mdbook-tera-backend/src/main.rs @@ -3,16 +3,16 @@ mod tera_renderer; use mdbook::renderer::RenderContext; use std::io; -use crate::tera_renderer::*; +use crate::tera_renderer::custom_component::TeraRendererConfig; +use crate::tera_renderer::renderer::Renderer; fn main() { let mut stdin = io::stdin(); - // Get the configs let ctx = RenderContext::from_json(&mut stdin).unwrap(); let config: TeraRendererConfig = ctx .config .get_deserialized_opt("output.tera-backend") - .expect("Failed to get Gaia config") + .expect("Failed to get tera-backend config") .unwrap(); let (tera_template, components) = config diff --git a/mdbook-tera-backend/src/tera_renderer/custom_component.rs b/mdbook-tera-backend/src/tera_renderer/custom_component.rs index a8074d21..a2eeb816 100644 --- a/mdbook-tera-backend/src/tera_renderer/custom_component.rs +++ b/mdbook-tera-backend/src/tera_renderer/custom_component.rs @@ -1,6 +1,5 @@ use anyhow::Result; use serde::Deserialize; -use std::cell::RefCell; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use tera::Tera; @@ -8,15 +7,12 @@ use tera::Tera; pub struct CustomComponent { template: Tera, name: String, - /// Used to generate unique ids for each component to prevent collisions in javascript with query selectors. - counter: RefCell, } impl CustomComponent { pub fn new(name: &str, template: Tera) -> Result { Ok(CustomComponent { name: String::from(name), - counter: RefCell::new(0), template, }) } @@ -30,13 +26,15 @@ impl CustomComponent { tera_context: &tera::Context, attributes: BTreeMap, ) -> Result { - let counter = self.counter.replace_with(|&mut counter| counter + 1); let mut tera_context = tera_context.clone(); - tera_context.insert("count", &counter); tera_context.insert("attributes", &attributes); + let output = self.template.render(&self.name, &tera_context); - let output = self.template.render(&self.name, &tera_context)?; - Ok(output) + if let Err(err) = &output { + println!("Error rendering component {}: {:?}", self.name, err); + } + + Ok(output?) } pub fn component_name(&self) -> String { @@ -45,6 +43,7 @@ impl CustomComponent { } #[derive(Deserialize)] +#[serde(untagged)] pub enum Component { Named { name: String, path: PathBuf }, Anonymous(PathBuf), @@ -53,7 +52,7 @@ pub enum Component { /// Configuration in `book.toml` `[output.tera-renderer]`. #[derive(Deserialize)] pub struct TeraRendererConfig { - /// Relative path to the templates directory. + /// Relative path to the templates directory from the `book.toml` directory. pub templates_dir: PathBuf, /// Custom HTML components to register. #[serde(default)] @@ -74,7 +73,11 @@ impl TeraRendererConfig { Ok(()) } - fn create_custom_components(&self, tera_template: &Tera) -> Result> { + fn create_custom_components( + &self, + tera_template: &Tera, + current_dir: &Path, + ) -> Result> { self.html_components .iter() .map(|component| { @@ -85,12 +88,14 @@ impl TeraRendererConfig { CustomComponent::new(name, template)? } Component::Anonymous(path) => { + let mut template = tera_template.clone(); let name = path - .file_name() + .file_stem() .unwrap_or_default() .to_str() .unwrap_or_default(); - CustomComponent::new(name, tera_template.clone())? + template.add_template_file(current_dir.join(path), Some(name))?; + CustomComponent::new(name, template)? } }) }) @@ -106,7 +111,7 @@ impl TeraRendererConfig { &mut tera_template, ¤t_dir.join(&self.templates_dir), )?; - let components = self.create_custom_components(&tera_template)?; + let components = self.create_custom_components(&tera_template, current_dir)?; Ok((tera_template, components)) } diff --git a/mdbook-tera-backend/src/tera_renderer/mod.rs b/mdbook-tera-backend/src/tera_renderer/mod.rs index cf9da0a8..d366ed6f 100644 --- a/mdbook-tera-backend/src/tera_renderer/mod.rs +++ b/mdbook-tera-backend/src/tera_renderer/mod.rs @@ -1,5 +1,2 @@ -mod custom_component; -mod renderer; - -pub(crate) use custom_component::*; -pub(crate) use renderer::*; +pub(crate) mod custom_component; +pub(crate) mod renderer; diff --git a/mdbook-tera-backend/src/tera_renderer/renderer.rs b/mdbook-tera-backend/src/tera_renderer/renderer.rs index 077ebee8..1eb0771f 100644 --- a/mdbook-tera-backend/src/tera_renderer/renderer.rs +++ b/mdbook-tera-backend/src/tera_renderer/renderer.rs @@ -1,4 +1,4 @@ -use super::CustomComponent; +use super::custom_component::CustomComponent; use anyhow::{anyhow, Result}; use lol_html::html_content::ContentType; use lol_html::{element, RewriteStrSettings}; @@ -6,49 +6,32 @@ use mdbook::renderer::RenderContext; use serde_json::to_value; use std::collections::{BTreeMap, HashMap}; use std::fs; -use std::io::{Read, Write}; -use std::path::{Path, PathBuf}; +use std::io::Write; +use std::path::Path; use std::sync::Arc; use tera::Tera; -pub struct RenderingContext<'a> { - pub path: PathBuf, - pub language: Option, - pub serialized_ctx: &'a serde_json::Value, - pub ctx: &'a RenderContext, -} - -impl<'a> RenderingContext<'a> { - fn new( - path: PathBuf, - language: Option, - serialized_ctx: &'a serde_json::Value, - ctx: &'a RenderContext, - ) -> Result { - Ok(RenderingContext { - path, - language, - serialized_ctx, - ctx, - }) - } -} - pub(crate) struct Renderer { ctx: Arc, serialized_ctx: serde_json::Value, components: Vec, + counter: u64, tera_template: Tera, } impl Renderer { pub(crate) fn new(ctx: RenderContext, tera_template: Tera) -> Result { - Ok(Renderer { + let mut renderer = Renderer { serialized_ctx: serde_json::to_value(&ctx)?, ctx: Arc::new(ctx), components: Vec::new(), + counter: 0, tera_template, - }) + }; + renderer + .tera_template + .register_function("get_context", renderer.create_get_context_function()); + Ok(renderer) } pub(crate) fn add_component(&mut self, mut component: CustomComponent) { @@ -57,7 +40,7 @@ impl Renderer { } fn create_get_context_function(&self) -> impl tera::Function { - let ctx_rx = Arc::clone(&self.ctx); + let ctx_rc = Arc::clone(&self.ctx); move |args: &HashMap| -> tera::Result { let key = args .get("key") @@ -66,7 +49,7 @@ impl Renderer { .ok_or_else(|| { tera::Error::from(format!("Key has invalid type, expected string")) })?; - let value = ctx_rx + let value = ctx_rc .config .get(key) .ok_or_else(|| tera::Error::from(format!("Could not find key {key} in config")))?; @@ -76,21 +59,11 @@ impl Renderer { } pub(crate) fn render_book(&mut self) -> Result<()> { - let dest_dir = &self - .ctx - .destination - .parent() - .ok_or_else(|| { - anyhow!( - "Destination directory {:?} has no parent", - self.ctx.destination - ) - })? - .to_owned(); + let dest_dir = &self.ctx.destination.parent().unwrap(); if !dest_dir.is_dir() { - return Err(anyhow!("{:?} is not a directory", dest_dir)); + return Err(anyhow!("{dest_dir:?} is not a directory")); } - self.render_book_directory(&dest_dir) + self.render_book_directory(dest_dir) } fn render_book_directory(&mut self, path: &Path) -> Result<()> { @@ -110,39 +83,32 @@ impl Renderer { if path.extension().unwrap_or_default() != "html" { return Ok(()); } - let mut file_content = String::new(); - { - let mut file = fs::File::open(path)?; - file.read_to_string(&mut file_content)?; - } - + let file_content = std::fs::read_to_string(path)?; let output = self.render_components(&file_content, path)?; let mut output_file = fs::File::create(path)?; output_file.write_all(output.as_bytes())?; Ok(()) } - fn create_context(&self, rendering_context: &RenderingContext) -> tera::Context { + fn create_context(&mut self, path: &Path) -> tera::Context { let mut context = tera::Context::new(); - context.insert("path", &rendering_context.path); - context.insert("ctx", &rendering_context.serialized_ctx); - context.insert( - "book_dir", - &rendering_context.ctx.destination.parent().unwrap(), - ); + context.insert("path", path); + context.insert("ctx", &self.serialized_ctx); + context.insert("book_dir", &self.ctx.destination.parent().unwrap()); + context.insert("counter", &self.counter); + context.insert("attributes", &BTreeMap::::new()); + self.counter += 1; context } fn render_components(&mut self, file_content: &str, path: &Path) -> Result { - let rendering_context = RenderingContext::new( - path.to_owned(), - self.ctx.config.book.language.clone(), - &self.serialized_ctx, - &self.ctx, - )?; - let tera_context = self.create_context(&rendering_context); - let rendered_file = self.tera_template.render_str(file_content, &tera_context)?; + let tera_context = self.create_context(path); + + let rendered_file = self + .tera_template + .render_str(file_content, &tera_context) + .map_err(|e| anyhow!("Error rendering file {path:?}: {e:?}"))?; let custom_components_handlers = self .components .iter() From 5061842ae35a3cc1a77e795eff9b2a552460d597 Mon Sep 17 00:00:00 2001 From: sakex Date: Sun, 8 Oct 2023 14:43:57 +0200 Subject: [PATCH 04/17] Fix --- mdbook-tera-backend/src/tera_renderer/renderer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mdbook-tera-backend/src/tera_renderer/renderer.rs b/mdbook-tera-backend/src/tera_renderer/renderer.rs index 1eb0771f..8ca411c5 100644 --- a/mdbook-tera-backend/src/tera_renderer/renderer.rs +++ b/mdbook-tera-backend/src/tera_renderer/renderer.rs @@ -59,7 +59,7 @@ impl Renderer { } pub(crate) fn render_book(&mut self) -> Result<()> { - let dest_dir = &self.ctx.destination.parent().unwrap(); + let dest_dir = self.ctx.destination.parent().unwrap().to_owned(); if !dest_dir.is_dir() { return Err(anyhow!("{dest_dir:?} is not a directory")); } From f913253ea1aba17a90a2ced0c026e16a7d109843 Mon Sep 17 00:00:00 2001 From: sakex Date: Sun, 8 Oct 2023 14:43:57 +0200 Subject: [PATCH 05/17] Fix --- mdbook-tera-backend/src/tera_renderer/renderer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mdbook-tera-backend/src/tera_renderer/renderer.rs b/mdbook-tera-backend/src/tera_renderer/renderer.rs index 8ca411c5..d517b402 100644 --- a/mdbook-tera-backend/src/tera_renderer/renderer.rs +++ b/mdbook-tera-backend/src/tera_renderer/renderer.rs @@ -63,7 +63,7 @@ impl Renderer { if !dest_dir.is_dir() { return Err(anyhow!("{dest_dir:?} is not a directory")); } - self.render_book_directory(dest_dir) + self.render_book_directory(&dest_dir) } fn render_book_directory(&mut self, path: &Path) -> Result<()> { From df1595391c33af04186801fbb787430a9fe13257 Mon Sep 17 00:00:00 2001 From: sakex Date: Fri, 20 Oct 2023 13:44:30 +0200 Subject: [PATCH 06/17] Remove custom components --- Cargo.lock | 404 +----------------- mdbook-tera-backend/Cargo.toml | 1 - mdbook-tera-backend/src/main.rs | 6 +- .../src/tera_renderer/custom_component.rs | 86 +--- .../src/tera_renderer/renderer.rs | 39 +- 5 files changed, 26 insertions(+), 510 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3f544e30..40efa394 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,17 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "ahash" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", -] - [[package]] name = "aho-corasick" version = "1.1.0" @@ -156,12 +145,6 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - [[package]] name = "cc" version = "1.0.83" @@ -197,7 +180,7 @@ checksum = "f1369bc6b9e9a7dfdae2055f6ec151fe9c554a9d23d357c0237cee2e25eaabb7" dependencies = [ "chrono", "chrono-tz-build", - "phf 0.11.2", + "phf", ] [[package]] @@ -207,8 +190,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2f5ebdc942f57ed96d560a6d1a459bae5851102a25d5bf89dc04ae453e31ecf" dependencies = [ "parse-zoneinfo", - "phf 0.11.2", - "phf_codegen 0.11.2", + "phf", + "phf_codegen", ] [[package]] @@ -254,12 +237,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -294,46 +271,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "cssparser" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa 0.4.8", - "matches", - "phf 0.8.0", - "proc-macro2", - "quote", - "smallvec", - "syn 1.0.109", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote", - "syn 2.0.37", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 1.0.109", -] - [[package]] name = "deunicode" version = "0.4.4" @@ -356,30 +293,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "dtoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" - -[[package]] -name = "dtoa-short" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74" -dependencies = [ - "dtoa", -] - -[[package]] -name = "encoding_rs" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" -dependencies = [ - "cfg-if", -] - [[package]] name = "env_logger" version = "0.10.0" @@ -437,15 +350,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -456,17 +360,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.10" @@ -475,7 +368,7 @@ checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -516,15 +409,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash", -] - [[package]] name = "hermit-abi" version = "0.3.2" @@ -603,12 +487,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - [[package]] name = "itoa" version = "1.0.9" @@ -630,12 +508,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.150" @@ -684,32 +556,6 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" -[[package]] -name = "lol_html" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10662f7aad081ec900fd735be33076da75e0389400277dc3734e2b0aa02bb115" -dependencies = [ - "bitflags 2.4.0", - "cfg-if", - "cssparser", - "encoding_rs", - "hashbrown", - "lazy_static", - "lazycell", - "memchr", - "mime", - "safemem", - "selectors", - "thiserror", -] - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "mdbook" version = "0.4.35" @@ -761,7 +607,6 @@ version = "0.0.1" dependencies = [ "anyhow", "chrono", - "lol_html", "mdbook", "serde", "serde_json", @@ -784,18 +629,6 @@ dependencies = [ "adler", ] -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - [[package]] name = "normpath" version = "1.1.1" @@ -899,7 +732,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.37", + "syn", ] [[package]] @@ -913,34 +746,13 @@ dependencies = [ "sha2", ] -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_macros", - "phf_shared 0.8.0", - "proc-macro-hack", -] - [[package]] name = "phf" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", + "phf_shared", ] [[package]] @@ -949,18 +761,8 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", + "phf_generator", + "phf_shared", ] [[package]] @@ -969,31 +771,8 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ - "phf_shared 0.11.2", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher", + "phf_shared", + "rand", ] [[package]] @@ -1020,12 +799,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - [[package]] name = "pretty_assertions" version = "1.4.0" @@ -1036,12 +809,6 @@ dependencies = [ "yansi", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" version = "1.0.69" @@ -1089,20 +856,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - [[package]] name = "rand" version = "0.8.5" @@ -1110,18 +863,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "rand_chacha", + "rand_core", ] [[package]] @@ -1131,16 +874,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", + "rand_core", ] [[package]] @@ -1149,25 +883,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.10", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", + "getrandom", ] [[package]] @@ -1208,15 +924,6 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - [[package]] name = "rustix" version = "0.38.13" @@ -1242,12 +949,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" - [[package]] name = "same-file" version = "1.0.6" @@ -1257,26 +958,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "selectors" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" -dependencies = [ - "bitflags 1.3.2", - "cssparser", - "derive_more", - "fxhash", - "log", - "matches", - "phf 0.8.0", - "phf_codegen 0.8.0", - "precomputed-hash", - "servo_arc", - "smallvec", - "thin-slice", -] - [[package]] name = "semver" version = "1.0.18" @@ -1315,7 +996,7 @@ checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn", ] [[package]] @@ -1324,21 +1005,11 @@ version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ - "itoa 1.0.9", + "itoa", "ryu", "serde", ] -[[package]] -name = "servo_arc" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" -dependencies = [ - "nodrop", - "stable_deref_trait", -] - [[package]] name = "sha2" version = "0.10.8" @@ -1371,35 +1042,12 @@ dependencies = [ "deunicode", ] -[[package]] -name = "smallvec" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.37" @@ -1459,7 +1107,7 @@ dependencies = [ "percent-encoding", "pest", "pest_derive", - "rand 0.8.5", + "rand", "regex", "serde", "serde_json", @@ -1486,12 +1134,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "thin-slice" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" - [[package]] name = "thiserror" version = "1.0.48" @@ -1515,7 +1157,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn", ] [[package]] @@ -1671,12 +1313,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1714,7 +1350,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.37", + "syn", "wasm-bindgen-shared", ] @@ -1736,7 +1372,7 @@ checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/mdbook-tera-backend/Cargo.toml b/mdbook-tera-backend/Cargo.toml index b5dffed9..591373fb 100644 --- a/mdbook-tera-backend/Cargo.toml +++ b/mdbook-tera-backend/Cargo.toml @@ -12,7 +12,6 @@ description = "Plugin to extend mdbook with Tera templates and custom HTML compo [dependencies] anyhow = "1.0.75" chrono = { version = "0.4.31", default-features = false, features = ["alloc"] } -lol_html = "1.2.0" mdbook = { version = "0.4.25", default-features = false } serde = "1.0" serde_json = "1.0.91" diff --git a/mdbook-tera-backend/src/main.rs b/mdbook-tera-backend/src/main.rs index 64c7009e..60df9e71 100644 --- a/mdbook-tera-backend/src/main.rs +++ b/mdbook-tera-backend/src/main.rs @@ -15,15 +15,11 @@ fn main() { .expect("Failed to get tera-backend config") .unwrap(); - let (tera_template, components) = config + let tera_template = config .create_template_and_components(&ctx.root) .expect("Failed to create components"); let mut renderer = Renderer::new(ctx, tera_template).expect("Failed to create renderer"); - for component in components { - renderer.add_component(component); - } - renderer.render_book().expect("Failed to render book"); } diff --git a/mdbook-tera-backend/src/tera_renderer/custom_component.rs b/mdbook-tera-backend/src/tera_renderer/custom_component.rs index a2eeb816..d8ce9649 100644 --- a/mdbook-tera-backend/src/tera_renderer/custom_component.rs +++ b/mdbook-tera-backend/src/tera_renderer/custom_component.rs @@ -1,62 +1,13 @@ use anyhow::Result; use serde::Deserialize; -use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use tera::Tera; -pub struct CustomComponent { - template: Tera, - name: String, -} - -impl CustomComponent { - pub fn new(name: &str, template: Tera) -> Result { - Ok(CustomComponent { - name: String::from(name), - template, - }) - } - - pub fn register_function(&mut self, name: &str, function: impl tera::Function + 'static) { - self.template.register_function(name, function); - } - - pub fn render( - &self, - tera_context: &tera::Context, - attributes: BTreeMap, - ) -> Result { - let mut tera_context = tera_context.clone(); - tera_context.insert("attributes", &attributes); - let output = self.template.render(&self.name, &tera_context); - - if let Err(err) = &output { - println!("Error rendering component {}: {:?}", self.name, err); - } - - Ok(output?) - } - - pub fn component_name(&self) -> String { - self.name.clone() - } -} - -#[derive(Deserialize)] -#[serde(untagged)] -pub enum Component { - Named { name: String, path: PathBuf }, - Anonymous(PathBuf), -} - /// Configuration in `book.toml` `[output.tera-renderer]`. #[derive(Deserialize)] pub struct TeraRendererConfig { /// Relative path to the templates directory from the `book.toml` directory. pub templates_dir: PathBuf, - /// Custom HTML components to register. - #[serde(default)] - pub html_components: Vec, } impl TeraRendererConfig { @@ -73,46 +24,13 @@ impl TeraRendererConfig { Ok(()) } - fn create_custom_components( - &self, - tera_template: &Tera, - current_dir: &Path, - ) -> Result> { - self.html_components - .iter() - .map(|component| { - Ok(match component { - Component::Named { name, path } => { - let mut template = tera_template.clone(); - template.add_template_file(path, Some(name))?; - CustomComponent::new(name, template)? - } - Component::Anonymous(path) => { - let mut template = tera_template.clone(); - let name = path - .file_stem() - .unwrap_or_default() - .to_str() - .unwrap_or_default(); - template.add_template_file(current_dir.join(path), Some(name))?; - CustomComponent::new(name, template)? - } - }) - }) - .collect() - } - - pub fn create_template_and_components( - &self, - current_dir: &Path, - ) -> Result<(Tera, Vec)> { + pub fn create_template_and_components(&self, current_dir: &Path) -> Result { let mut tera_template = Tera::default(); Self::add_templates_recursively( &mut tera_template, ¤t_dir.join(&self.templates_dir), )?; - let components = self.create_custom_components(&tera_template, current_dir)?; - Ok((tera_template, components)) + Ok(tera_template) } } diff --git a/mdbook-tera-backend/src/tera_renderer/renderer.rs b/mdbook-tera-backend/src/tera_renderer/renderer.rs index d517b402..b2ce1247 100644 --- a/mdbook-tera-backend/src/tera_renderer/renderer.rs +++ b/mdbook-tera-backend/src/tera_renderer/renderer.rs @@ -1,7 +1,4 @@ -use super::custom_component::CustomComponent; use anyhow::{anyhow, Result}; -use lol_html::html_content::ContentType; -use lol_html::{element, RewriteStrSettings}; use mdbook::renderer::RenderContext; use serde_json::to_value; use std::collections::{BTreeMap, HashMap}; @@ -14,7 +11,6 @@ use tera::Tera; pub(crate) struct Renderer { ctx: Arc, serialized_ctx: serde_json::Value, - components: Vec, counter: u64, tera_template: Tera, } @@ -24,7 +20,6 @@ impl Renderer { let mut renderer = Renderer { serialized_ctx: serde_json::to_value(&ctx)?, ctx: Arc::new(ctx), - components: Vec::new(), counter: 0, tera_template, }; @@ -34,11 +29,6 @@ impl Renderer { Ok(renderer) } - pub(crate) fn add_component(&mut self, mut component: CustomComponent) { - component.register_function("get_context", self.create_get_context_function()); - self.components.push(component); - } - fn create_get_context_function(&self) -> impl tera::Function { let ctx_rc = Arc::clone(&self.ctx); move |args: &HashMap| -> tera::Result { @@ -84,7 +74,7 @@ impl Renderer { return Ok(()); } let file_content = std::fs::read_to_string(path)?; - let output = self.render_components(&file_content, path)?; + let output = self.render(&file_content, path)?; let mut output_file = fs::File::create(path)?; output_file.write_all(output.as_bytes())?; Ok(()) @@ -102,36 +92,13 @@ impl Renderer { context } - fn render_components(&mut self, file_content: &str, path: &Path) -> Result { + fn render(&mut self, file_content: &str, path: &Path) -> Result { let tera_context = self.create_context(path); let rendered_file = self .tera_template .render_str(file_content, &tera_context) .map_err(|e| anyhow!("Error rendering file {path:?}: {e:?}"))?; - let custom_components_handlers = self - .components - .iter() - .map(|component| { - element!(component.component_name(), |el| { - let attributes: BTreeMap = el - .attributes() - .iter() - .map(|attribute| (attribute.name(), attribute.value())) - .collect(); - let rendered = component.render(&tera_context, attributes)?; - el.replace(&rendered, ContentType::Html); - Ok(()) - }) - }) - .collect(); - let output = lol_html::rewrite_str( - &rendered_file, - RewriteStrSettings { - element_content_handlers: custom_components_handlers, - ..RewriteStrSettings::default() - }, - )?; - Ok(output) + Ok(rendered_file) } } From 0efb073b1c285a2ce50d807738b693fb62322558 Mon Sep 17 00:00:00 2001 From: sakex Date: Fri, 20 Oct 2023 13:49:09 +0200 Subject: [PATCH 07/17] Add comments --- mdbook-tera-backend/src/main.rs | 2 +- .../src/tera_renderer/custom_component.rs | 4 +- .../src/tera_renderer/renderer.rs | 66 ++++++++++++++++--- 3 files changed, 60 insertions(+), 12 deletions(-) diff --git a/mdbook-tera-backend/src/main.rs b/mdbook-tera-backend/src/main.rs index 60df9e71..ea87b430 100644 --- a/mdbook-tera-backend/src/main.rs +++ b/mdbook-tera-backend/src/main.rs @@ -16,7 +16,7 @@ fn main() { .unwrap(); let tera_template = config - .create_template_and_components(&ctx.root) + .create_template(&ctx.root) .expect("Failed to create components"); let mut renderer = Renderer::new(ctx, tera_template).expect("Failed to create renderer"); diff --git a/mdbook-tera-backend/src/tera_renderer/custom_component.rs b/mdbook-tera-backend/src/tera_renderer/custom_component.rs index d8ce9649..36d303c6 100644 --- a/mdbook-tera-backend/src/tera_renderer/custom_component.rs +++ b/mdbook-tera-backend/src/tera_renderer/custom_component.rs @@ -11,6 +11,7 @@ pub struct TeraRendererConfig { } impl TeraRendererConfig { + /// Recursively add all templates in the `templates_dir` to the `tera_template`. fn add_templates_recursively(tera_template: &mut Tera, directory: &Path) -> Result<()> { for entry in std::fs::read_dir(directory)? { let entry = entry?; @@ -24,7 +25,8 @@ impl TeraRendererConfig { Ok(()) } - pub fn create_template_and_components(&self, current_dir: &Path) -> Result { + /// Create the `tera_template` and add all templates in the `templates_dir` to it. + pub fn create_template(&self, current_dir: &Path) -> Result { let mut tera_template = Tera::default(); Self::add_templates_recursively( &mut tera_template, diff --git a/mdbook-tera-backend/src/tera_renderer/renderer.rs b/mdbook-tera-backend/src/tera_renderer/renderer.rs index b2ce1247..78d5c2cc 100644 --- a/mdbook-tera-backend/src/tera_renderer/renderer.rs +++ b/mdbook-tera-backend/src/tera_renderer/renderer.rs @@ -8,6 +8,27 @@ use std::path::Path; use std::sync::Arc; use tera::Tera; +/// Renderer for the tera backend. +/// +/// This will read all the files in the `RenderContext` and render them using the `Tera` template. +/// +/// # Example +/// +/// ``` +/// let mut stdin = io::stdin(); +/// let ctx = RenderContext::from_json(&mut stdin).unwrap(); +/// let config: TeraRendererConfig = ctx +/// .config +/// .get_deserialized_opt("output.tera-backend") +/// .expect("Failed to get tera-backend config") +/// .unwrap(); +/// +/// let tera_template = config +/// .create_template(&ctx.root) +/// .expect("Failed to create components"); +/// let mut renderer = Renderer::new(ctx, tera_template).expect("Failed to create renderer"); +/// renderer.render_book().expect("Failed to render book"); +/// ``` pub(crate) struct Renderer { ctx: Arc, serialized_ctx: serde_json::Value, @@ -16,6 +37,12 @@ pub(crate) struct Renderer { } impl Renderer { + /// Create a new `Renderer` from the `RenderContext` and `Tera` template. + /// + /// # Arguments + /// + /// `ctx`: The `RenderContext` to be used for rendering. This is usually obtained from `stdin`. + /// `tera_template`: A pre-configured `Tera` template. pub(crate) fn new(ctx: RenderContext, tera_template: Tera) -> Result { let mut renderer = Renderer { serialized_ctx: serde_json::to_value(&ctx)?, @@ -29,6 +56,16 @@ impl Renderer { Ok(renderer) } + /// Render the book. + pub(crate) fn render_book(&mut self) -> Result<()> { + let dest_dir = self.ctx.destination.parent().unwrap().to_owned(); + if !dest_dir.is_dir() { + return Err(anyhow!("{dest_dir:?} is not a directory")); + } + self.render_book_directory(&dest_dir) + } + + /// Create the `get_context` function for the `Tera` template, a helper that allows retrieving values from `ctx`. fn create_get_context_function(&self) -> impl tera::Function { let ctx_rc = Arc::clone(&self.ctx); move |args: &HashMap| -> tera::Result { @@ -48,14 +85,7 @@ impl Renderer { } } - pub(crate) fn render_book(&mut self) -> Result<()> { - let dest_dir = self.ctx.destination.parent().unwrap().to_owned(); - if !dest_dir.is_dir() { - return Err(anyhow!("{dest_dir:?} is not a directory")); - } - self.render_book_directory(&dest_dir) - } - + /// Render the book directory located at `path` recursively. fn render_book_directory(&mut self, path: &Path) -> Result<()> { for entry in path.read_dir()? { let entry = entry?; @@ -69,17 +99,23 @@ impl Renderer { Ok(()) } + /// Reads the file at `path` and renders it. fn process_file(&mut self, path: &Path) -> Result<()> { if path.extension().unwrap_or_default() != "html" { return Ok(()); } let file_content = std::fs::read_to_string(path)?; - let output = self.render(&file_content, path)?; + let output = self.render_file_content(&file_content, path)?; let mut output_file = fs::File::create(path)?; output_file.write_all(output.as_bytes())?; Ok(()) } + /// Creates the rendering context to be passed to the templates. + /// + /// # Arguments + /// + /// `path`: The path to the file that will be added as extra context to the renderer. fn create_context(&mut self, path: &Path) -> tera::Context { let mut context = tera::Context::new(); context.insert("path", path); @@ -92,7 +128,17 @@ impl Renderer { context } - fn render(&mut self, file_content: &str, path: &Path) -> Result { + /// Rendering logic for an individual file. + /// + /// # Arguments + /// + /// `file_content`: The content of the file to be rendered. + /// `path`: The path of the file to be rendered. + /// + /// # Returns + /// + /// The rendered file. + fn render_file_content(&mut self, file_content: &str, path: &Path) -> Result { let tera_context = self.create_context(path); let rendered_file = self From 4916c6a61d8a25149a250cc5ebe5b4c9e7d70a9b Mon Sep 17 00:00:00 2001 From: sakex Date: Wed, 1 Nov 2023 14:11:45 +0100 Subject: [PATCH 08/17] Remove counter + only render html --- mdbook-tera-backend/src/main.rs | 12 ++++- .../src/tera_renderer/renderer.rs | 44 +++++++------------ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/mdbook-tera-backend/src/main.rs b/mdbook-tera-backend/src/main.rs index ea87b430..36d5a365 100644 --- a/mdbook-tera-backend/src/main.rs +++ b/mdbook-tera-backend/src/main.rs @@ -1,14 +1,22 @@ mod tera_renderer; +use anyhow::anyhow; use mdbook::renderer::RenderContext; use std::io; use crate::tera_renderer::custom_component::TeraRendererConfig; use crate::tera_renderer::renderer::Renderer; -fn main() { +/// Re-renders HTML files outputed by the HTML backend with Tera templates. +/// Please make sure the HTML backend is enabled. +fn main() -> anyhow::Result<()> { let mut stdin = io::stdin(); let ctx = RenderContext::from_json(&mut stdin).unwrap(); + if ctx.config.get_preprocessor("html").is_none() { + return Err(anyhow!( + "Could not find the HTML backend. Please make sure the HTML backend is enabled." + )); + } let config: TeraRendererConfig = ctx .config .get_deserialized_opt("output.tera-backend") @@ -22,4 +30,6 @@ fn main() { let mut renderer = Renderer::new(ctx, tera_template).expect("Failed to create renderer"); renderer.render_book().expect("Failed to render book"); + + Ok(()) } diff --git a/mdbook-tera-backend/src/tera_renderer/renderer.rs b/mdbook-tera-backend/src/tera_renderer/renderer.rs index 78d5c2cc..8e6a1b50 100644 --- a/mdbook-tera-backend/src/tera_renderer/renderer.rs +++ b/mdbook-tera-backend/src/tera_renderer/renderer.rs @@ -31,23 +31,14 @@ use tera::Tera; /// ``` pub(crate) struct Renderer { ctx: Arc, - serialized_ctx: serde_json::Value, - counter: u64, tera_template: Tera, } impl Renderer { /// Create a new `Renderer` from the `RenderContext` and `Tera` template. - /// - /// # Arguments - /// - /// `ctx`: The `RenderContext` to be used for rendering. This is usually obtained from `stdin`. - /// `tera_template`: A pre-configured `Tera` template. pub(crate) fn new(ctx: RenderContext, tera_template: Tera) -> Result { let mut renderer = Renderer { - serialized_ctx: serde_json::to_value(&ctx)?, ctx: Arc::new(ctx), - counter: 0, tera_template, }; renderer @@ -56,11 +47,21 @@ impl Renderer { Ok(renderer) } - /// Render the book. + /// Render the book. This goes through the output of the HTML renderer + /// by considering all the output HTML files as input to the Tera template. + /// It overwrites the preexisting files with their Tera-rendered version. pub(crate) fn render_book(&mut self) -> Result<()> { - let dest_dir = self.ctx.destination.parent().unwrap().to_owned(); + let dest_dir = self + .ctx + .destination + .parent() + .unwrap() + .join("html") + .to_owned(); if !dest_dir.is_dir() { - return Err(anyhow!("{dest_dir:?} is not a directory")); + return Err(anyhow!( + "{dest_dir:?} is not a directory. Please make sure the HTML renderer is enabled." + )); } self.render_book_directory(&dest_dir) } @@ -116,30 +117,19 @@ impl Renderer { /// # Arguments /// /// `path`: The path to the file that will be added as extra context to the renderer. - fn create_context(&mut self, path: &Path) -> tera::Context { + fn create_context(&mut self, path: &Path) -> Result { let mut context = tera::Context::new(); context.insert("path", path); - context.insert("ctx", &self.serialized_ctx); + context.insert("ctx", &serde_json::to_value(&*self.ctx)?); context.insert("book_dir", &self.ctx.destination.parent().unwrap()); - context.insert("counter", &self.counter); context.insert("attributes", &BTreeMap::::new()); - self.counter += 1; - context + Ok(context) } /// Rendering logic for an individual file. - /// - /// # Arguments - /// - /// `file_content`: The content of the file to be rendered. - /// `path`: The path of the file to be rendered. - /// - /// # Returns - /// - /// The rendered file. fn render_file_content(&mut self, file_content: &str, path: &Path) -> Result { - let tera_context = self.create_context(path); + let tera_context = self.create_context(path)?; let rendered_file = self .tera_template From e89c2b5306529f6fd939e16d3d4ce15c2af64279 Mon Sep 17 00:00:00 2001 From: sakex Date: Wed, 1 Nov 2023 14:37:27 +0100 Subject: [PATCH 09/17] README --- README.md | 16 +++++-- mdbook-tera-backend/README.md | 84 +++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 mdbook-tera-backend/README.md diff --git a/README.md b/README.md index e2097f46..1b2f50cf 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,10 @@ This repository contains the following crates that provide extensions and infrastructure for [mdbook](https://github.com/rust-lang/mdBook/): -- [mdbook-i18n-helpers](i18n-helpers/README.md): Gettext translation support for - [mdbook](https://github.com/rust-lang/mdBook/) +- [mdbook-i18n-helpers](./i18n-helpers/README.md): Gettext translation support + for [mdbook](https://github.com/rust-lang/mdBook/) +- [mdbook-tera-backend](./mdbook-tera-backend/README.md): Tera templates extension + for [mdbook](https://github.com/rust-lang/mdBook/)'s HTML renderer. ## Showcases @@ -39,11 +41,17 @@ cargo install mdbook-i18n-helpers Please see [USAGE](i18n-helpers/USAGE.md) for how to translate your [mdbook](https://github.com/rust-lang/mdBook/) project. -## Changelog - Please see the [i18n-helpers/CHANGELOG](CHANGELOG) for details on the changes in each release. +### `mdbook-tera-backend` + +Run + +```shell +$ cargo install mdbook-tera-backend +``` + ## Contact For questions or comments, please contact diff --git a/mdbook-tera-backend/README.md b/mdbook-tera-backend/README.md new file mode 100644 index 00000000..cc5f0cd5 --- /dev/null +++ b/mdbook-tera-backend/README.md @@ -0,0 +1,84 @@ +# [Tera](https://github.com/Keats/tera) backend extension for `mdbook`'s HTML backend + +[![Visit crates.io](https://img.shields.io/crates/v/mdbook-i18n-helpers?style=flat-square)](https://crates.io/crates/mdbook-tera-backend) +[![Build workflow](https://img.shields.io/github/actions/workflow/status/google/mdbook-i18n-helpers/test.yml?style=flat-square)](https://github.com/google/mdbook-i18n-helpers/actions/workflows/test.yml?query=branch%3Amain) +[![GitHub contributors](https://img.shields.io/github/contributors/google/mdbook-i18n-helpers?style=flat-square)](https://github.com/google/mdbook-i18n-helpers/graphs/contributors) +[![GitHub stars](https://img.shields.io/github/stars/google/mdbook-i18n-helpers?style=flat-square)](https://github.com/google/mdbook-i18n-helpers/stargazers) + +This `mdbook` backend makes it possible to use [tera](https://github.com/Keats/tera) +templates and expand the capabilities of your books. It works on top of the default HTML +backend. + +## Installation + +Run + +```shell +$ cargo install mdbook-tera-backend +``` + +## Usage + +### Configuring the backend + +To enable the backend, simply add `[output.tera-backend]` to your `book.toml`, +and configure the place where youre templates will live. +For instance `theme/templates`: + +```toml +... + +[output.tera-backend] +templates_dir = "theme/templates" + +... +``` + +### Creating templates + +Create your template files in the same directory as your book. + +```html + +
    +{% for identifier, language_name in get_context(key="output.i18n.languages") %} +
  • {{ identifier }}: {{ language_name }}
  • +{% endfor %} +
+``` + +### Using templates in `index.hbs` + +Since the HTML renderer will first render Handlebars templates, we need to tell it to +ignore tera templates using `{{{{raw}}}}` blocks: + +```html +{{{{raw}}}} +{% set current_language = ctx | get(key="config") | get(key="book") | get(key="language", default="en") %} +

CURRENT LANGUAGE: {{ current_language }}

+

All languages: {% include "language_list.html" %}

+{{{{/raw}}}} +``` + +Includes names are based on the file name and not the whole file path. + +### Tera documentation + +Find out all you can do with Tera templates [here](https://keats.github.io/tera/docs/). + +## Changelog + +Please see [CHANGELOG](../CHANGELOG.md) for details on the changes in each +release. + +## Contact + +For questions or comments, please contact +[Martin Geisler](mailto:mgeisler@google.com) or +[Alexandre Senges](mailto:asenges@google.come) or start a +[discussion](https://github.com/google/mdbook-i18n-helpers/discussions). We +would love to hear from you. + +--- + +This is not an officially supported Google product. From 9de875c2f91e213120d8535a41bf6eb335b431a8 Mon Sep 17 00:00:00 2001 From: Alexandre Senges Date: Fri, 3 Nov 2023 18:42:09 +0100 Subject: [PATCH 10/17] Update mdbook-tera-backend/src/tera_renderer/renderer.rs Co-authored-by: Martin Geisler --- mdbook-tera-backend/src/tera_renderer/renderer.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mdbook-tera-backend/src/tera_renderer/renderer.rs b/mdbook-tera-backend/src/tera_renderer/renderer.rs index 8e6a1b50..aab723e5 100644 --- a/mdbook-tera-backend/src/tera_renderer/renderer.rs +++ b/mdbook-tera-backend/src/tera_renderer/renderer.rs @@ -107,9 +107,7 @@ impl Renderer { } let file_content = std::fs::read_to_string(path)?; let output = self.render_file_content(&file_content, path)?; - let mut output_file = fs::File::create(path)?; - output_file.write_all(output.as_bytes())?; - Ok(()) + fs::write(path, output) } /// Creates the rendering context to be passed to the templates. From 24a27d618e0985bb0e6986704d969c3b24eeb068 Mon Sep 17 00:00:00 2001 From: sakex Date: Fri, 3 Nov 2023 18:42:29 +0100 Subject: [PATCH 11/17] fixes --- mdbook-tera-backend/src/tera_renderer/renderer.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/mdbook-tera-backend/src/tera_renderer/renderer.rs b/mdbook-tera-backend/src/tera_renderer/renderer.rs index aab723e5..7a753651 100644 --- a/mdbook-tera-backend/src/tera_renderer/renderer.rs +++ b/mdbook-tera-backend/src/tera_renderer/renderer.rs @@ -120,7 +120,6 @@ impl Renderer { context.insert("path", path); context.insert("ctx", &serde_json::to_value(&*self.ctx)?); context.insert("book_dir", &self.ctx.destination.parent().unwrap()); - context.insert("attributes", &BTreeMap::::new()); Ok(context) } From 2c57c1cb3a713d09828f2ce5e077e09ff3a2b5c8 Mon Sep 17 00:00:00 2001 From: sakex Date: Fri, 3 Nov 2023 20:05:49 +0100 Subject: [PATCH 12/17] Add test --- Cargo.lock | 73 +++++++- mdbook-tera-backend/Cargo.toml | 3 +- mdbook-tera-backend/README.md | 23 ++- mdbook-tera-backend/src/main.rs | 14 +- mdbook-tera-backend/src/tera_renderer.rs | 2 + .../src/tera_renderer/custom_component.rs | 35 ++-- mdbook-tera-backend/src/tera_renderer/mod.rs | 2 - .../src/tera_renderer/renderer.rs | 160 +++++++++++------- 8 files changed, 201 insertions(+), 111 deletions(-) create mode 100644 mdbook-tera-backend/src/tera_renderer.rs delete mode 100644 mdbook-tera-backend/src/tera_renderer/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 40efa394..6f0be97b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -350,6 +350,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + [[package]] name = "generic-array" version = "0.14.7" @@ -606,11 +612,10 @@ name = "mdbook-tera-backend" version = "0.0.1" dependencies = [ "anyhow", - "chrono", "mdbook", "serde", "serde_json", - "tempfile", + "tempdir", "tera", ] @@ -772,7 +777,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ "phf_shared", - "rand", + "rand 0.8.5", ] [[package]] @@ -856,6 +861,19 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + [[package]] name = "rand" version = "0.8.5" @@ -864,7 +882,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -874,9 +892,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", ] +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + [[package]] name = "rand_core" version = "0.6.4" @@ -886,6 +919,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -924,6 +966,15 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + [[package]] name = "rustix" version = "0.38.13" @@ -1080,6 +1131,16 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "tempdir" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +dependencies = [ + "rand 0.4.6", + "remove_dir_all", +] + [[package]] name = "tempfile" version = "3.8.1" @@ -1107,7 +1168,7 @@ dependencies = [ "percent-encoding", "pest", "pest_derive", - "rand", + "rand 0.8.5", "regex", "serde", "serde_json", diff --git a/mdbook-tera-backend/Cargo.toml b/mdbook-tera-backend/Cargo.toml index 591373fb..a388a1c0 100644 --- a/mdbook-tera-backend/Cargo.toml +++ b/mdbook-tera-backend/Cargo.toml @@ -11,11 +11,10 @@ description = "Plugin to extend mdbook with Tera templates and custom HTML compo [dependencies] anyhow = "1.0.75" -chrono = { version = "0.4.31", default-features = false, features = ["alloc"] } mdbook = { version = "0.4.25", default-features = false } serde = "1.0" serde_json = "1.0.91" tera = "1.19.1" [dev-dependencies] -tempfile = "3.5.0" +tempdir = "0.3.7" diff --git a/mdbook-tera-backend/README.md b/mdbook-tera-backend/README.md index cc5f0cd5..b0e0ea2a 100644 --- a/mdbook-tera-backend/README.md +++ b/mdbook-tera-backend/README.md @@ -1,4 +1,4 @@ -# [Tera](https://github.com/Keats/tera) backend extension for `mdbook`'s HTML backend +# Tera backend extension for `mdbook` [![Visit crates.io](https://img.shields.io/crates/v/mdbook-i18n-helpers?style=flat-square)](https://crates.io/crates/mdbook-tera-backend) [![Build workflow](https://img.shields.io/github/actions/workflow/status/google/mdbook-i18n-helpers/test.yml?style=flat-square)](https://github.com/google/mdbook-i18n-helpers/actions/workflows/test.yml?query=branch%3Amain) @@ -26,12 +26,9 @@ and configure the place where youre templates will live. For instance `theme/templates`: ```toml -... - +[output.html] # You must still enable the html backend. [output.tera-backend] -templates_dir = "theme/templates" - -... +template_dir = "theme/templates" ``` ### Creating templates @@ -41,20 +38,20 @@ Create your template files in the same directory as your book. ```html
    -{% for identifier, language_name in get_context(key="output.i18n.languages") %} -
  • {{ identifier }}: {{ language_name }}
  • -{% endfor %} + {% for identifier, language_name in get_context(key="output.i18n.languages") + %} +
  • {{ identifier }}: {{ language_name }}
  • + {% endfor %}
``` ### Using templates in `index.hbs` Since the HTML renderer will first render Handlebars templates, we need to tell it to -ignore tera templates using `{{{{raw}}}}` blocks: +ignore Tera templates using `{{{{raw}}}}` blocks: ```html -{{{{raw}}}} -{% set current_language = ctx | get(key="config") | get(key="book") | get(key="language", default="en") %} +{{{{raw}}}} {% set current_language = ctx.config.book.language %}

CURRENT LANGUAGE: {{ current_language }}

All languages: {% include "language_list.html" %}

{{{{/raw}}}} @@ -74,7 +71,7 @@ release. ## Contact For questions or comments, please contact -[Martin Geisler](mailto:mgeisler@google.com) or +[Martin Geisler](mailto:mgeisler@google.com) or [Alexandre Senges](mailto:asenges@google.come) or start a [discussion](https://github.com/google/mdbook-i18n-helpers/discussions). We would love to hear from you. diff --git a/mdbook-tera-backend/src/main.rs b/mdbook-tera-backend/src/main.rs index 36d5a365..6ef65522 100644 --- a/mdbook-tera-backend/src/main.rs +++ b/mdbook-tera-backend/src/main.rs @@ -1,6 +1,6 @@ mod tera_renderer; -use anyhow::anyhow; +use anyhow::{anyhow, Context}; use mdbook::renderer::RenderContext; use std::io; @@ -12,7 +12,7 @@ use crate::tera_renderer::renderer::Renderer; fn main() -> anyhow::Result<()> { let mut stdin = io::stdin(); let ctx = RenderContext::from_json(&mut stdin).unwrap(); - if ctx.config.get_preprocessor("html").is_none() { + if ctx.config.get_renderer("html").is_none() { return Err(anyhow!( "Could not find the HTML backend. Please make sure the HTML backend is enabled." )); @@ -20,16 +20,16 @@ fn main() -> anyhow::Result<()> { let config: TeraRendererConfig = ctx .config .get_deserialized_opt("output.tera-backend") - .expect("Failed to get tera-backend config") - .unwrap(); + .context("Failed to get tera-backend config")? + .context("No tera-backend config found")?; let tera_template = config .create_template(&ctx.root) - .expect("Failed to create components"); + .context("Failed to create components")?; - let mut renderer = Renderer::new(ctx, tera_template).expect("Failed to create renderer"); + let mut renderer = Renderer::new(ctx, tera_template); - renderer.render_book().expect("Failed to render book"); + renderer.render_book().context("Failed to render book")?; Ok(()) } diff --git a/mdbook-tera-backend/src/tera_renderer.rs b/mdbook-tera-backend/src/tera_renderer.rs new file mode 100644 index 00000000..9f720662 --- /dev/null +++ b/mdbook-tera-backend/src/tera_renderer.rs @@ -0,0 +1,2 @@ +pub mod custom_component; +pub mod renderer; diff --git a/mdbook-tera-backend/src/tera_renderer/custom_component.rs b/mdbook-tera-backend/src/tera_renderer/custom_component.rs index 36d303c6..46c87e9a 100644 --- a/mdbook-tera-backend/src/tera_renderer/custom_component.rs +++ b/mdbook-tera-backend/src/tera_renderer/custom_component.rs @@ -7,31 +7,30 @@ use tera::Tera; #[derive(Deserialize)] pub struct TeraRendererConfig { /// Relative path to the templates directory from the `book.toml` directory. - pub templates_dir: PathBuf, + pub template_dir: Option, } -impl TeraRendererConfig { - /// Recursively add all templates in the `templates_dir` to the `tera_template`. - fn add_templates_recursively(tera_template: &mut Tera, directory: &Path) -> Result<()> { - for entry in std::fs::read_dir(directory)? { - let entry = entry?; - let path = entry.path(); - if path.is_dir() { - Self::add_templates_recursively(tera_template, &path)?; - } else { - tera_template.add_template_file(&path, path.file_name().unwrap().to_str())?; - } +/// Recursively add all templates in the `template_dir` to the `tera_template`. +fn add_templates_recursively(tera_template: &mut Tera, directory: &Path) -> Result<()> { + for entry in std::fs::read_dir(directory)? { + let entry = entry?; + let path = entry.path(); + if path.is_dir() { + add_templates_recursively(tera_template, &path)?; + } else { + tera_template.add_template_file(&path, path.file_name().unwrap().to_str())?; } - Ok(()) } + Ok(()) +} - /// Create the `tera_template` and add all templates in the `templates_dir` to it. +impl TeraRendererConfig { + /// Create the `tera_template` and add all templates in the `template_dir` to it. pub fn create_template(&self, current_dir: &Path) -> Result { let mut tera_template = Tera::default(); - Self::add_templates_recursively( - &mut tera_template, - ¤t_dir.join(&self.templates_dir), - )?; + if let Some(template_dir) = &self.template_dir { + add_templates_recursively(&mut tera_template, ¤t_dir.join(template_dir))?; + } Ok(tera_template) } diff --git a/mdbook-tera-backend/src/tera_renderer/mod.rs b/mdbook-tera-backend/src/tera_renderer/mod.rs deleted file mode 100644 index d366ed6f..00000000 --- a/mdbook-tera-backend/src/tera_renderer/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub(crate) mod custom_component; -pub(crate) mod renderer; diff --git a/mdbook-tera-backend/src/tera_renderer/renderer.rs b/mdbook-tera-backend/src/tera_renderer/renderer.rs index 7a753651..e55f320a 100644 --- a/mdbook-tera-backend/src/tera_renderer/renderer.rs +++ b/mdbook-tera-backend/src/tera_renderer/renderer.rs @@ -1,63 +1,28 @@ use anyhow::{anyhow, Result}; use mdbook::renderer::RenderContext; -use serde_json::to_value; -use std::collections::{BTreeMap, HashMap}; -use std::fs; -use std::io::Write; use std::path::Path; -use std::sync::Arc; use tera::Tera; /// Renderer for the tera backend. /// /// This will read all the files in the `RenderContext` and render them using the `Tera` template. -/// -/// # Example -/// -/// ``` -/// let mut stdin = io::stdin(); -/// let ctx = RenderContext::from_json(&mut stdin).unwrap(); -/// let config: TeraRendererConfig = ctx -/// .config -/// .get_deserialized_opt("output.tera-backend") -/// .expect("Failed to get tera-backend config") -/// .unwrap(); -/// -/// let tera_template = config -/// .create_template(&ctx.root) -/// .expect("Failed to create components"); -/// let mut renderer = Renderer::new(ctx, tera_template).expect("Failed to create renderer"); -/// renderer.render_book().expect("Failed to render book"); /// ``` -pub(crate) struct Renderer { - ctx: Arc, +pub struct Renderer { + ctx: RenderContext, tera_template: Tera, } impl Renderer { /// Create a new `Renderer` from the `RenderContext` and `Tera` template. - pub(crate) fn new(ctx: RenderContext, tera_template: Tera) -> Result { - let mut renderer = Renderer { - ctx: Arc::new(ctx), - tera_template, - }; - renderer - .tera_template - .register_function("get_context", renderer.create_get_context_function()); - Ok(renderer) + pub fn new(ctx: RenderContext, tera_template: Tera) -> Self { + Renderer { ctx, tera_template } } /// Render the book. This goes through the output of the HTML renderer /// by considering all the output HTML files as input to the Tera template. /// It overwrites the preexisting files with their Tera-rendered version. - pub(crate) fn render_book(&mut self) -> Result<()> { - let dest_dir = self - .ctx - .destination - .parent() - .unwrap() - .join("html") - .to_owned(); + pub fn render_book(&mut self) -> Result<()> { + let dest_dir = self.ctx.destination.parent().unwrap().join("html"); if !dest_dir.is_dir() { return Err(anyhow!( "{dest_dir:?} is not a directory. Please make sure the HTML renderer is enabled." @@ -66,26 +31,6 @@ impl Renderer { self.render_book_directory(&dest_dir) } - /// Create the `get_context` function for the `Tera` template, a helper that allows retrieving values from `ctx`. - fn create_get_context_function(&self) -> impl tera::Function { - let ctx_rc = Arc::clone(&self.ctx); - move |args: &HashMap| -> tera::Result { - let key = args - .get("key") - .ok_or_else(|| tera::Error::from(format!("No key argument provided")))? - .as_str() - .ok_or_else(|| { - tera::Error::from(format!("Key has invalid type, expected string")) - })?; - let value = ctx_rc - .config - .get(key) - .ok_or_else(|| tera::Error::from(format!("Could not find key {key} in config")))?; - let value = to_value(value)?; - Ok(value) - } - } - /// Render the book directory located at `path` recursively. fn render_book_directory(&mut self, path: &Path) -> Result<()> { for entry in path.read_dir()? { @@ -107,7 +52,7 @@ impl Renderer { } let file_content = std::fs::read_to_string(path)?; let output = self.render_file_content(&file_content, path)?; - fs::write(path, output) + Ok(std::fs::write(path, output)?) } /// Creates the rendering context to be passed to the templates. @@ -118,7 +63,7 @@ impl Renderer { fn create_context(&mut self, path: &Path) -> Result { let mut context = tera::Context::new(); context.insert("path", path); - context.insert("ctx", &serde_json::to_value(&*self.ctx)?); + context.insert("ctx", &serde_json::to_value(&self.ctx)?); context.insert("book_dir", &self.ctx.destination.parent().unwrap()); Ok(context) @@ -135,3 +80,92 @@ impl Renderer { Ok(rendered_file) } } + +#[cfg(test)] +mod test { + use tempdir::TempDir; + + use super::*; + use crate::tera_renderer::custom_component::TeraRendererConfig; + use anyhow::Result; + + const RENDER_CONTEXT_STR: &str = r#" + { + "version":"0.4.32", + "root":"", + "book":{ + "sections": [], + "__non_exhaustive": null + }, + "destination": "", + "config":{ + "book":{ + "authors":[ + "Martin Geisler" + ], + "language":"en", + "multilingual":false, + "src":"src", + "title":"Comprehensive Rust 🦀" + }, + "build":{ + "build-dir":"book", + "use-default-preprocessors":true + }, + "output":{ + "tera-backend": { + "template_dir": "templates" + }, + "renderers":[ + "html", + "tera-backend" + ] + } + } + }"#; + + const HTML_FILE: &str = r#" + + {%include "test_template.html" %} + + "#; + + const TEMPLATE_FILE: &str = "RENDERED"; + + const RENDERED_HTML_FILE: &str = r#" + + RENDERED + + "#; + + #[test] + fn test_renderer() -> Result<()> { + let mut ctx = RenderContext::from_json(RENDER_CONTEXT_STR.as_bytes()).unwrap(); + + let tmp_dir = TempDir::new("output")?; + let html_path = tmp_dir.path().join("html"); + let templates_path = tmp_dir.path().join("templates"); + + std::fs::create_dir(&html_path)?; + std::fs::create_dir(&templates_path)?; + + let html_file_path = html_path.join("test.html"); + std::fs::write(&html_file_path, HTML_FILE)?; + std::fs::write(templates_path.join("test_template.html"), TEMPLATE_FILE)?; + + ctx.destination = tmp_dir.path().join("tera-renderer"); + ctx.root = tmp_dir.path().to_owned(); + + let config: TeraRendererConfig = ctx + .config + .get_deserialized_opt("output.tera-backend")? + .ok_or_else(|| anyhow!("No tera backend configuration."))?; + + let tera_template = config.create_template(&ctx.root)?; + let mut renderer = Renderer::new(ctx, tera_template); + renderer.render_book().expect("Failed to render book"); + + assert_eq!(std::fs::read_to_string(html_file_path)?, RENDERED_HTML_FILE); + Ok(()) + } +} From 84181d18ccd83f036221ee9b7e6d120d2c91deb3 Mon Sep 17 00:00:00 2001 From: Alexandre Senges Date: Tue, 7 Nov 2023 09:25:34 +0100 Subject: [PATCH 13/17] Fix README.md formatting --- mdbook-tera-backend/README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/mdbook-tera-backend/README.md b/mdbook-tera-backend/README.md index b0e0ea2a..7980b7ad 100644 --- a/mdbook-tera-backend/README.md +++ b/mdbook-tera-backend/README.md @@ -22,8 +22,8 @@ $ cargo install mdbook-tera-backend ### Configuring the backend To enable the backend, simply add `[output.tera-backend]` to your `book.toml`, -and configure the place where youre templates will live. -For instance `theme/templates`: +and configure the place where youre templates will live. For instance +`theme/templates`: ```toml [output.html] # You must still enable the html backend. @@ -47,8 +47,8 @@ Create your template files in the same directory as your book. ### Using templates in `index.hbs` -Since the HTML renderer will first render Handlebars templates, we need to tell it to -ignore Tera templates using `{{{{raw}}}}` blocks: +Since the HTML renderer will first render Handlebars templates, we need to tell +it to ignore Tera templates using `{{{{raw}}}}` blocks: ```html {{{{raw}}}} {% set current_language = ctx.config.book.language %} @@ -61,7 +61,8 @@ Includes names are based on the file name and not the whole file path. ### Tera documentation -Find out all you can do with Tera templates [here](https://keats.github.io/tera/docs/). +Find out all you can do with Tera templates +[here](https://keats.github.io/tera/docs/). ## Changelog From 5d865029b2ce4c83b07f4b2da24746980a01d8d9 Mon Sep 17 00:00:00 2001 From: Alexandre Senges Date: Tue, 7 Nov 2023 08:46:53 +0000 Subject: [PATCH 14/17] Make path relative --- README.md | 4 ++-- mdbook-tera-backend/README.md | 6 +++--- mdbook-tera-backend/src/tera_renderer/renderer.rs | 9 ++++++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 1b2f50cf..8e763bea 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ infrastructure for [mdbook](https://github.com/rust-lang/mdBook/): - [mdbook-i18n-helpers](./i18n-helpers/README.md): Gettext translation support for [mdbook](https://github.com/rust-lang/mdBook/) -- [mdbook-tera-backend](./mdbook-tera-backend/README.md): Tera templates extension - for [mdbook](https://github.com/rust-lang/mdBook/)'s HTML renderer. +- [mdbook-tera-backend](./mdbook-tera-backend/README.md): Tera templates + extension for [mdbook](https://github.com/rust-lang/mdBook/)'s HTML renderer. ## Showcases diff --git a/mdbook-tera-backend/README.md b/mdbook-tera-backend/README.md index 7980b7ad..73d90c33 100644 --- a/mdbook-tera-backend/README.md +++ b/mdbook-tera-backend/README.md @@ -5,9 +5,9 @@ [![GitHub contributors](https://img.shields.io/github/contributors/google/mdbook-i18n-helpers?style=flat-square)](https://github.com/google/mdbook-i18n-helpers/graphs/contributors) [![GitHub stars](https://img.shields.io/github/stars/google/mdbook-i18n-helpers?style=flat-square)](https://github.com/google/mdbook-i18n-helpers/stargazers) -This `mdbook` backend makes it possible to use [tera](https://github.com/Keats/tera) -templates and expand the capabilities of your books. It works on top of the default HTML -backend. +This `mdbook` backend makes it possible to use +[tera](https://github.com/Keats/tera) templates and expand the capabilities of +your books. It works on top of the default HTML backend. ## Installation diff --git a/mdbook-tera-backend/src/tera_renderer/renderer.rs b/mdbook-tera-backend/src/tera_renderer/renderer.rs index e55f320a..bfe45833 100644 --- a/mdbook-tera-backend/src/tera_renderer/renderer.rs +++ b/mdbook-tera-backend/src/tera_renderer/renderer.rs @@ -62,8 +62,9 @@ impl Renderer { /// `path`: The path to the file that will be added as extra context to the renderer. fn create_context(&mut self, path: &Path) -> Result { let mut context = tera::Context::new(); - context.insert("path", path); - context.insert("ctx", &serde_json::to_value(&self.ctx)?); + let book_dir = self.ctx.destination.parent().unwrap(); + let relative_path = path.strip_prefix(book_dir).unwrap(); + context.insert("path", &relative_path); context.insert("book_dir", &self.ctx.destination.parent().unwrap()); Ok(context) @@ -126,7 +127,8 @@ mod test { const HTML_FILE: &str = r#" - {%include "test_template.html" %} + {% include "test_template.html" %} + PATH: {{ path }} "#; @@ -135,6 +137,7 @@ mod test { const RENDERED_HTML_FILE: &str = r#" RENDERED + PATH: html/test.html "#; From ddbacea24e5d6c0660a704d3aa710eaac55779c9 Mon Sep 17 00:00:00 2001 From: Alexandre Senges Date: Wed, 8 Nov 2023 19:49:52 +0100 Subject: [PATCH 15/17] Update mdbook-tera-backend/README.md Co-authored-by: Martin Geisler --- mdbook-tera-backend/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mdbook-tera-backend/README.md b/mdbook-tera-backend/README.md index 73d90c33..75ca7dc3 100644 --- a/mdbook-tera-backend/README.md +++ b/mdbook-tera-backend/README.md @@ -51,8 +51,9 @@ Since the HTML renderer will first render Handlebars templates, we need to tell it to ignore Tera templates using `{{{{raw}}}}` blocks: ```html -{{{{raw}}}} {% set current_language = ctx.config.book.language %} -

CURRENT LANGUAGE: {{ current_language }}

+{{{{raw}}}} +{% set current_language = ctx.config.book.language %} +

Current language: {{ current_language }}

All languages: {% include "language_list.html" %}

{{{{/raw}}}} ``` From 57f73e481594ee299d2d5c19a69e6fe73bc92a10 Mon Sep 17 00:00:00 2001 From: Alexandre Senges Date: Thu, 9 Nov 2023 16:00:45 +0100 Subject: [PATCH 16/17] Fix README.md --- mdbook-tera-backend/README.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/mdbook-tera-backend/README.md b/mdbook-tera-backend/README.md index 75ca7dc3..41535f89 100644 --- a/mdbook-tera-backend/README.md +++ b/mdbook-tera-backend/README.md @@ -36,13 +36,10 @@ template_dir = "theme/templates" Create your template files in the same directory as your book. ```html - -
    - {% for identifier, language_name in get_context(key="output.i18n.languages") - %} -
  • {{ identifier }}: {{ language_name }}
  • - {% endfor %} -
+ +
+ Hello world! +
``` ### Using templates in `index.hbs` @@ -54,7 +51,7 @@ it to ignore Tera templates using `{{{{raw}}}}` blocks: {{{{raw}}}} {% set current_language = ctx.config.book.language %}

Current language: {{ current_language }}

-

All languages: {% include "language_list.html" %}

+{% include "hello_world.html" %} {{{{/raw}}}} ``` From 23472a5ecdfbc70fd8286810cbb4b72742876bb4 Mon Sep 17 00:00:00 2001 From: Alexandre Senges Date: Thu, 9 Nov 2023 15:43:19 +0000 Subject: [PATCH 17/17] Fix lock --- Cargo.lock | 112 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f0be97b..c135d12d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,8 +3,8 @@ version = 3 [[package]] -name = "aho-corasick" -version = "1.1.0" +name = "adler" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" @@ -271,6 +271,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "deranged" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +dependencies = [ + "powerfmt", +] + [[package]] name = "deunicode" version = "0.4.4" @@ -344,12 +353,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -416,8 +419,8 @@ dependencies = [ ] [[package]] -name = "hermit-abi" -version = "0.3.2" +name = "hashbrown" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" @@ -482,6 +485,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "is-terminal" version = "0.4.9" @@ -520,6 +533,12 @@ version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +[[package]] +name = "libm" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" + [[package]] name = "line-wrap" version = "0.1.1" @@ -529,12 +548,6 @@ dependencies = [ "safemem", ] -[[package]] -name = "libm" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" - [[package]] name = "linereader" version = "0.4.0" @@ -789,6 +802,26 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "plist" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef" +dependencies = [ + "base64", + "indexmap", + "line-wrap", + "quick-xml", + "serde", + "time", +] + [[package]] name = "polib" version = "0.2.0" @@ -798,6 +831,12 @@ dependencies = [ "linereader", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -966,6 +1005,12 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "remove_dir_all" version = "0.5.3" @@ -975,12 +1020,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "rustix" -version = "0.38.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - [[package]] name = "rustix" version = "0.38.21" @@ -1001,17 +1040,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "semver" -version = "1.0.18" +name = "safemem" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" @@ -1101,7 +1131,7 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "2.0.37" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ @@ -1196,8 +1226,8 @@ dependencies = [ ] [[package]] -name = "thiserror" -version = "1.0.48" +name = "textwrap" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" @@ -1380,16 +1410,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasm-bindgen" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" -dependencies = [ - "same-file", - "winapi-util", -] - [[package]] name = "wasm-bindgen" version = "0.2.88"