├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── example-book ├── .gitignore ├── book.toml └── src │ ├── SUMMARY.md │ ├── chapter_1.md │ ├── context.toml │ └── macros.tera └── src ├── context.rs ├── lib.rs └── main.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [avitex] 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "19:30" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: [push, pull_request] 3 | jobs: 4 | test: 5 | strategy: 6 | matrix: 7 | os: [ubuntu-latest, windows-latest, macos-latest] 8 | rust-toolchain: [stable] 9 | fail-fast: false 10 | runs-on: ${{ matrix.os }} 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v2 14 | - name: Install Rust toolchain 15 | uses: actions-rs/toolchain@v1 16 | with: 17 | toolchain: ${{ matrix.rust-toolchain }} 18 | components: clippy, rustfmt 19 | override: true 20 | - name: Verify versions 21 | run: rustc --version && rustup --version && cargo --version 22 | - name: Cache build artifacts 23 | id: cache-cargo 24 | uses: actions/cache@v2 25 | with: 26 | path: | 27 | ~/.cargo/registry 28 | ~/.cargo/git 29 | target 30 | key: ${{ runner.os }}-cargo-${{ matrix.rust-toolchain }} 31 | - name: Test code with default features 32 | run: cargo test 33 | - name: Test code with all features 34 | run: cargo test --all-features 35 | - name: Test code with no default features 36 | run: cargo test --no-default-features 37 | - name: Lint code 38 | if: ${{ matrix.rust-toolchain == 'stable' }} 39 | run: cargo fmt -- --check && cargo clippy --all-features 40 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | release: 3 | types: [created] 4 | 5 | jobs: 6 | release: 7 | strategy: 8 | matrix: 9 | os: [ubuntu-latest, windows-latest, macos-latest] 10 | rust-toolchain: [stable] 11 | fail-fast: false 12 | runs-on: ${{ matrix.os }} 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v2 16 | - name: Install Rust toolchain 17 | uses: actions-rs/toolchain@v1 18 | with: 19 | toolchain: ${{ matrix.rust-toolchain }} 20 | components: clippy, rustfmt 21 | override: true 22 | - name: Verify versions 23 | run: rustc --version && rustup --version && cargo --version 24 | - name: Cache build artifacts 25 | id: cache-cargo 26 | uses: actions/cache@v2 27 | with: 28 | path: | 29 | ~/.cargo/registry 30 | ~/.cargo/git 31 | target 32 | key: ${{ runner.os }}-cargo-${{ matrix.rust-toolchain }} 33 | - name: Compile and release 34 | uses: avitex/rust-release.action@v0.1.0 35 | with: 36 | token: ${{ secrets.GITHUB_TOKEN }} 37 | binary: mdbook-tera 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "0.7.18" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "anyhow" 16 | version = "1.0.58" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" 19 | 20 | [[package]] 21 | name = "atty" 22 | version = "0.2.14" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 25 | dependencies = [ 26 | "hermit-abi", 27 | "libc", 28 | "winapi", 29 | ] 30 | 31 | [[package]] 32 | name = "autocfg" 33 | version = "1.1.0" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 36 | 37 | [[package]] 38 | name = "bitflags" 39 | version = "1.3.2" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 42 | 43 | [[package]] 44 | name = "block-buffer" 45 | version = "0.7.3" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" 48 | dependencies = [ 49 | "block-padding", 50 | "byte-tools", 51 | "byteorder", 52 | "generic-array", 53 | ] 54 | 55 | [[package]] 56 | name = "block-padding" 57 | version = "0.1.5" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" 60 | dependencies = [ 61 | "byte-tools", 62 | ] 63 | 64 | [[package]] 65 | name = "bstr" 66 | version = "0.2.17" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" 69 | dependencies = [ 70 | "lazy_static", 71 | "memchr", 72 | "regex-automata", 73 | ] 74 | 75 | [[package]] 76 | name = "byte-tools" 77 | version = "0.3.1" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" 80 | 81 | [[package]] 82 | name = "byteorder" 83 | version = "1.4.3" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 86 | 87 | [[package]] 88 | name = "cfg-if" 89 | version = "1.0.0" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 92 | 93 | [[package]] 94 | name = "chrono" 95 | version = "0.4.19" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 98 | dependencies = [ 99 | "libc", 100 | "num-integer", 101 | "num-traits", 102 | "time", 103 | "winapi", 104 | ] 105 | 106 | [[package]] 107 | name = "chrono-tz" 108 | version = "0.6.1" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "58549f1842da3080ce63002102d5bc954c7bc843d4f47818e642abdc36253552" 111 | dependencies = [ 112 | "chrono", 113 | "chrono-tz-build", 114 | "phf", 115 | ] 116 | 117 | [[package]] 118 | name = "chrono-tz-build" 119 | version = "0.0.2" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "db058d493fb2f65f41861bfed7e3fe6335264a9f0f92710cab5bdf01fef09069" 122 | dependencies = [ 123 | "parse-zoneinfo", 124 | "phf", 125 | "phf_codegen", 126 | ] 127 | 128 | [[package]] 129 | name = "clap" 130 | version = "3.2.8" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83" 133 | dependencies = [ 134 | "atty", 135 | "bitflags", 136 | "clap_lex", 137 | "indexmap", 138 | "once_cell", 139 | "strsim", 140 | "termcolor", 141 | "textwrap", 142 | ] 143 | 144 | [[package]] 145 | name = "clap_complete" 146 | version = "3.2.3" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "ead064480dfc4880a10764488415a97fdd36a4cf1bb022d372f02e8faf8386e1" 149 | dependencies = [ 150 | "clap", 151 | ] 152 | 153 | [[package]] 154 | name = "clap_lex" 155 | version = "0.2.4" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" 158 | dependencies = [ 159 | "os_str_bytes", 160 | ] 161 | 162 | [[package]] 163 | name = "crossbeam-utils" 164 | version = "0.8.10" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" 167 | dependencies = [ 168 | "cfg-if", 169 | "once_cell", 170 | ] 171 | 172 | [[package]] 173 | name = "deunicode" 174 | version = "0.4.3" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690" 177 | 178 | [[package]] 179 | name = "digest" 180 | version = "0.8.1" 181 | source = "registry+https://github.com/rust-lang/crates.io-index" 182 | checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" 183 | dependencies = [ 184 | "generic-array", 185 | ] 186 | 187 | [[package]] 188 | name = "env_logger" 189 | version = "0.9.0" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" 192 | dependencies = [ 193 | "atty", 194 | "humantime", 195 | "log", 196 | "regex", 197 | "termcolor", 198 | ] 199 | 200 | [[package]] 201 | name = "fake-simd" 202 | version = "0.1.2" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" 205 | 206 | [[package]] 207 | name = "fastrand" 208 | version = "1.7.0" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" 211 | dependencies = [ 212 | "instant", 213 | ] 214 | 215 | [[package]] 216 | name = "fnv" 217 | version = "1.0.7" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 220 | 221 | [[package]] 222 | name = "generic-array" 223 | version = "0.12.4" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" 226 | dependencies = [ 227 | "typenum", 228 | ] 229 | 230 | [[package]] 231 | name = "getrandom" 232 | version = "0.2.7" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" 235 | dependencies = [ 236 | "cfg-if", 237 | "libc", 238 | "wasi 0.11.0+wasi-snapshot-preview1", 239 | ] 240 | 241 | [[package]] 242 | name = "globset" 243 | version = "0.4.9" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" 246 | dependencies = [ 247 | "aho-corasick", 248 | "bstr", 249 | "fnv", 250 | "log", 251 | "regex", 252 | ] 253 | 254 | [[package]] 255 | name = "globwalk" 256 | version = "0.8.1" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" 259 | dependencies = [ 260 | "bitflags", 261 | "ignore", 262 | "walkdir", 263 | ] 264 | 265 | [[package]] 266 | name = "handlebars" 267 | version = "4.3.1" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "b66d0c1b6e3abfd1e72818798925e16e02ed77e1b47f6c25a95a23b377ee4299" 270 | dependencies = [ 271 | "log", 272 | "pest", 273 | "pest_derive", 274 | "serde", 275 | "serde_json", 276 | "thiserror", 277 | ] 278 | 279 | [[package]] 280 | name = "hashbrown" 281 | version = "0.12.2" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "607c8a29735385251a339424dd462993c0fed8fa09d378f259377df08c126022" 284 | 285 | [[package]] 286 | name = "hermit-abi" 287 | version = "0.1.19" 288 | source = "registry+https://github.com/rust-lang/crates.io-index" 289 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 290 | dependencies = [ 291 | "libc", 292 | ] 293 | 294 | [[package]] 295 | name = "humansize" 296 | version = "1.1.1" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" 299 | 300 | [[package]] 301 | name = "humantime" 302 | version = "2.1.0" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 305 | 306 | [[package]] 307 | name = "ignore" 308 | version = "0.4.18" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" 311 | dependencies = [ 312 | "crossbeam-utils", 313 | "globset", 314 | "lazy_static", 315 | "log", 316 | "memchr", 317 | "regex", 318 | "same-file", 319 | "thread_local", 320 | "walkdir", 321 | "winapi-util", 322 | ] 323 | 324 | [[package]] 325 | name = "indexmap" 326 | version = "1.9.1" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" 329 | dependencies = [ 330 | "autocfg", 331 | "hashbrown", 332 | ] 333 | 334 | [[package]] 335 | name = "instant" 336 | version = "0.1.12" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 339 | dependencies = [ 340 | "cfg-if", 341 | ] 342 | 343 | [[package]] 344 | name = "itoa" 345 | version = "1.0.2" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" 348 | 349 | [[package]] 350 | name = "lazy_static" 351 | version = "1.4.0" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 354 | 355 | [[package]] 356 | name = "libc" 357 | version = "0.2.126" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" 360 | 361 | [[package]] 362 | name = "log" 363 | version = "0.4.17" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 366 | dependencies = [ 367 | "cfg-if", 368 | ] 369 | 370 | [[package]] 371 | name = "maplit" 372 | version = "1.0.2" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" 375 | 376 | [[package]] 377 | name = "mdbook" 378 | version = "0.4.19" 379 | source = "registry+https://github.com/rust-lang/crates.io-index" 380 | checksum = "fe2468f3c25ca56d4e9e309b94a1a61626aa2a66a68d0649477f6a9fb14de972" 381 | dependencies = [ 382 | "anyhow", 383 | "chrono", 384 | "clap", 385 | "clap_complete", 386 | "env_logger", 387 | "handlebars", 388 | "lazy_static", 389 | "log", 390 | "memchr", 391 | "opener", 392 | "pulldown-cmark", 393 | "regex", 394 | "serde", 395 | "serde_json", 396 | "shlex", 397 | "tempfile", 398 | "toml", 399 | "topological-sort", 400 | ] 401 | 402 | [[package]] 403 | name = "mdbook-tera" 404 | version = "0.5.1" 405 | dependencies = [ 406 | "anyhow", 407 | "clap", 408 | "globwalk", 409 | "mdbook", 410 | "semver", 411 | "serde", 412 | "serde_json", 413 | "tera", 414 | "toml", 415 | ] 416 | 417 | [[package]] 418 | name = "memchr" 419 | version = "2.5.0" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 422 | 423 | [[package]] 424 | name = "num-integer" 425 | version = "0.1.45" 426 | source = "registry+https://github.com/rust-lang/crates.io-index" 427 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" 428 | dependencies = [ 429 | "autocfg", 430 | "num-traits", 431 | ] 432 | 433 | [[package]] 434 | name = "num-traits" 435 | version = "0.2.15" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" 438 | dependencies = [ 439 | "autocfg", 440 | ] 441 | 442 | [[package]] 443 | name = "once_cell" 444 | version = "1.13.0" 445 | source = "registry+https://github.com/rust-lang/crates.io-index" 446 | checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" 447 | 448 | [[package]] 449 | name = "opaque-debug" 450 | version = "0.2.3" 451 | source = "registry+https://github.com/rust-lang/crates.io-index" 452 | checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" 453 | 454 | [[package]] 455 | name = "opener" 456 | version = "0.5.0" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "4ea3ebcd72a54701f56345f16785a6d3ac2df7e986d273eb4395c0b01db17952" 459 | dependencies = [ 460 | "bstr", 461 | "winapi", 462 | ] 463 | 464 | [[package]] 465 | name = "os_str_bytes" 466 | version = "6.1.0" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" 469 | 470 | [[package]] 471 | name = "parse-zoneinfo" 472 | version = "0.3.0" 473 | source = "registry+https://github.com/rust-lang/crates.io-index" 474 | checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" 475 | dependencies = [ 476 | "regex", 477 | ] 478 | 479 | [[package]] 480 | name = "percent-encoding" 481 | version = "2.1.0" 482 | source = "registry+https://github.com/rust-lang/crates.io-index" 483 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 484 | 485 | [[package]] 486 | name = "pest" 487 | version = "2.1.3" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" 490 | dependencies = [ 491 | "ucd-trie", 492 | ] 493 | 494 | [[package]] 495 | name = "pest_derive" 496 | version = "2.1.0" 497 | source = "registry+https://github.com/rust-lang/crates.io-index" 498 | checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" 499 | dependencies = [ 500 | "pest", 501 | "pest_generator", 502 | ] 503 | 504 | [[package]] 505 | name = "pest_generator" 506 | version = "2.1.3" 507 | source = "registry+https://github.com/rust-lang/crates.io-index" 508 | checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" 509 | dependencies = [ 510 | "pest", 511 | "pest_meta", 512 | "proc-macro2", 513 | "quote", 514 | "syn", 515 | ] 516 | 517 | [[package]] 518 | name = "pest_meta" 519 | version = "2.1.3" 520 | source = "registry+https://github.com/rust-lang/crates.io-index" 521 | checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" 522 | dependencies = [ 523 | "maplit", 524 | "pest", 525 | "sha-1", 526 | ] 527 | 528 | [[package]] 529 | name = "phf" 530 | version = "0.10.1" 531 | source = "registry+https://github.com/rust-lang/crates.io-index" 532 | checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" 533 | dependencies = [ 534 | "phf_shared", 535 | ] 536 | 537 | [[package]] 538 | name = "phf_codegen" 539 | version = "0.10.0" 540 | source = "registry+https://github.com/rust-lang/crates.io-index" 541 | checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" 542 | dependencies = [ 543 | "phf_generator", 544 | "phf_shared", 545 | ] 546 | 547 | [[package]] 548 | name = "phf_generator" 549 | version = "0.10.0" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" 552 | dependencies = [ 553 | "phf_shared", 554 | "rand", 555 | ] 556 | 557 | [[package]] 558 | name = "phf_shared" 559 | version = "0.10.0" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" 562 | dependencies = [ 563 | "siphasher", 564 | "uncased", 565 | ] 566 | 567 | [[package]] 568 | name = "ppv-lite86" 569 | version = "0.2.16" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" 572 | 573 | [[package]] 574 | name = "proc-macro2" 575 | version = "1.0.40" 576 | source = "registry+https://github.com/rust-lang/crates.io-index" 577 | checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" 578 | dependencies = [ 579 | "unicode-ident", 580 | ] 581 | 582 | [[package]] 583 | name = "pulldown-cmark" 584 | version = "0.9.1" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6" 587 | dependencies = [ 588 | "bitflags", 589 | "memchr", 590 | "unicase", 591 | ] 592 | 593 | [[package]] 594 | name = "quote" 595 | version = "1.0.20" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" 598 | dependencies = [ 599 | "proc-macro2", 600 | ] 601 | 602 | [[package]] 603 | name = "rand" 604 | version = "0.8.5" 605 | source = "registry+https://github.com/rust-lang/crates.io-index" 606 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 607 | dependencies = [ 608 | "libc", 609 | "rand_chacha", 610 | "rand_core", 611 | ] 612 | 613 | [[package]] 614 | name = "rand_chacha" 615 | version = "0.3.1" 616 | source = "registry+https://github.com/rust-lang/crates.io-index" 617 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 618 | dependencies = [ 619 | "ppv-lite86", 620 | "rand_core", 621 | ] 622 | 623 | [[package]] 624 | name = "rand_core" 625 | version = "0.6.3" 626 | source = "registry+https://github.com/rust-lang/crates.io-index" 627 | checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" 628 | dependencies = [ 629 | "getrandom", 630 | ] 631 | 632 | [[package]] 633 | name = "redox_syscall" 634 | version = "0.2.13" 635 | source = "registry+https://github.com/rust-lang/crates.io-index" 636 | checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" 637 | dependencies = [ 638 | "bitflags", 639 | ] 640 | 641 | [[package]] 642 | name = "regex" 643 | version = "1.6.0" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" 646 | dependencies = [ 647 | "aho-corasick", 648 | "memchr", 649 | "regex-syntax", 650 | ] 651 | 652 | [[package]] 653 | name = "regex-automata" 654 | version = "0.1.10" 655 | source = "registry+https://github.com/rust-lang/crates.io-index" 656 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 657 | 658 | [[package]] 659 | name = "regex-syntax" 660 | version = "0.6.27" 661 | source = "registry+https://github.com/rust-lang/crates.io-index" 662 | checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" 663 | 664 | [[package]] 665 | name = "remove_dir_all" 666 | version = "0.5.3" 667 | source = "registry+https://github.com/rust-lang/crates.io-index" 668 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 669 | dependencies = [ 670 | "winapi", 671 | ] 672 | 673 | [[package]] 674 | name = "ryu" 675 | version = "1.0.10" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" 678 | 679 | [[package]] 680 | name = "same-file" 681 | version = "1.0.6" 682 | source = "registry+https://github.com/rust-lang/crates.io-index" 683 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 684 | dependencies = [ 685 | "winapi-util", 686 | ] 687 | 688 | [[package]] 689 | name = "semver" 690 | version = "1.0.12" 691 | source = "registry+https://github.com/rust-lang/crates.io-index" 692 | checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" 693 | 694 | [[package]] 695 | name = "serde" 696 | version = "1.0.138" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47" 699 | dependencies = [ 700 | "serde_derive", 701 | ] 702 | 703 | [[package]] 704 | name = "serde_derive" 705 | version = "1.0.138" 706 | source = "registry+https://github.com/rust-lang/crates.io-index" 707 | checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c" 708 | dependencies = [ 709 | "proc-macro2", 710 | "quote", 711 | "syn", 712 | ] 713 | 714 | [[package]] 715 | name = "serde_json" 716 | version = "1.0.82" 717 | source = "registry+https://github.com/rust-lang/crates.io-index" 718 | checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" 719 | dependencies = [ 720 | "itoa", 721 | "ryu", 722 | "serde", 723 | ] 724 | 725 | [[package]] 726 | name = "sha-1" 727 | version = "0.8.2" 728 | source = "registry+https://github.com/rust-lang/crates.io-index" 729 | checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" 730 | dependencies = [ 731 | "block-buffer", 732 | "digest", 733 | "fake-simd", 734 | "opaque-debug", 735 | ] 736 | 737 | [[package]] 738 | name = "shlex" 739 | version = "1.1.0" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" 742 | 743 | [[package]] 744 | name = "siphasher" 745 | version = "0.3.10" 746 | source = "registry+https://github.com/rust-lang/crates.io-index" 747 | checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" 748 | 749 | [[package]] 750 | name = "slug" 751 | version = "0.1.4" 752 | source = "registry+https://github.com/rust-lang/crates.io-index" 753 | checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" 754 | dependencies = [ 755 | "deunicode", 756 | ] 757 | 758 | [[package]] 759 | name = "strsim" 760 | version = "0.10.0" 761 | source = "registry+https://github.com/rust-lang/crates.io-index" 762 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 763 | 764 | [[package]] 765 | name = "syn" 766 | version = "1.0.98" 767 | source = "registry+https://github.com/rust-lang/crates.io-index" 768 | checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" 769 | dependencies = [ 770 | "proc-macro2", 771 | "quote", 772 | "unicode-ident", 773 | ] 774 | 775 | [[package]] 776 | name = "tempfile" 777 | version = "3.3.0" 778 | source = "registry+https://github.com/rust-lang/crates.io-index" 779 | checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" 780 | dependencies = [ 781 | "cfg-if", 782 | "fastrand", 783 | "libc", 784 | "redox_syscall", 785 | "remove_dir_all", 786 | "winapi", 787 | ] 788 | 789 | [[package]] 790 | name = "tera" 791 | version = "1.16.0" 792 | source = "registry+https://github.com/rust-lang/crates.io-index" 793 | checksum = "7c9783d6ff395ae80cf17ed9a25360e7ba37742a79fa8fddabb073c5c7c8856d" 794 | dependencies = [ 795 | "chrono", 796 | "chrono-tz", 797 | "globwalk", 798 | "humansize", 799 | "lazy_static", 800 | "percent-encoding", 801 | "pest", 802 | "pest_derive", 803 | "rand", 804 | "regex", 805 | "serde", 806 | "serde_json", 807 | "slug", 808 | "unic-segment", 809 | ] 810 | 811 | [[package]] 812 | name = "termcolor" 813 | version = "1.1.3" 814 | source = "registry+https://github.com/rust-lang/crates.io-index" 815 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 816 | dependencies = [ 817 | "winapi-util", 818 | ] 819 | 820 | [[package]] 821 | name = "textwrap" 822 | version = "0.15.0" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" 825 | 826 | [[package]] 827 | name = "thiserror" 828 | version = "1.0.31" 829 | source = "registry+https://github.com/rust-lang/crates.io-index" 830 | checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" 831 | dependencies = [ 832 | "thiserror-impl", 833 | ] 834 | 835 | [[package]] 836 | name = "thiserror-impl" 837 | version = "1.0.31" 838 | source = "registry+https://github.com/rust-lang/crates.io-index" 839 | checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" 840 | dependencies = [ 841 | "proc-macro2", 842 | "quote", 843 | "syn", 844 | ] 845 | 846 | [[package]] 847 | name = "thread_local" 848 | version = "1.1.4" 849 | source = "registry+https://github.com/rust-lang/crates.io-index" 850 | checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" 851 | dependencies = [ 852 | "once_cell", 853 | ] 854 | 855 | [[package]] 856 | name = "time" 857 | version = "0.1.44" 858 | source = "registry+https://github.com/rust-lang/crates.io-index" 859 | checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" 860 | dependencies = [ 861 | "libc", 862 | "wasi 0.10.0+wasi-snapshot-preview1", 863 | "winapi", 864 | ] 865 | 866 | [[package]] 867 | name = "toml" 868 | version = "0.5.9" 869 | source = "registry+https://github.com/rust-lang/crates.io-index" 870 | checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" 871 | dependencies = [ 872 | "serde", 873 | ] 874 | 875 | [[package]] 876 | name = "topological-sort" 877 | version = "0.1.0" 878 | source = "registry+https://github.com/rust-lang/crates.io-index" 879 | checksum = "aa7c7f42dea4b1b99439786f5633aeb9c14c1b53f75e282803c2ec2ad545873c" 880 | 881 | [[package]] 882 | name = "typenum" 883 | version = "1.15.0" 884 | source = "registry+https://github.com/rust-lang/crates.io-index" 885 | checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" 886 | 887 | [[package]] 888 | name = "ucd-trie" 889 | version = "0.1.4" 890 | source = "registry+https://github.com/rust-lang/crates.io-index" 891 | checksum = "89570599c4fe5585de2b388aab47e99f7fa4e9238a1399f707a02e356058141c" 892 | 893 | [[package]] 894 | name = "uncased" 895 | version = "0.9.7" 896 | source = "registry+https://github.com/rust-lang/crates.io-index" 897 | checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622" 898 | dependencies = [ 899 | "version_check", 900 | ] 901 | 902 | [[package]] 903 | name = "unic-char-property" 904 | version = "0.9.0" 905 | source = "registry+https://github.com/rust-lang/crates.io-index" 906 | checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" 907 | dependencies = [ 908 | "unic-char-range", 909 | ] 910 | 911 | [[package]] 912 | name = "unic-char-range" 913 | version = "0.9.0" 914 | source = "registry+https://github.com/rust-lang/crates.io-index" 915 | checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" 916 | 917 | [[package]] 918 | name = "unic-common" 919 | version = "0.9.0" 920 | source = "registry+https://github.com/rust-lang/crates.io-index" 921 | checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" 922 | 923 | [[package]] 924 | name = "unic-segment" 925 | version = "0.9.0" 926 | source = "registry+https://github.com/rust-lang/crates.io-index" 927 | checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" 928 | dependencies = [ 929 | "unic-ucd-segment", 930 | ] 931 | 932 | [[package]] 933 | name = "unic-ucd-segment" 934 | version = "0.9.0" 935 | source = "registry+https://github.com/rust-lang/crates.io-index" 936 | checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" 937 | dependencies = [ 938 | "unic-char-property", 939 | "unic-char-range", 940 | "unic-ucd-version", 941 | ] 942 | 943 | [[package]] 944 | name = "unic-ucd-version" 945 | version = "0.9.0" 946 | source = "registry+https://github.com/rust-lang/crates.io-index" 947 | checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" 948 | dependencies = [ 949 | "unic-common", 950 | ] 951 | 952 | [[package]] 953 | name = "unicase" 954 | version = "2.6.0" 955 | source = "registry+https://github.com/rust-lang/crates.io-index" 956 | checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" 957 | dependencies = [ 958 | "version_check", 959 | ] 960 | 961 | [[package]] 962 | name = "unicode-ident" 963 | version = "1.0.1" 964 | source = "registry+https://github.com/rust-lang/crates.io-index" 965 | checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" 966 | 967 | [[package]] 968 | name = "version_check" 969 | version = "0.9.4" 970 | source = "registry+https://github.com/rust-lang/crates.io-index" 971 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 972 | 973 | [[package]] 974 | name = "walkdir" 975 | version = "2.3.2" 976 | source = "registry+https://github.com/rust-lang/crates.io-index" 977 | checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" 978 | dependencies = [ 979 | "same-file", 980 | "winapi", 981 | "winapi-util", 982 | ] 983 | 984 | [[package]] 985 | name = "wasi" 986 | version = "0.10.0+wasi-snapshot-preview1" 987 | source = "registry+https://github.com/rust-lang/crates.io-index" 988 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 989 | 990 | [[package]] 991 | name = "wasi" 992 | version = "0.11.0+wasi-snapshot-preview1" 993 | source = "registry+https://github.com/rust-lang/crates.io-index" 994 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 995 | 996 | [[package]] 997 | name = "winapi" 998 | version = "0.3.9" 999 | source = "registry+https://github.com/rust-lang/crates.io-index" 1000 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1001 | dependencies = [ 1002 | "winapi-i686-pc-windows-gnu", 1003 | "winapi-x86_64-pc-windows-gnu", 1004 | ] 1005 | 1006 | [[package]] 1007 | name = "winapi-i686-pc-windows-gnu" 1008 | version = "0.4.0" 1009 | source = "registry+https://github.com/rust-lang/crates.io-index" 1010 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1011 | 1012 | [[package]] 1013 | name = "winapi-util" 1014 | version = "0.1.5" 1015 | source = "registry+https://github.com/rust-lang/crates.io-index" 1016 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1017 | dependencies = [ 1018 | "winapi", 1019 | ] 1020 | 1021 | [[package]] 1022 | name = "winapi-x86_64-pc-windows-gnu" 1023 | version = "0.4.0" 1024 | source = "registry+https://github.com/rust-lang/crates.io-index" 1025 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1026 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mdbook-tera" 3 | version = "0.5.1" 4 | authors = ["avitex "] 5 | edition = "2018" 6 | description = "Tera preprocessor for mdBook" 7 | keywords = ["mdbook", "tera", "preprocessor"] 8 | categories = ["command-line-utilities", "template-engine"] 9 | documentation = "https://docs.rs/mdbook-tera" 10 | homepage = "https://github.com/avitex/mdbook-tera" 11 | repository = "https://github.com/avitex/mdbook-tera" 12 | license = "MIT" 13 | readme = "README.md" 14 | include = ["src/**/*", "README.md", "LICENSE", "Cargo.lock", "Cargo.toml"] 15 | 16 | [features] 17 | default = ["toml", "json"] 18 | json = ["serde_json"] 19 | 20 | [[bin]] 21 | name = "mdbook-tera" 22 | required-features = ["toml", "json"] 23 | 24 | [dependencies] 25 | clap = "~3" 26 | serde = "~1" 27 | anyhow = "~1" 28 | semver = "~1" 29 | tera = "^1.5.0" 30 | globwalk = "0.8" 31 | mdbook = { version = "0.4", default-features = false } 32 | 33 | toml = { version = "~0.5", optional = true } 34 | serde_json = { version = "~1", optional = true } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020-2021 James Dyson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://github.com/avitex/mdbook-tera/workflows/build/badge.svg)](https://github.com/avitex/mdbook-tera/actions?query=workflow:build) 2 | [![Crate](https://img.shields.io/crates/v/mdbook-tera.svg)](https://crates.io/crates/mdbook-tera) 3 | [![Docs](https://docs.rs/mdbook-tera/badge.svg)](https://docs.rs/mdbook-tera) 4 | 5 | # mdbook-tera 6 | 7 | **[Tera](https://github.com/Keats/tera) preprocessor for [mdBook](https://github.com/rust-lang/mdBook)** 8 | API documentation hosted on [docs.rs](https://docs.rs/mdbook-tera). 9 | 10 | ```text 11 | $ mdbook-tera --help 12 | mdbook-tera 0.5.1 13 | A mdBook preprocessor that renders Tera 14 | 15 | USAGE: 16 | mdbook-tera [OPTIONS] [SUBCOMMAND] 17 | 18 | OPTIONS: 19 | -h, --help Print help information 20 | --json Sets context from JSON file 21 | --template-include Include tera templates matching a glob expression [default: 22 | **/*.tera] 23 | --template-root Root directory to include templates from [default: ./src] 24 | --toml Sets context from TOML file 25 | -V, --version Print version information 26 | 27 | SUBCOMMANDS: 28 | help Print this message or the help of the given subcommand(s) 29 | supports Check whether a renderer is supported by this preprocessor 30 | ``` 31 | 32 | ## Usage 33 | 34 | First install the tera preprocessor. 35 | 36 | ```text 37 | cargo install mdbook-tera 38 | ``` 39 | 40 | Then in your `book.toml` file, add the tera preprocessor as below. 41 | 42 | ### Default Configuration 43 | 44 | ```toml 45 | # Default options, load a TOML context file from ./src/context.toml 46 | [preprocessor.tera] 47 | ``` 48 | 49 | ### JSON Configuration 50 | 51 | ```toml 52 | [preprocessor.tera] 53 | command = "mdbook-tera --json ./src/context.json" 54 | ``` 55 | 56 | ### Usage in Markdown files 57 | 58 | See `example-book` for a basic usage. 59 | 60 | Simply define your values in the `context.toml` file, and use them in tera statements. 61 | You can access the book context with the key `ctx`. 62 | 63 | ```md 64 | # My Heading 65 | 66 | {{ my_value }} 67 | ``` 68 | -------------------------------------------------------------------------------- /example-book/.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | -------------------------------------------------------------------------------- /example-book/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["James Dyson"] 3 | language = "en" 4 | title = "Example Book" 5 | 6 | [preprocessor.tera] 7 | command = "cargo run" -------------------------------------------------------------------------------- /example-book/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | - [Chapter 1](./chapter_1.md) 4 | -------------------------------------------------------------------------------- /example-book/src/chapter_1.md: -------------------------------------------------------------------------------- 1 | {% import "macros.tera" as macros %} 2 | 3 | # Chapter 1 4 | 5 | {{ macros::greeting(name=my_value) }} 6 | 7 | This book is written by {{ ctx.config.book.authors | join() }} 8 | -------------------------------------------------------------------------------- /example-book/src/context.toml: -------------------------------------------------------------------------------- 1 | my_value = "world" -------------------------------------------------------------------------------- /example-book/src/macros.tera: -------------------------------------------------------------------------------- 1 | {% macro greeting(name) %} 2 | Hello {{ name }} 3 | {% endmacro greeting %} 4 | -------------------------------------------------------------------------------- /src/context.rs: -------------------------------------------------------------------------------- 1 | #[cfg(any(feature = "json", feature = "toml"))] 2 | use std::fs; 3 | #[cfg(any(feature = "json", feature = "toml"))] 4 | use std::path::Path; 5 | 6 | pub use tera::Context; 7 | 8 | #[cfg(any(feature = "json", feature = "toml"))] 9 | use crate::Error; 10 | 11 | /// A context source for the Tera preprocessor. 12 | pub trait ContextSource { 13 | /// Returns a context from the source. 14 | fn context(&self) -> Context; 15 | } 16 | 17 | /// Static context source for the Tera preprocessor. 18 | #[derive(Clone)] 19 | pub struct StaticContextSource { 20 | context: Context, 21 | } 22 | 23 | impl ContextSource for StaticContextSource { 24 | fn context(&self) -> Context { 25 | self.context.clone() 26 | } 27 | } 28 | 29 | impl StaticContextSource { 30 | /// Construct a context source given a tera context. 31 | #[must_use] 32 | pub const fn new(context: Context) -> Self { 33 | Self { context } 34 | } 35 | 36 | /// Construct a context source given a JSON path. 37 | /// 38 | /// # Errors 39 | /// 40 | /// Returns an error if the provided path or JSON read is invalid. 41 | #[cfg(feature = "json")] 42 | pub fn from_json_file

