From b040499d2d19e5c4e91ec11db73d7602431ae77b Mon Sep 17 00:00:00 2001 From: Huck Boles Date: Thu, 11 May 2023 14:16:32 -0500 Subject: [PATCH] rebuilt test site --- .gitignore | 2 +- Cargo.lock | 480 ++++++++++++- Cargo.toml | 5 + LICENSE | 675 ++++++++++++++++++ README | 0 benches/build_site.rs | 0 files/site/build/dir1/dir.html | 28 + .../site/build/dir1/sub_dir1/deep1/deep.html | 5 + .../site/build/dir1/sub_dir1/deep2/deep.html | 5 + files/site/build/dir1/sub_dir1/sub_dir.html | 17 + files/site/build/dir1/sub_dir2/sub_dir.html | 11 + files/site/build/dir1/sub_dir3/sub_dir.html | 11 + files/site/build/dir2/dir.html | 19 + files/site/build/expand.html | 4 + .../site/build/expand_html.html | 0 files/site/build/root.html | 12 + files/site/build/sub_dir/deep/deep.html | 4 + files/site/build/sub_dir/sub_dir.html | 4 + files/site/pattern/base/default.meta | 3 + files/site/pattern/base/text.meta | 1 + .../site/pattern/body}/default.meta | 2 + files/site/pattern/body/variables.meta | 3 + files/site/pattern/footer/default.meta | 1 + files/site/pattern/header/default.meta | 1 + files/site/pattern/header/list.meta | 4 + files/site/pattern/link/bold.meta | 1 + files/site/pattern/link/default.meta | 1 + files/site/pattern/list/default.meta | 3 + files/site/pattern/list/item/default.meta | 1 + files/site/source/dir1/dir.meta | 9 + .../site/source/dir1/sub_dir1/deep1/deep.meta | 6 + .../site/source/dir1/sub_dir1/deep2/deep.meta | 2 + files/site/source/dir1/sub_dir1/sub_dir.meta | 14 + files/site/source/dir1/sub_dir2/sub_dir.meta | 8 + files/site/source/dir1/sub_dir3/sub_dir.meta | 11 + files/site/source/dir2/dir.meta | 20 + files/site/source/root.meta | 2 + src/{filetype => }/builder.rs | 79 +- src/filetype.rs | 5 - src/lib.rs | 9 +- src/main.rs | 48 +- src/{parser => }/meta.pest | 0 src/{filetype => }/metafile.rs | 0 src/options.rs | 12 +- src/parser.rs | 227 +++++- src/parser/parse.rs | 155 ---- src/tests.rs | 2 - src/tests/test_metafile.rs | 77 -- src/tests/test_parser.rs | 54 -- test_site/pattern/test/array.meta | 1 - test_site/pattern/test/blank/default.meta | 1 - test_site/pattern/test/default/default.meta | 1 - test_site/pattern/test/new/default.meta | 1 - test_site/pattern/test/new/new.meta | 1 - test_site/pattern/test/overwrite/default.meta | 1 - .../pattern/test/overwrite/overwrite.meta | 1 - test_site/pattern/test/parent/default.meta | 1 - test_site/pattern/test/parent/parent.meta | 1 - test_site/pattern/test/pattern.meta | 7 - test_site/pattern/test/sub_pat/default.meta | 1 - .../pattern/test/sub_pat/sub_pattern.meta | 1 - test_site/source/expand.meta | 37 - test_site/source/expand_html.meta | 19 - test_site/source/sub_dir/deep/deep.meta | 14 - test_site/source/sub_dir/sub_dir.meta | 5 - tests/files/expanded | 27 - tests/files/test_source.meta | 30 - tests/metafile_builder.rs | 54 -- 68 files changed, 1687 insertions(+), 560 deletions(-) create mode 100644 LICENSE create mode 100644 README create mode 100644 benches/build_site.rs create mode 100644 files/site/build/dir1/dir.html create mode 100644 files/site/build/dir1/sub_dir1/deep1/deep.html create mode 100644 files/site/build/dir1/sub_dir1/deep2/deep.html create mode 100644 files/site/build/dir1/sub_dir1/sub_dir.html create mode 100644 files/site/build/dir1/sub_dir2/sub_dir.html create mode 100644 files/site/build/dir1/sub_dir3/sub_dir.html create mode 100644 files/site/build/dir2/dir.html create mode 100644 files/site/build/expand.html rename tests/files/expanded_html => files/site/build/expand_html.html (100%) create mode 100644 files/site/build/root.html create mode 100644 files/site/build/sub_dir/deep/deep.html create mode 100644 files/site/build/sub_dir/sub_dir.html create mode 100644 files/site/pattern/base/default.meta create mode 100644 files/site/pattern/base/text.meta rename {test_site/pattern/base => files/site/pattern/body}/default.meta (59%) create mode 100644 files/site/pattern/body/variables.meta create mode 100644 files/site/pattern/footer/default.meta create mode 100644 files/site/pattern/header/default.meta create mode 100644 files/site/pattern/header/list.meta create mode 100644 files/site/pattern/link/bold.meta create mode 100644 files/site/pattern/link/default.meta create mode 100644 files/site/pattern/list/default.meta create mode 100644 files/site/pattern/list/item/default.meta create mode 100644 files/site/source/dir1/dir.meta create mode 100644 files/site/source/dir1/sub_dir1/deep1/deep.meta create mode 100644 files/site/source/dir1/sub_dir1/deep2/deep.meta create mode 100644 files/site/source/dir1/sub_dir1/sub_dir.meta create mode 100644 files/site/source/dir1/sub_dir2/sub_dir.meta create mode 100644 files/site/source/dir1/sub_dir3/sub_dir.meta create mode 100644 files/site/source/dir2/dir.meta create mode 100644 files/site/source/root.meta rename src/{filetype => }/builder.rs (76%) delete mode 100644 src/filetype.rs rename src/{parser => }/meta.pest (100%) rename src/{filetype => }/metafile.rs (100%) delete mode 100644 src/parser/parse.rs delete mode 100644 src/tests.rs delete mode 100644 src/tests/test_metafile.rs delete mode 100644 src/tests/test_parser.rs delete mode 100644 test_site/pattern/test/array.meta delete mode 100644 test_site/pattern/test/blank/default.meta delete mode 100644 test_site/pattern/test/default/default.meta delete mode 100644 test_site/pattern/test/new/default.meta delete mode 100644 test_site/pattern/test/new/new.meta delete mode 100644 test_site/pattern/test/overwrite/default.meta delete mode 100644 test_site/pattern/test/overwrite/overwrite.meta delete mode 100644 test_site/pattern/test/parent/default.meta delete mode 100644 test_site/pattern/test/parent/parent.meta delete mode 100644 test_site/pattern/test/pattern.meta delete mode 100644 test_site/pattern/test/sub_pat/default.meta delete mode 100644 test_site/pattern/test/sub_pat/sub_pattern.meta delete mode 100644 test_site/source/expand.meta delete mode 100644 test_site/source/expand_html.meta delete mode 100644 test_site/source/sub_dir/deep/deep.meta delete mode 100644 test_site/source/sub_dir/sub_dir.meta delete mode 100644 tests/files/expanded delete mode 100644 tests/files/test_source.meta delete mode 100644 tests/metafile_builder.rs diff --git a/.gitignore b/.gitignore index c688828..9c45757 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ /target -/test_site/build +/test/build/ diff --git a/Cargo.lock b/Cargo.lock index 3370acb..8afe109 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "anstream" version = "0.3.2" @@ -66,6 +72,23 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "backtrace" version = "0.3.67" @@ -96,6 +119,18 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cc" version = "1.0.79" @@ -108,6 +143,45 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "bitflags", + "clap_lex 0.2.4", + "indexmap", + "textwrap", +] + [[package]] name = "clap" version = "4.2.7" @@ -128,7 +202,7 @@ dependencies = [ "anstream", "anstyle", "bitflags", - "clap_lex", + "clap_lex 0.4.1", "strsim", ] @@ -144,6 +218,15 @@ dependencies = [ "syn 2.0.15", ] +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "clap_lex" version = "0.4.1" @@ -178,6 +261,85 @@ dependencies = [ "libc", ] +[[package]] +name = "criterion" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" +dependencies = [ + "anes", + "atty", + "cast", + "ciborium", + "clap 3.2.25", + "criterion-plot", + "itertools 0.10.5", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +dependencies = [ + "cfg-if", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -267,12 +429,42 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.3.1" @@ -285,13 +477,23 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + [[package]] name = "io-lifetimes" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.1", "libc", "windows-sys", ] @@ -302,7 +504,7 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.1", "io-lifetimes", "rustix", "windows-sys", @@ -317,6 +519,36 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "js-sys" +version = "0.3.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68c16e1bfd491478ab155fd8b4896b86f9ede344949b641e61501e07c2b8b4d5" +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 = "libc" version = "0.2.144" @@ -329,18 +561,37 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + [[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + [[package]] name = "metaforge" version = "0.1.1" dependencies = [ - "clap", + "clap 4.2.7", "color-eyre", + "criterion", "pandoc", "pest", "pest_derive", @@ -357,6 +608,25 @@ dependencies = [ "adler", ] +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + [[package]] name = "object" version = "0.30.3" @@ -372,6 +642,18 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "os_str_bytes" +version = "6.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" + [[package]] name = "output_vt100" version = "0.1.3" @@ -393,7 +675,7 @@ version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb8469d27ed9fd7925629076a3675fea964c3f44c49662bdf549a8b7ddf0820" dependencies = [ - "itertools", + "itertools 0.8.2", ] [[package]] @@ -440,6 +722,34 @@ dependencies = [ "sha2", ] +[[package]] +name = "plotters" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" + +[[package]] +name = "plotters-svg" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" +dependencies = [ + "plotters-backend", +] + [[package]] name = "pretty_assertions" version = "1.3.0" @@ -470,6 +780,43 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "regex" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -490,6 +837,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + [[package]] name = "same-file" version = "1.0.6" @@ -499,6 +852,43 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "serde_json" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha2" version = "0.10.6" @@ -538,6 +928,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + [[package]] name = "thiserror" version = "1.0.40" @@ -558,6 +954,16 @@ dependencies = [ "syn 2.0.15", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "typenum" version = "1.16.0" @@ -598,6 +1004,70 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasm-bindgen" +version = "0.2.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b6cb788c4e39112fbe1822277ef6fb3c55cd86b95cb3d3c4c1c9597e4ac74b4" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e522ed4105a9d626d885b35d62501b30d9666283a5c8be12c14a8bdafe7822" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.15", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "358a79a0cb89d21db8120cbfb91392335913e4890665b1a7981d9e956903b434" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a901d592cafaa4d711bc324edfaff879ac700b19c3dfd60058d2b445be2691eb" + +[[package]] +name = "web-sys" +version = "0.3.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b5f940c7edfdc6d12126d98c9ef4d1b3d470011c47c76a6581df47ad9ba721" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 471f100..6f9a987 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,8 @@ pest_derive = "2" [dev-dependencies] pretty_assertions = "1" +criterion = "0.4" + +[[bench]] +name = "build_site" +harness = false diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..53d1f3d --- /dev/null +++ b/LICENSE @@ -0,0 +1,675 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + diff --git a/README b/README new file mode 100644 index 0000000..e69de29 diff --git a/benches/build_site.rs b/benches/build_site.rs new file mode 100644 index 0000000..e69de29 diff --git a/files/site/build/dir1/dir.html b/files/site/build/dir1/dir.html new file mode 100644 index 0000000..e0b7905 --- /dev/null +++ b/files/site/build/dir1/dir.html @@ -0,0 +1,28 @@ + + +
HEADER
+ +

LIST

+This is to test using arrays as lists. +
    +
  • +A +
  • +
  • +Single +
  • +
  • +Word +
  • +
  • +Per +
  • +
  • +Item +
  • +
+ + +
FOOTER
+ + diff --git a/files/site/build/dir1/sub_dir1/deep1/deep.html b/files/site/build/dir1/sub_dir1/deep1/deep.html new file mode 100644 index 0000000..a60088b --- /dev/null +++ b/files/site/build/dir1/sub_dir1/deep1/deep.html @@ -0,0 +1,5 @@ + +

SIMPLE SUBSTITUTION

+

variable: GOOD

+ + diff --git a/files/site/build/dir1/sub_dir1/deep2/deep.html b/files/site/build/dir1/sub_dir1/deep2/deep.html new file mode 100644 index 0000000..27c9159 --- /dev/null +++ b/files/site/build/dir1/sub_dir1/deep2/deep.html @@ -0,0 +1,5 @@ + + +GOOD + + diff --git a/files/site/build/dir1/sub_dir1/sub_dir.html b/files/site/build/dir1/sub_dir1/sub_dir.html new file mode 100644 index 0000000..a510f98 --- /dev/null +++ b/files/site/build/dir1/sub_dir1/sub_dir.html @@ -0,0 +1,17 @@ + + +
HEADER
+ +

LINKS

+

This should create a group of bold links A Website B Place C Dest

+ + +
FOOTER
+ + diff --git a/files/site/build/dir1/sub_dir2/sub_dir.html b/files/site/build/dir1/sub_dir2/sub_dir.html new file mode 100644 index 0000000..6907021 --- /dev/null +++ b/files/site/build/dir1/sub_dir2/sub_dir.html @@ -0,0 +1,11 @@ + + + + +

BLANK

+

This should have no header or footer

+ + + + + diff --git a/files/site/build/dir1/sub_dir3/sub_dir.html b/files/site/build/dir1/sub_dir3/sub_dir.html new file mode 100644 index 0000000..52ea22b --- /dev/null +++ b/files/site/build/dir1/sub_dir3/sub_dir.html @@ -0,0 +1,11 @@ + + +
HEADER
+ +

HEADER LIST

+

This should have a list in the header

+ + +
FOOTER
+ + diff --git a/files/site/build/dir2/dir.html b/files/site/build/dir2/dir.html new file mode 100644 index 0000000..e3465ee --- /dev/null +++ b/files/site/build/dir2/dir.html @@ -0,0 +1,19 @@ + +

MARKDOWN

+ +

This is a test for how various markdown elements translate

+

Small Header

+
    +
  • Lists
  • +
  • With
  • +
  • Items
  • +
+

tiny header

+

Fancy Text With +Adornments

+

+Inline HTML +

+

a link

+ + diff --git a/files/site/build/expand.html b/files/site/build/expand.html new file mode 100644 index 0000000..a9c1572 --- /dev/null +++ b/files/site/build/expand.html @@ -0,0 +1,4 @@ + + + + diff --git a/tests/files/expanded_html b/files/site/build/expand_html.html similarity index 100% rename from tests/files/expanded_html rename to files/site/build/expand_html.html diff --git a/files/site/build/root.html b/files/site/build/root.html new file mode 100644 index 0000000..139ffbf --- /dev/null +++ b/files/site/build/root.html @@ -0,0 +1,12 @@ + + +
HEADER
+ +

ROOT

+

This is to test that the default base works without any +defintions.

+ + +
FOOTER
+ + diff --git a/files/site/build/sub_dir/deep/deep.html b/files/site/build/sub_dir/deep/deep.html new file mode 100644 index 0000000..a9c1572 --- /dev/null +++ b/files/site/build/sub_dir/deep/deep.html @@ -0,0 +1,4 @@ + + + + diff --git a/files/site/build/sub_dir/sub_dir.html b/files/site/build/sub_dir/sub_dir.html new file mode 100644 index 0000000..d008ed6 --- /dev/null +++ b/files/site/build/sub_dir/sub_dir.html @@ -0,0 +1,4 @@ + +

This is a simple filler file with a single variable: variable

+ + diff --git a/files/site/pattern/base/default.meta b/files/site/pattern/base/default.meta new file mode 100644 index 0000000..c47271e --- /dev/null +++ b/files/site/pattern/base/default.meta @@ -0,0 +1,3 @@ + + &{body} + diff --git a/files/site/pattern/base/text.meta b/files/site/pattern/base/text.meta new file mode 100644 index 0000000..8b9ce1f --- /dev/null +++ b/files/site/pattern/base/text.meta @@ -0,0 +1 @@ +&{SOURCE} diff --git a/test_site/pattern/base/default.meta b/files/site/pattern/body/default.meta similarity index 59% rename from test_site/pattern/base/default.meta rename to files/site/pattern/body/default.meta index e820c4c..4ee24b7 100644 --- a/test_site/pattern/base/default.meta +++ b/files/site/pattern/body/default.meta @@ -1,3 +1,5 @@ +&{header} &{SOURCE} +&{footer} diff --git a/files/site/pattern/body/variables.meta b/files/site/pattern/body/variables.meta new file mode 100644 index 0000000..982fba0 --- /dev/null +++ b/files/site/pattern/body/variables.meta @@ -0,0 +1,3 @@ + + ${variable} + diff --git a/files/site/pattern/footer/default.meta b/files/site/pattern/footer/default.meta new file mode 100644 index 0000000..fcf2c2a --- /dev/null +++ b/files/site/pattern/footer/default.meta @@ -0,0 +1 @@ +
FOOTER
diff --git a/files/site/pattern/header/default.meta b/files/site/pattern/header/default.meta new file mode 100644 index 0000000..8d0f674 --- /dev/null +++ b/files/site/pattern/header/default.meta @@ -0,0 +1 @@ +
HEADER
diff --git a/files/site/pattern/header/list.meta b/files/site/pattern/header/list.meta new file mode 100644 index 0000000..47db5db --- /dev/null +++ b/files/site/pattern/header/list.meta @@ -0,0 +1,4 @@ +
+

A list called: ${list_name}

+&{list} +
diff --git a/files/site/pattern/link/bold.meta b/files/site/pattern/link/bold.meta new file mode 100644 index 0000000..e6acc5a --- /dev/null +++ b/files/site/pattern/link/bold.meta @@ -0,0 +1 @@ +@{title} diff --git a/files/site/pattern/link/default.meta b/files/site/pattern/link/default.meta new file mode 100644 index 0000000..d88cfe0 --- /dev/null +++ b/files/site/pattern/link/default.meta @@ -0,0 +1 @@ +@{title} diff --git a/files/site/pattern/list/default.meta b/files/site/pattern/list/default.meta new file mode 100644 index 0000000..e9e730c --- /dev/null +++ b/files/site/pattern/list/default.meta @@ -0,0 +1,3 @@ +
    + &{list.item} +
diff --git a/files/site/pattern/list/item/default.meta b/files/site/pattern/list/item/default.meta new file mode 100644 index 0000000..22b704c --- /dev/null +++ b/files/site/pattern/list/item/default.meta @@ -0,0 +1 @@ +
  • @{items}
  • diff --git a/files/site/source/dir1/dir.meta b/files/site/source/dir1/dir.meta new file mode 100644 index 0000000..b051e39 --- /dev/null +++ b/files/site/source/dir1/dir.meta @@ -0,0 +1,9 @@ +@{ + list.item.items = ['A', 'Single','Word','Per','Item'] +} + +# LIST + +This is to test using arrays as lists. + +&{list} diff --git a/files/site/source/dir1/sub_dir1/deep1/deep.meta b/files/site/source/dir1/sub_dir1/deep1/deep.meta new file mode 100644 index 0000000..2c4e4d2 --- /dev/null +++ b/files/site/source/dir1/sub_dir1/deep1/deep.meta @@ -0,0 +1,6 @@ +${ var = 'GOOD' } +&{ base = 'text' } + +# SIMPLE SUBSTITUTION + +variable: ${var} diff --git a/files/site/source/dir1/sub_dir1/deep2/deep.meta b/files/site/source/dir1/sub_dir1/deep2/deep.meta new file mode 100644 index 0000000..ad3f829 --- /dev/null +++ b/files/site/source/dir1/sub_dir1/deep2/deep.meta @@ -0,0 +1,2 @@ +${ variable = 'GOOD' } +&{ body = 'variables' } diff --git a/files/site/source/dir1/sub_dir1/sub_dir.meta b/files/site/source/dir1/sub_dir1/sub_dir.meta new file mode 100644 index 0000000..c0fb1fe --- /dev/null +++ b/files/site/source/dir1/sub_dir1/sub_dir.meta @@ -0,0 +1,14 @@ +@{ + link.url = [ 'a.com', 'b.net', 'c.org'] + link.title = [ 'A Website', 'B Place', 'C Dest' ] +} + +&{ + link = 'bold' +} + +# LINKS + +This should create a group of bold links + +&{link} diff --git a/files/site/source/dir1/sub_dir2/sub_dir.meta b/files/site/source/dir1/sub_dir2/sub_dir.meta new file mode 100644 index 0000000..e64533a --- /dev/null +++ b/files/site/source/dir1/sub_dir2/sub_dir.meta @@ -0,0 +1,8 @@ +&{ + header = BLANK + footer = BLANK +} + +# BLANK + +This should have no header or footer diff --git a/files/site/source/dir1/sub_dir3/sub_dir.meta b/files/site/source/dir1/sub_dir3/sub_dir.meta new file mode 100644 index 0000000..c9ea33d --- /dev/null +++ b/files/site/source/dir1/sub_dir3/sub_dir.meta @@ -0,0 +1,11 @@ +${ + list_name = "A BIG LIST" +} + +@{ + list.item.items = ['item1','item2','item3','item4'] +} + +# HEADER LIST + +This should have a list in the header diff --git a/files/site/source/dir2/dir.meta b/files/site/source/dir2/dir.meta new file mode 100644 index 0000000..ca713e7 --- /dev/null +++ b/files/site/source/dir2/dir.meta @@ -0,0 +1,20 @@ +&{ + base = "text" +} + +# MARKDOWN + +## Header +This is a test for how various markdown elements translate + +### Small Header +- Lists +- With +- Items + +#### tiny header +*Fancy* **Text** __With__ _Adornments_ + +

    Inline HTML

    + +[a link](https://example.org) diff --git a/files/site/source/root.meta b/files/site/source/root.meta new file mode 100644 index 0000000..957a2d3 --- /dev/null +++ b/files/site/source/root.meta @@ -0,0 +1,2 @@ +# ROOT +This is to test that the default base works without any defintions. diff --git a/src/filetype/builder.rs b/src/builder.rs similarity index 76% rename from src/filetype/builder.rs rename to src/builder.rs index f9de49d..57d4322 100644 --- a/src/filetype/builder.rs +++ b/src/builder.rs @@ -10,8 +10,53 @@ use std::{ fs, path::{Path, PathBuf}, }; +use walkdir::WalkDir; + +pub fn build_site(opts: &Options) -> Result<()> { + log!(opts, "finding files", 2); + let files: Vec = WalkDir::new(&opts.source) + .into_iter() + .filter_map(|file| { + if file.as_ref().ok()?.file_type().is_dir() { + // need to create directories in build dir + let path = file.unwrap().into_path(); + let path = path.strip_prefix(&opts.source).ok()?; + let path = opts.build.join(path); + log!(opts, format!("\tcreating dir: {}", path.display()), 3); + std::fs::create_dir(path).ok()?; + // don't need them for any further operations so we filter them out + None + } else { + if let Ok(file) = file { + log!(opts, format!("\tadding file: {}", file.path().display()), 3); + Some(file.into_path()) + } else { + None + } + } + }) + .collect(); + + log!(opts, "building files", 2); + for file in files.iter() { + match build_metafile(file, &opts) { + Ok(_) => continue, + Err(e) => { + if opts.force { + // print a line to stderr about failure but continue with other files + eprintln!("{}: {}", file.display(), e); + continue; + } else { + return Err(e.wrap_err(eyre!("{}:", file.display()))); + } + } + } + } -pub fn build_metafile(path: &Path, opts: &Options) -> Result<()> { + Ok(()) +} + +fn build_metafile(path: &Path, opts: &Options) -> Result<()> { log!(opts, format!("\t{}", path.display()), 1); let file = fs::read_to_string(path).wrap_err_with(|| eyre!("failed to read: {}\n", path.display()))?; @@ -45,7 +90,7 @@ pub fn build_metafile(path: &Path, opts: &Options) -> Result<()> { Ok(()) } -pub fn metafile_to_string(file: &MetaFile, opts: &Options, name: Option<&str>) -> Result { +fn metafile_to_string(file: &MetaFile, opts: &Options, name: Option<&str>) -> Result { let mut output = String::default(); let mut arrays = false; @@ -234,3 +279,33 @@ fn get_max_size(map: &HashMap<&str, &[&str]>) -> usize { } max } + +#[cfg(test)] +mod tests { + use super::*; + fn build_options() -> Result { + let dir = PathBuf::from("files/site").canonicalize()?; + + let opts = Options { + root: dir.clone(), + source: dir.join("source"), + build: dir.join("build"), + pattern: dir.join("pattern"), + verbose: 0, + quiet: false, + force: false, + undefined: false, + clean: true, + }; + + Ok(opts) + } + + #[test] + fn test_find_dest() -> Result<()> { + let opts = build_options()?; + let path = opts.source.join("dir1/dir.meta"); + assert_eq!(find_dest(&path, &opts)?, opts.build.join("dir1/dir.html")); + Ok(()) + } +} diff --git a/src/filetype.rs b/src/filetype.rs deleted file mode 100644 index 06f0ef0..0000000 --- a/src/filetype.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod builder; -mod metafile; - -pub use builder::*; -pub use metafile::*; diff --git a/src/lib.rs b/src/lib.rs index a4fed10..3bb3fa3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,13 +2,12 @@ extern crate pest; #[macro_use] extern crate pest_derive; -mod filetype; +mod builder; +mod metafile; mod options; mod parser; -pub use filetype::*; +pub use builder::*; +pub use metafile::*; pub use options::*; pub use parser::*; - -#[cfg(test)] -mod tests; diff --git a/src/main.rs b/src/main.rs index a76ea7e..c156dca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,52 +1,10 @@ -use color_eyre::{eyre::eyre, Result}; -use metaforge::{build_metafile, log, parse_opts}; -use std::path::PathBuf; -use walkdir::WalkDir; +use color_eyre::Result; +use metaforge::{build_site, parse_opts}; fn main() -> Result<()> { color_eyre::install()?; let opts = parse_opts()?; - log!(opts, "finding files", 2); - let files: Vec = WalkDir::new(&opts.source) - .into_iter() - .filter_map(|file| { - if file.as_ref().ok()?.file_type().is_dir() { - // need to create directories in build dir - let path = file.unwrap().into_path(); - let path = path.strip_prefix(&opts.source).ok()?; - let path = opts.build.join(path); - log!(opts, format!("\tcreating dir: {}", path.display()), 3); - std::fs::create_dir(path).ok()?; - // don't need them for any further operations so we filter them out - None - } else { - if let Ok(file) = file { - log!(opts, format!("\tadding file: {}", file.path().display()), 3); - Some(file.into_path()) - } else { - None - } - } - }) - .collect(); - - log!(opts, "building files", 2); - for file in files.iter() { - match build_metafile(file, &opts) { - Ok(_) => continue, - Err(e) => { - if opts.force { - // print a line to stderr about failure but continue with other files - eprintln!("{}: {}", file.display(), e); - continue; - } else { - return Err(e.wrap_err(eyre!("{}:", file.display()))); - } - } - } - } - - Ok(()) + build_site(&opts) } diff --git a/src/parser/meta.pest b/src/meta.pest similarity index 100% rename from src/parser/meta.pest rename to src/meta.pest diff --git a/src/filetype/metafile.rs b/src/metafile.rs similarity index 100% rename from src/filetype/metafile.rs rename to src/metafile.rs diff --git a/src/options.rs b/src/options.rs index 18afa9c..7cbaf34 100644 --- a/src/options.rs +++ b/src/options.rs @@ -27,12 +27,15 @@ pub struct Opts { /// Minimal output #[arg(short, long, default_value_t = false)] quiet: bool, - /// Don't stop if a single file fails [false] + /// Don't stop on file failure [FALSE] #[arg(long, default_value_t = false)] force: bool, - /// Stop on undefined variables, patterns, and arrays [false] + /// Stop on undefined variables, patterns, and arrays [FALSE] #[arg(long, default_value_t = false)] undefined: bool, + /// Clean build directory before building site [FALSE] + #[arg(long, default_value_t = false)] + clean: bool, } #[derive(Debug, Clone, Default)] @@ -45,6 +48,7 @@ pub struct Options { pub quiet: bool, pub force: bool, pub undefined: bool, + pub clean: bool, } impl Options { @@ -58,6 +62,7 @@ impl Options { quiet: false, force: false, undefined: false, + clean: false, } } } @@ -65,7 +70,7 @@ impl Options { #[macro_export] macro_rules! log { ($opts:ident, $string:expr, $level:expr) => { - if $opts.verbose >= $level { + if $opts.verbose >= $level && !$opts.quiet { println!("{}", $string); } }; @@ -79,6 +84,7 @@ pub fn parse_opts() -> Result { options.quiet = opts.quiet; options.force = opts.force; options.undefined = opts.undefined; + options.clean = opts.clean; if let Some(root) = opts.root.as_deref() { options.root = PathBuf::from(root).canonicalize()?; diff --git a/src/parser.rs b/src/parser.rs index 4f42021..11d5d19 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,3 +1,226 @@ -mod parse; +use crate::{source, MetaFile, Source, Substitution}; +use color_eyre::{eyre::WrapErr, Result}; +use pest::{ + iterators::{Pair, Pairs}, + Parser, +}; +use std::collections::HashMap; -pub use parse::*; +#[derive(Parser)] +#[grammar = "meta.pest"] +pub struct MetaParser; + +pub fn parse_file(file: &str) -> Result { + let meta_source = MetaParser::parse(Rule::file, file) + .wrap_err("parser error")? + .next() + .unwrap(); + + Ok(parse_pair(meta_source)) +} + +fn parse_pair(pair: Pair) -> MetaFile { + let mut meta_file = MetaFile::new(); + + if Rule::file == pair.as_rule() { + for pair in pair.into_inner() { + match pair.as_rule() { + Rule::source => meta_file.source = parse_source(pair.into_inner()), + Rule::var_def => meta_file.variables = parse_defs(pair.into_inner()), + Rule::arr_def => meta_file.arrays = parse_array_defs(pair.into_inner()), + Rule::pat_def => meta_file.patterns = parse_defs(pair.into_inner()), + // do nothing on end of file + Rule::EOI => continue, + // anything else is either hidden or children of previous nodes and will be dealt with + // in respective parse functions + _ => unreachable!(), + } + } + } + + meta_file +} + +fn parse_defs(pairs: Pairs) -> HashMap<&'_ str, &'_ str> { + let mut map = HashMap::new(); + for pair in pairs { + if Rule::assign == pair.as_rule() { + let (key, val) = parse_assign(pair); + map.insert(key, val); + } + } + map +} + +fn parse_array_defs(pairs: Pairs) -> HashMap<&str, Vec<&str>> { + let mut map = HashMap::new(); + for pair in pairs { + if Rule::assign == pair.as_rule() { + let (key, val) = parse_assign_array(pair); + map.insert(key, val); + } + } + map +} + +fn parse_source(pairs: Pairs) -> Vec { + let mut vec = Vec::new(); + for pair in pairs { + match pair.as_rule() { + Rule::var_sub => vec.push(source!(var(parse_sub(pair)))), + Rule::arr_sub => vec.push(source!(arr(parse_sub(pair)))), + Rule::pat_sub => vec.push(source!(pat(parse_sub(pair)))), + Rule::char_seq => vec.push(source!(pair.as_str())), + // anything that isn't a substitution is a char_seq inside source + _ => unreachable!(), + } + } + + vec +} + +fn parse_sub(pair: Pair) -> &'_ str { + match pair.as_rule() { + Rule::var_sub | Rule::arr_sub | Rule::pat_sub => { + let str = pair.as_str(); + // return the value as the inner string for substitution + // all substitutions have the format of + // *{ ... } + // we return everything except: + // first two chars (sigil and preceding brace) + // last char (trailing brace) + &str[2..str.len() - 1] + } + // this function only gets called to parse substituiton patterns + // so anything else should never be called + _ => unreachable!(), + } +} + +fn parse_assign(pair: Pair) -> (&'_ str, &'_ str) { + let mut key = ""; + let mut val = ""; + + for pair in pair.into_inner() { + if Rule::key == pair.as_rule() { + key = pair.as_str(); + } + if Rule::value == pair.as_rule() { + let tmp = pair.as_str(); + // blank and default shoud be handled by whoever is getting the value + if tmp == "BLANK" || tmp == "DEFAULT" { + return (key, tmp); + } + // remove surrounding quotes from values by returning + // everything except first and last characters + // a string is defined as " ... " or ' ... ' + // so it's safe to strip these characters + val = &tmp[1..tmp.len() - 1]; + } + } + + (key, val) +} + +fn parse_assign_array(pair: Pair) -> (&str, Vec<&str>) { + let mut key = ""; + let mut val = Vec::default(); + + for pair in pair.into_inner() { + if Rule::key == pair.as_rule() { + key = pair.as_str(); + } + if Rule::value == pair.as_rule() { + val = parse_array(pair.into_inner()); + } + } + + (key, val) +} + +fn parse_array(pairs: Pairs) -> Vec<&str> { + let mut vec: Vec<&str> = Vec::default(); + + for pair in pairs { + if Rule::string == pair.as_rule() { + let tmp = pair.as_str(); + // remove surrounding quotes from values + // see parse_assign() for reasoning + let val = &tmp[1..tmp.len() - 1]; + vec.push(val); + } + } + + vec +} + +#[cfg(test)] +mod tests { + use super::*; + + macro_rules! test_str ( + ($s: expr) => { + let str = $s; + parse_file(str).unwrap(); + }; + ); + + #[test] + fn no_spaces_in_def() { + test_str!(r#"${v='v'}@{a=['a']}&{p='p'}"#); + } + + #[test] + fn just_source_string() { + test_str!(r#"This is just a &{source} snippet"#); + } + + #[test] + fn one_line() { + test_str!( + r#"${variable = 'var' } @{array = ['array']} &{ pattern = "pattern"} And some extra text"# + ); + } + + #[test] + #[should_panic] + fn key_with_spaces() { + test_str!(r#"${ key with spaces = "value" }"#); + } + + #[test] + #[should_panic] + fn value_missing_quote() { + test_str!(r#"${ key = "value missing quote }"#); + } + + #[test] + #[should_panic] + fn mixed_quotes() { + test_str!(r#"${ key = "value mixing quotes' }"#); + } + + #[test] + #[should_panic] + fn spaces_in_substitution() { + test_str!(r#"This ${variable is not allowed}"#); + } + + #[test] + #[should_panic] + fn missing_closing_brace() { + test_str!(r#"${ key = "value" "#); + } + + #[test] + #[should_panic] + fn map_in_source() { + test_str!(r#"This map: ${ is = "invalid" }"#); + } + + #[test] + #[should_panic] + fn map_source_map() { + test_str!(r#"${var='v'} Some text @{array = ['a']}"#); + } +} diff --git a/src/parser/parse.rs b/src/parser/parse.rs deleted file mode 100644 index 82c9609..0000000 --- a/src/parser/parse.rs +++ /dev/null @@ -1,155 +0,0 @@ -use crate::{source, MetaFile, Source, Substitution}; -use color_eyre::{eyre::WrapErr, Result}; -use pest::{ - iterators::{Pair, Pairs}, - Parser, -}; -use std::collections::HashMap; - -#[derive(Parser)] -#[grammar = "parser/meta.pest"] -pub struct MetaParser; - -pub fn parse_file(file: &str) -> Result { - let meta_source = MetaParser::parse(Rule::file, file) - .wrap_err("parser error")? - .next() - .unwrap(); - - Ok(parse_pair(meta_source)) -} - -fn parse_pair(pair: Pair) -> MetaFile { - let mut meta_file = MetaFile::new(); - - if Rule::file == pair.as_rule() { - for pair in pair.into_inner() { - match pair.as_rule() { - Rule::source => meta_file.source = parse_source(pair.into_inner()), - Rule::var_def => meta_file.variables = parse_defs(pair.into_inner()), - Rule::arr_def => meta_file.arrays = parse_array_defs(pair.into_inner()), - Rule::pat_def => meta_file.patterns = parse_defs(pair.into_inner()), - // do nothing on end of file - Rule::EOI => continue, - // anything else is either hidden or children of previous nodes and will be dealt with - // in respective parse functions - _ => unreachable!(), - } - } - } - - meta_file -} - -fn parse_defs(pairs: Pairs) -> HashMap<&'_ str, &'_ str> { - let mut map = HashMap::new(); - for pair in pairs { - if Rule::assign == pair.as_rule() { - let (key, val) = parse_assign(pair); - map.insert(key, val); - } - } - map -} - -fn parse_array_defs(pairs: Pairs) -> HashMap<&str, Vec<&str>> { - let mut map = HashMap::new(); - for pair in pairs { - if Rule::assign == pair.as_rule() { - let (key, val) = parse_assign_array(pair); - map.insert(key, val); - } - } - map -} - -fn parse_source(pairs: Pairs) -> Vec { - let mut vec = Vec::new(); - for pair in pairs { - match pair.as_rule() { - Rule::var_sub => vec.push(source!(var(parse_sub(pair)))), - Rule::arr_sub => vec.push(source!(arr(parse_sub(pair)))), - Rule::pat_sub => vec.push(source!(pat(parse_sub(pair)))), - Rule::char_seq => vec.push(source!(pair.as_str())), - // anything that isn't a substitution is a char_seq inside source - _ => unreachable!(), - } - } - - vec -} - -fn parse_sub(pair: Pair) -> &'_ str { - match pair.as_rule() { - Rule::var_sub | Rule::arr_sub | Rule::pat_sub => { - let str = pair.as_str(); - // return the value as the inner string for substitution - // all substitutions have the format of - // *{ ... } - // we return everything except: - // first two chars (sigil and preceding brace) - // last char (trailing brace) - &str[2..str.len() - 1] - } - // this function only gets called to parse substituiton patterns - // so anything else should never be called - _ => unreachable!(), - } -} - -fn parse_assign(pair: Pair) -> (&'_ str, &'_ str) { - let mut key = ""; - let mut val = ""; - - for pair in pair.into_inner() { - if Rule::key == pair.as_rule() { - key = pair.as_str(); - } - if Rule::value == pair.as_rule() { - let tmp = pair.as_str(); - // blank and default shoud be handled by whoever is getting the value - if tmp == "BLANK" || tmp == "DEFAULT" { - return (key, tmp); - } - // remove surrounding quotes from values by returning - // everything except first and last characters - // a string is defined as " ... " or ' ... ' - // so it's safe to strip these characters - val = &tmp[1..tmp.len() - 1]; - } - } - - (key, val) -} - -fn parse_assign_array(pair: Pair) -> (&str, Vec<&str>) { - let mut key = ""; - let mut val = Vec::default(); - - for pair in pair.into_inner() { - if Rule::key == pair.as_rule() { - key = pair.as_str(); - } - if Rule::value == pair.as_rule() { - val = parse_array(pair.into_inner()); - } - } - - (key, val) -} - -fn parse_array(pairs: Pairs) -> Vec<&str> { - let mut vec: Vec<&str> = Vec::default(); - - for pair in pairs { - if Rule::string == pair.as_rule() { - let tmp = pair.as_str(); - // remove surrounding quotes from values - // see parse_assign() for reasoning - let val = &tmp[1..tmp.len() - 1]; - vec.push(val); - } - } - - vec -} diff --git a/src/tests.rs b/src/tests.rs deleted file mode 100644 index 2dfbe1d..0000000 --- a/src/tests.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod test_metafile; -mod test_parser; diff --git a/src/tests/test_metafile.rs b/src/tests/test_metafile.rs deleted file mode 100644 index d9a4be6..0000000 --- a/src/tests/test_metafile.rs +++ /dev/null @@ -1,77 +0,0 @@ -use crate::{parse_file, source, Source, Substitution}; -use color_eyre::Result; -use pretty_assertions::assert_eq; - -static SOURCE: &str = include_str!("../../tests/files/test_source.meta"); -static PATTERN: &str = include_str!("../../test_site/pattern/test/pattern.meta"); - -#[test] -fn test_metafile_gets() -> Result<()> { - let source = parse_file(SOURCE)?; - - assert_eq!(source.get_var("var").unwrap(), "GOOD"); - assert_eq!(source.get_var("single_quotes").unwrap(), "GOOD"); - assert_eq!(source.get_var("blank").unwrap(), "BLANK"); - assert_eq!(source.get_var("not_defined"), None); - - assert_eq!(source.get_arr("sub.array").unwrap(), ["GOOD", "GOOD"]); - assert_eq!(source.get_arr("arr").unwrap(), ["GOOD", "GOOD", "GOOD"]); - assert_eq!( - source.get_arr("with_spaces").unwrap(), - ["GOOD", "GOOD", "GOOD"] - ); - assert_eq!(source.get_arr("not_defined"), None); - - assert_eq!(source.get_pat("test").unwrap(), "pattern"); - assert_eq!(source.get_pat("test.sub_pat").unwrap(), "DEFAULT"); - assert_eq!(source.get_pat("blank_pat").unwrap(), "BLANK"); - assert_eq!(source.get_pat("not_defined"), None); - - Ok(()) -} - -#[test] -fn parse_meta_file() -> Result<()> { - let source = parse_file(SOURCE)?; - - assert_eq!(source.variables.get("var").unwrap(), &"GOOD"); - assert_eq!(source.variables.get("blank").unwrap(), &"BLANK"); - assert_eq!(source.variables.get("not_here"), None); - - assert_eq!( - source.arrays.get("sub.array").unwrap(), - &vec!["GOOD", "GOOD"] - ); - assert_eq!( - source.arrays.get("arr").unwrap(), - &vec!["GOOD", "GOOD", "GOOD"] - ); - assert_eq!( - source.arrays.get("with_spaces").unwrap(), - &vec!["GOOD", "GOOD", "GOOD"] - ); - assert_eq!(source.arrays.get("not_defined"), None); - - assert_eq!(source.patterns.get("test").unwrap(), &"pattern"); - assert_eq!(source.patterns.get("test.sub_pat").unwrap(), &"DEFAULT"); - assert_eq!(source.patterns.get("blank_pat").unwrap(), &"BLANK"); - assert_eq!(source.patterns.get("not_defined"), None); - - Ok(()) -} - -#[test] -fn parse_pattern_file() -> Result<()> { - let mut pattern_src = parse_file(PATTERN)?.source.into_iter(); - - pattern_src.next(); - assert_eq!(pattern_src.next().unwrap(), source!(var("variable"))); - pattern_src.next(); - assert_eq!(pattern_src.next().unwrap(), source!(arr("array"))); - pattern_src.next(); - assert_eq!(pattern_src.next().unwrap(), source!(pat("test.blank"))); - pattern_src.next(); - assert_eq!(pattern_src.next(), None); - - Ok(()) -} diff --git a/src/tests/test_parser.rs b/src/tests/test_parser.rs deleted file mode 100644 index 43a4285..0000000 --- a/src/tests/test_parser.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::parse_file; - -macro_rules! test_str ( - ($s: expr) => { - let str = $s; - parse_file(str).unwrap(); - }; -); - -#[test] -fn no_spaces_def() { - test_str!(r#"${v='v'}@{a=['a']}&{p='p'}"#); -} - -#[test] -fn just_source() { - test_str!(r#"This is just a &{source} snippet"#); -} - -#[test] -#[should_panic] -fn key_with_spaces() { - test_str!(r#"${ key with spaces = "value" }"#); -} - -#[test] -#[should_panic] -fn value_missing_quote() { - test_str!(r#"${ key = "value missing quote }"#); -} - -#[test] -#[should_panic] -fn mixed_quotes() { - test_str!(r#"${ key = "value mixing quotes' }"#); -} - -#[test] -#[should_panic] -fn spaces_in_substitution() { - test_str!(r#"This ${variable is not allowed}"#); -} - -#[test] -#[should_panic] -fn missing_closing_brace() { - test_str!(r#"${ key = "value" "#); -} - -#[test] -#[should_panic] -fn map_in_source() { - test_str!(r#"This map: ${ is = "invalid" }"#); -} diff --git a/test_site/pattern/test/array.meta b/test_site/pattern/test/array.meta deleted file mode 100644 index c530977..0000000 --- a/test_site/pattern/test/array.meta +++ /dev/null @@ -1 +0,0 @@ -

    @{arr}

    diff --git a/test_site/pattern/test/blank/default.meta b/test_site/pattern/test/blank/default.meta deleted file mode 100644 index 7b3a785..0000000 --- a/test_site/pattern/test/blank/default.meta +++ /dev/null @@ -1 +0,0 @@ -BAD diff --git a/test_site/pattern/test/default/default.meta b/test_site/pattern/test/default/default.meta deleted file mode 100644 index ada2226..0000000 --- a/test_site/pattern/test/default/default.meta +++ /dev/null @@ -1 +0,0 @@ -

    DEFAULT

    diff --git a/test_site/pattern/test/new/default.meta b/test_site/pattern/test/new/default.meta deleted file mode 100644 index 7b3a785..0000000 --- a/test_site/pattern/test/new/default.meta +++ /dev/null @@ -1 +0,0 @@ -BAD diff --git a/test_site/pattern/test/new/new.meta b/test_site/pattern/test/new/new.meta deleted file mode 100644 index f49b816..0000000 --- a/test_site/pattern/test/new/new.meta +++ /dev/null @@ -1 +0,0 @@ -GOOD diff --git a/test_site/pattern/test/overwrite/default.meta b/test_site/pattern/test/overwrite/default.meta deleted file mode 100644 index 7b3a785..0000000 --- a/test_site/pattern/test/overwrite/default.meta +++ /dev/null @@ -1 +0,0 @@ -BAD diff --git a/test_site/pattern/test/overwrite/overwrite.meta b/test_site/pattern/test/overwrite/overwrite.meta deleted file mode 100644 index f49b816..0000000 --- a/test_site/pattern/test/overwrite/overwrite.meta +++ /dev/null @@ -1 +0,0 @@ -GOOD diff --git a/test_site/pattern/test/parent/default.meta b/test_site/pattern/test/parent/default.meta deleted file mode 100644 index 7b3a785..0000000 --- a/test_site/pattern/test/parent/default.meta +++ /dev/null @@ -1 +0,0 @@ -BAD diff --git a/test_site/pattern/test/parent/parent.meta b/test_site/pattern/test/parent/parent.meta deleted file mode 100644 index f49b816..0000000 --- a/test_site/pattern/test/parent/parent.meta +++ /dev/null @@ -1 +0,0 @@ -GOOD diff --git a/test_site/pattern/test/pattern.meta b/test_site/pattern/test/pattern.meta deleted file mode 100644 index 7b54269..0000000 --- a/test_site/pattern/test/pattern.meta +++ /dev/null @@ -1,7 +0,0 @@ -

    This is a test

    -

    ${variable}

    -
      - @{array} -
    Other stuff diff --git a/test_site/pattern/test/sub_pat/default.meta b/test_site/pattern/test/sub_pat/default.meta deleted file mode 100644 index f49b816..0000000 --- a/test_site/pattern/test/sub_pat/default.meta +++ /dev/null @@ -1 +0,0 @@ -GOOD diff --git a/test_site/pattern/test/sub_pat/sub_pattern.meta b/test_site/pattern/test/sub_pat/sub_pattern.meta deleted file mode 100644 index 5377fce..0000000 --- a/test_site/pattern/test/sub_pat/sub_pattern.meta +++ /dev/null @@ -1 +0,0 @@ -

    SUBPATTERN

    diff --git a/test_site/source/expand.meta b/test_site/source/expand.meta deleted file mode 100644 index 0d3754d..0000000 --- a/test_site/source/expand.meta +++ /dev/null @@ -1,37 +0,0 @@ -${ - var1 = 'GOOD' - var2 = BLANK - var3 = 'GOOD GOOD' -} - -@{ - arr1 = [ 'GOOD' ] - arr2 = [] - test.arr = [ 'GOOD', 'GOOD GOOD' ] -} - -&{ - test = 'array' - test.sub_pat = 'sub_pattern' - test.blank = BLANK - test.default = DEFAULT -} - - -TESTS: - -var1 [VALUE]: ${var1} -var2 [BLANK]: ${var2} -var3 [VAL WITH SPACES]: ${var3} - -arr1 [VALUE]: @{arr1} -arr2 [BLANK]: @{arr2} - -Pattern subs: - -test [WITH ARRAY]: &{test} -test.sub_pat: &{test.sub_pat} -test.default: &{test.default} -test.blank: &{test.blank} - -This comment should not be rendered: -{arr1} diff --git a/test_site/source/expand_html.meta b/test_site/source/expand_html.meta deleted file mode 100644 index 2643a44..0000000 --- a/test_site/source/expand_html.meta +++ /dev/null @@ -1,19 +0,0 @@ -${ - var = 'GOOD' -} - -@{ - test.arr = ["GOOD", 'GOOD GOOD'] -} - -&{ - test = 'array' -} - -## This is a test - -

    Inline html

    - -variable: ${var} - -pattern: &{test} diff --git a/test_site/source/sub_dir/deep/deep.meta b/test_site/source/sub_dir/deep/deep.meta deleted file mode 100644 index cef3adb..0000000 --- a/test_site/source/sub_dir/deep/deep.meta +++ /dev/null @@ -1,14 +0,0 @@ -${ - variable = 'GOOD' -} - -@{ - test.pattern.array = ["GOOD"] -} - -&{ - test = 'pattern' - test.blank = BLANK -} - -&{test} diff --git a/test_site/source/sub_dir/sub_dir.meta b/test_site/source/sub_dir/sub_dir.meta deleted file mode 100644 index 0cbb769..0000000 --- a/test_site/source/sub_dir/sub_dir.meta +++ /dev/null @@ -1,5 +0,0 @@ -${ - var = 'variable' -} - -This is a simple filler file with a single variable: ${var} diff --git a/tests/files/expanded b/tests/files/expanded deleted file mode 100644 index bc2fff8..0000000 --- a/tests/files/expanded +++ /dev/null @@ -1,27 +0,0 @@ -TESTS: - -var1 [VALUE]: -GOOD -var2 [BLANK]: - -var3 [VAL WITH SPACES]: -GOOD GOOD -arr1 [VALUE]: -GOOD -arr2 [BLANK]: - -Pattern subs: - -test [WITH ARRAY]: -

    -GOOD -

    -GOOD GOOD -

    -test.sub_pat: -

    SUBPATTERN

    -test.default: -

    DEFAULT

    -test.blank: - -This comment should not be rendered: diff --git a/tests/files/test_source.meta b/tests/files/test_source.meta deleted file mode 100644 index 68aad64..0000000 --- a/tests/files/test_source.meta +++ /dev/null @@ -1,30 +0,0 @@ -${ - var = "GOOD" - single_quotes = 'GOOD' - blank = BLANK -} - -@{ - sub.array = ["GOOD","GOOD"] - arr = ["GOOD",'GOOD',"GOOD"] - with_spaces = [ "GOOD", "GOOD" , "GOOD" ] -} - -&{ - test = "pattern" - test.sub_pat = DEFAULT - blank_pat = BLANK -} - -variables ${var} - -patterns &{pat} - -subpatterns &{pat.sub_pat} - --{ and inline comments } - -arrays @{arr} -nested_array: @{sub.array} - -and all the other symbols: !@#$%^&*(){}_+ diff --git a/tests/metafile_builder.rs b/tests/metafile_builder.rs deleted file mode 100644 index e83e0c7..0000000 --- a/tests/metafile_builder.rs +++ /dev/null @@ -1,54 +0,0 @@ -use color_eyre::Result; -use metaforge::*; -use pretty_assertions::assert_eq; -use std::{fs, path::PathBuf}; - -static PRE_EXPAND: &str = include_str!("../test_site/source/expand.meta"); -static POST_EXPAND: &str = include_str!("files/expanded"); - -#[test] -fn test_metafile_to_str() -> Result<()> { - let metafile = parse_file(PRE_EXPAND)?; - let dirs = build_options()?; - - let file = metafile_to_string(&metafile, &dirs, None)?; - - // requires newline to match with files ending newline - assert_eq!(file + "\n", POST_EXPAND); - - Ok(()) -} - -#[test] -fn test_metafile_builder() -> Result<()> { - let dirs = build_options()?; - let path = PathBuf::from("test_site/source/expand_html.meta"); - build_metafile(&path, &dirs)?; - let source = fs::read_to_string("test_site/build/expand_html.html")?; - let html = fs::read_to_string("tests/files/expanded_html")?; - - assert_eq!(source, html); - - Ok(()) -} - -fn build_options() -> Result { - let dir = PathBuf::from("./test_site").canonicalize()?; - - let opts = Options { - root: dir.clone(), - source: dir.join("source"), - build: dir.join("build"), - pattern: dir.join("pattern"), - verbose: 0, - quiet: false, - force: false, - undefined: false, - }; - - if !opts.build.exists() { - fs::create_dir(&opts.build)?; - } - - Ok(opts) -} -- 2.44.2