(path: P) -> Result 43 | where 44 | P: AsRef, 45 | { 46 | let context_str = fs::read_to_string(path)?; 47 | let value = context_str.parse()?; 48 | let context = Context::from_value(value)?; 49 | Ok(Self::new(context)) 50 | } 51 | 52 | /// Construct a context source given a TOML path. 53 | /// 54 | /// # Errors 55 | /// 56 | /// Returns an error if the provided path or TOML read is invalid. 57 | #[cfg(feature = "toml")] 58 | pub fn from_toml_file

(path: P) -> Result 59 | where 60 | P: AsRef, 61 | { 62 | let context_str = fs::read_to_string(path)?; 63 | let value: toml::Value = context_str.parse()?; 64 | let context = Context::from_serialize(value)?; 65 | Ok(Self::new(context)) 66 | } 67 | } 68 | 69 | impl Default for StaticContextSource { 70 | fn default() -> Self { 71 | Self::new(Context::default()) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny( 2 | warnings, 3 | rustdoc::all, 4 | clippy::all, 5 | clippy::cargo, 6 | clippy::nursery, 7 | clippy::pedantic 8 | )] 9 | #![allow(clippy::module_name_repetitions)] 10 | #![cfg_attr(doc, deny(rustdoc::all))] 11 | #![cfg_attr(doc, allow(rustdoc::missing_doc_code_examples))] 12 | 13 | mod context; 14 | 15 | use std::path::Path; 16 | 17 | use anyhow::anyhow; 18 | use globwalk::GlobWalkerBuilder; 19 | use mdbook::book::{Book, BookItem}; 20 | use mdbook::errors::Error; 21 | use mdbook::preprocess::{Preprocessor, PreprocessorContext}; 22 | use tera::{Context, Tera}; 23 | 24 | pub use self::context::{ContextSource, StaticContextSource}; 25 | 26 | /// A mdBook preprocessor that renders Tera. 27 | #[derive(Clone)] 28 | pub struct TeraPreprocessor { 29 | tera: Tera, 30 | context: C, 31 | } 32 | 33 | impl TeraPreprocessor { 34 | /// Construct a Tera preprocessor given a context source. 35 | pub fn new(context: C) -> Self { 36 | Self { 37 | context, 38 | tera: Tera::default(), 39 | } 40 | } 41 | 42 | /// Includes Tera templates given a glob pattern and a root directory. 43 | /// 44 | /// # Errors 45 | /// 46 | /// Returns an error if the provided path cannot be canonicalized or the 47 | /// inheritance chain can't be built, such as adding a child template 48 | /// without the parent one. 49 | #[allow(clippy::missing_panics_doc)] 50 | pub fn include_templates

(&mut self, root: P, glob_str: &str) -> Result<(), Error> 51 | where 52 | P: AsRef, 53 | { 54 | let root = &root.as_ref().canonicalize()?; 55 | 56 | let paths = GlobWalkerBuilder::from_patterns(root, &[glob_str]) 57 | .build()? 58 | .filter_map(Result::ok) 59 | .map(|p| { 60 | let path = p.into_path(); 61 | let name = path 62 | .strip_prefix(root) 63 | .unwrap() 64 | .to_string_lossy() 65 | .into_owned(); 66 | (path, Some(name)) 67 | }); 68 | 69 | self.tera.add_template_files(paths)?; 70 | 71 | Ok(()) 72 | } 73 | 74 | /// Returns a mutable reference to the internal Tera engine. 75 | pub fn tera_mut(&mut self) -> &mut Tera { 76 | &mut self.tera 77 | } 78 | } 79 | 80 | impl Default for TeraPreprocessor { 81 | fn default() -> Self { 82 | Self::new(Default::default()) 83 | } 84 | } 85 | 86 | impl Preprocessor for TeraPreprocessor 87 | where 88 | C: ContextSource, 89 | { 90 | fn name(&self) -> &str { 91 | "tera" 92 | } 93 | 94 | fn run(&self, book_ctx: &PreprocessorContext, mut book: Book) -> Result { 95 | let mut tera = Tera::default(); 96 | tera.extend(&self.tera).unwrap(); 97 | 98 | let mut ctx = Context::new(); 99 | ctx.insert("ctx", &book_ctx); 100 | ctx.extend(self.context.context()); 101 | 102 | render_book_items(&mut book, &mut tera, &ctx)?; 103 | 104 | Ok(book) 105 | } 106 | } 107 | 108 | fn render_book_items(book: &mut Book, tera: &mut Tera, context: &Context) -> Result<(), Error> { 109 | let mut templates = Vec::new(); 110 | // Build the list of templates 111 | collect_item_chapters(&mut templates, book.sections.as_slice())?; 112 | // Register them 113 | tera.add_raw_templates(templates)?; 114 | // Render chapters 115 | render_item_chapters(tera, context, book.sections.as_mut_slice()) 116 | } 117 | 118 | fn collect_item_chapters<'a>( 119 | templates: &mut Vec<(&'a str, &'a str)>, 120 | items: &'a [BookItem], 121 | ) -> Result<(), Error> { 122 | for item in items { 123 | match item { 124 | BookItem::Chapter(chapter) => { 125 | if let Some(ref path) = chapter.path { 126 | let path = path 127 | .to_str() 128 | .ok_or_else(|| anyhow!("invalid chapter path"))?; 129 | templates.push((path, chapter.content.as_str())); 130 | collect_item_chapters(templates, chapter.sub_items.as_slice())?; 131 | } 132 | } 133 | BookItem::PartTitle(_) | BookItem::Separator => (), 134 | } 135 | } 136 | Ok(()) 137 | } 138 | 139 | fn render_item_chapters( 140 | tera: &mut Tera, 141 | context: &Context, 142 | items: &mut [BookItem], 143 | ) -> Result<(), Error> { 144 | for item in items { 145 | match item { 146 | BookItem::Chapter(chapter) => { 147 | if let Some(ref path) = chapter.path { 148 | let path = path 149 | .to_str() 150 | .ok_or_else(|| anyhow!("invalid chapter path"))?; 151 | chapter.content = tera.render(path, context)?; 152 | render_item_chapters(tera, context, chapter.sub_items.as_mut_slice())?; 153 | } 154 | } 155 | BookItem::PartTitle(_) | BookItem::Separator => (), 156 | } 157 | } 158 | Ok(()) 159 | } 160 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | use std::{io, process}; 3 | 4 | use anyhow::anyhow; 5 | use clap::{App, Arg}; 6 | use mdbook::errors::Error; 7 | use mdbook::preprocess::{CmdPreprocessor, Preprocessor}; 8 | use semver::{Version, VersionReq}; 9 | 10 | use mdbook_tera::{StaticContextSource, TeraPreprocessor}; 11 | 12 | const DEFAULT_CONTEXT_TOML_PATH: &str = "./src/context.toml"; 13 | const DEFAULT_TEMPLATE_ROOT: &str = "./src"; 14 | 15 | fn app() -> App<'static> { 16 | App::new("mdbook-tera") 17 | .about("A mdBook preprocessor that renders Tera") 18 | .version(env!("CARGO_PKG_VERSION")) 19 | .arg( 20 | Arg::new("json") 21 | .long("json") 22 | .value_name("FILE") 23 | .help("Sets context from JSON file") 24 | .takes_value(true), 25 | ) 26 | .arg( 27 | Arg::new("toml") 28 | .long("toml") 29 | .value_name("FILE") 30 | .help("Sets context from TOML file") 31 | .takes_value(true), 32 | ) 33 | .arg( 34 | Arg::new("template-root") 35 | .long("template-root") 36 | .value_name("PATH") 37 | .help("Root directory to include templates from") 38 | .default_value(DEFAULT_TEMPLATE_ROOT) 39 | .takes_value(true), 40 | ) 41 | .arg( 42 | Arg::new("template-include") 43 | .long("template-include") 44 | .value_name("GLOB") 45 | .help("Include tera templates matching a glob expression") 46 | .default_value("**/*.tera") 47 | .takes_value(true), 48 | ) 49 | .subcommand( 50 | App::new("supports") 51 | .arg(Arg::new("renderer").required(true)) 52 | .about("Check whether a renderer is supported by this preprocessor"), 53 | ) 54 | } 55 | 56 | fn main() { 57 | let matches = app().get_matches(); 58 | 59 | if matches.subcommand_matches("supports").is_some() { 60 | // We support every renderer 61 | process::exit(0); 62 | } 63 | 64 | let ctx_src = match (matches.value_of("json"), matches.value_of("toml")) { 65 | (Some(_), Some(_)) => exit_with_error(anyhow!("cannot set both json and toml context")), 66 | (Some(json_path), None) => StaticContextSource::from_json_file(json_path), 67 | (None, Some(toml_path)) => StaticContextSource::from_toml_file(toml_path), 68 | (None, None) => { 69 | let default_path = Path::new(DEFAULT_CONTEXT_TOML_PATH); 70 | if default_path.exists() { 71 | StaticContextSource::from_toml_file(default_path) 72 | } else { 73 | Ok(StaticContextSource::default()) 74 | } 75 | } 76 | }; 77 | 78 | let ctx_src = match ctx_src { 79 | Ok(ctx_src) => ctx_src, 80 | Err(err) => { 81 | exit_with_error(anyhow!("failed to load context: {}", err)); 82 | } 83 | }; 84 | 85 | let mut preprocessor = TeraPreprocessor::new(ctx_src); 86 | 87 | if let Some(glob_str) = matches.value_of("template-include") { 88 | let root_dir = matches 89 | .value_of("template-root") 90 | .unwrap_or(DEFAULT_TEMPLATE_ROOT); 91 | 92 | if glob_str != "false" { 93 | if let Err(err) = preprocessor.include_templates(root_dir, glob_str) { 94 | exit_with_error(anyhow!(err)); 95 | } 96 | } 97 | } 98 | 99 | if let Err(err) = handle_preprocessing(&preprocessor) { 100 | exit_with_error(anyhow!(err)); 101 | } 102 | } 103 | 104 | fn handle_preprocessing(pre: &dyn Preprocessor) -> Result<(), Error> { 105 | let (ctx, book) = CmdPreprocessor::parse_input(io::stdin())?; 106 | 107 | let ver = Version::parse(ctx.mdbook_version.as_str()).unwrap(); 108 | let ver_req = VersionReq::parse(mdbook::MDBOOK_VERSION).unwrap(); 109 | 110 | if !ver_req.matches(&ver) { 111 | eprintln!( 112 | "Warning: The {} plugin has the version requirement {} for mdbook, \ 113 | but we're being called from version {}", 114 | pre.name(), 115 | ver_req, 116 | ver 117 | ); 118 | } 119 | 120 | let processed_book = pre.run(&ctx, book)?; 121 | serde_json::to_writer(io::stdout(), &processed_book)?; 122 | 123 | Ok(()) 124 | } 125 | 126 | fn exit_with_error(err: Error) -> ! { 127 | eprintln!("{:?}", err); 128 | process::exit(1); 129 | } 130 | --------------------------------------------------------------------------------