]> git.huck.website - metaforge.git/commitdiff
release: v0.1.3
authorHuck Boles <huck@huck.website>
Sat, 3 Jun 2023 01:09:15 +0000 (20:09 -0500)
committerHuck Boles <huck@huck.website>
Sat, 3 Jun 2023 01:09:15 +0000 (20:09 -0500)
42 files changed:
.gitignore
Cargo.lock
Cargo.toml
README.md
benches/parallel.rs
docs/pattern/base/default.meta [moved from files/README/pattern/base/default.meta with 100% similarity]
docs/pattern/body/default.meta [moved from files/README/pattern/body/default.meta with 100% similarity]
docs/pattern/foot/default.meta [moved from files/README/pattern/foot/default.meta with 100% similarity]
docs/pattern/head/default.meta [moved from files/README/pattern/head/default.meta with 100% similarity]
docs/source/default.meta [moved from files/README/source/default.meta with 72% similarity]
docs/source/docs/default.meta [moved from files/README/source/docs/default.meta with 65% similarity]
docs/source/docs/definitions.meta [moved from files/README/source/docs/definitions.meta with 97% similarity]
docs/source/docs/expansions.meta [moved from files/README/source/docs/expansions.meta with 77% similarity]
docs/source/docs/flags.meta [moved from files/README/source/docs/flags.meta with 93% similarity]
docs/source/docs/header.meta [moved from files/README/source/docs/header.meta with 88% similarity]
docs/source/docs/structure.meta [moved from files/README/source/docs/structure.meta with 99% similarity]
docs/source/docs/syntax.meta [moved from files/README/source/docs/syntax.meta with 93% similarity]
docs/source/index.meta [moved from files/README/source/index.meta with 55% similarity]
files/test_site/pattern/test/expand_source.meta [new file with mode: 0644]
files/test_site/pattern/test/pandoc.meta [new file with mode: 0644]
files/test_site/source/unit_tests/expand/source.meta [new file with mode: 0644]
files/test_site/source/unit_tests/expand/source_expand.meta [new file with mode: 0644]
files/test_site/source/unit_tests/expand/spaces.meta [new file with mode: 0644]
files/test_site/source/unit_tests/header/copy.meta [new file with mode: 0644]
files/test_site/source/unit_tests/header/expandoc.meta [new file with mode: 0644]
src/lib.rs
src/metafile.rs
src/metafile/dir/node.rs
src/metafile/file.rs
src/metafile/file/arrays.rs
src/metafile/file/patterns.rs
src/metafile/file/source.rs
src/metafile/file/variables.rs
src/metafile/header.rs
src/metafile/scope.rs
src/options.rs
src/parser.rs
src/parser/array.rs
src/parser/def_block.rs
src/parser/meta.pest
src/tests.rs
tests/readme.rs

index d8450c1d3a8cf8caa80b6cb72fdccac169ba133d..16e17a4689b4036ed47d0ff15256b4d2829780d2 100644 (file)
@@ -1,5 +1,5 @@
 /target
 files/test_site/build
-files/README/build
+docs/build
 files/bench_site/build
 bacon.toml
index f9c80f59d71c4d9fd5b6f4f223c680fe5290daf2..1f37171073fa2cf03a4a70f647c22801f4a28f7b 100644 (file)
@@ -2,6 +2,15 @@
 # It is not intended for manual editing.
 version = 3
 
+[[package]]
+name = "aho-corasick"
+version = "0.7.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "anes"
 version = "0.1.6"
@@ -154,9 +163,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.3.0"
+version = "4.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc"
+checksum = "b4ed2379f8603fa2b7509891660e802b88c70a79a6427a70abb5968054de2c28"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -165,9 +174,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.3.0"
+version = "4.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990"
+checksum = "72394f3339a76daf211e57d4bcb374410f3965dcc606dd0e03738c7888766980"
 dependencies = [
  "anstream",
  "anstyle",
@@ -178,14 +187,14 @@ dependencies = [
 
 [[package]]
 name = "clap_derive"
-version = "4.3.0"
+version = "4.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "191d9573962933b4027f932c600cd252ce27a8ad5979418fe78e43c07996f27b"
+checksum = "59e9ef9a08ee1c0e1f2e162121665ac45ac3783b0f897db7244ae75ad9a8f65b"
 dependencies = [
  "heck",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.18",
 ]
 
 [[package]]
@@ -209,6 +218,12 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
 
+[[package]]
+name = "convert_case"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
+
 [[package]]
 name = "cpufeatures"
 version = "0.2.7"
@@ -307,6 +322,30 @@ dependencies = [
  "typenum",
 ]
 
+[[package]]
+name = "css-minify"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "874c6e2d19f8d4a285083b11a3241bfbe01ac3ed85f26e1e6b34888d960552bd"
+dependencies = [
+ "derive_more",
+ "indexmap",
+ "nom",
+]
+
+[[package]]
+name = "derive_more"
+version = "0.99.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
+dependencies = [
+ "convert_case",
+ "proc-macro2",
+ "quote",
+ "rustc_version",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "digest"
 version = "0.10.7"
@@ -498,12 +537,15 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
 
 [[package]]
 name = "log"
-version = "0.4.17"
+version = "0.4.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
-dependencies = [
- "cfg-if",
-]
+checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de"
+
+[[package]]
+name = "memchr"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 
 [[package]]
 name = "memoffset"
@@ -516,11 +558,12 @@ dependencies = [
 
 [[package]]
 name = "metaforge"
-version = "0.1.1"
+version = "0.1.3"
 dependencies = [
- "clap 4.3.0",
+ "clap 4.3.1",
  "criterion",
  "eyre",
+ "minify-html",
  "pandoc",
  "pest",
  "pest_derive",
@@ -528,6 +571,46 @@ dependencies = [
  "thiserror",
 ]
 
+[[package]]
+name = "minify-html"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc4d9147754a49e80557df835eb59e743eab1bf75410a134f55dc4b9dbb692ad"
+dependencies = [
+ "aho-corasick",
+ "css-minify",
+ "lazy_static",
+ "memchr",
+ "minify-js",
+ "rustc-hash",
+]
+
+[[package]]
+name = "minify-js"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c300f90ba1138b5c5daf5d9441dc9bdc67b808aac22cf638362a2647bc213be4"
+dependencies = [
+ "lazy_static",
+ "parse-js",
+]
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
 [[package]]
 name = "num-traits"
 version = "0.2.15"
@@ -549,9 +632,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.17.1"
+version = "1.17.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
+checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b"
 
 [[package]]
 name = "oorandom"
@@ -574,6 +657,17 @@ dependencies = [
  "itertools 0.8.2",
 ]
 
+[[package]]
+name = "parse-js"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30534759e6ad87aa144c396544747e1c25b1020bd133356fd758c8facec764e5"
+dependencies = [
+ "aho-corasick",
+ "lazy_static",
+ "memchr",
+]
+
 [[package]]
 name = "pest"
 version = "2.6.0"
@@ -604,7 +698,7 @@ dependencies = [
  "pest_meta",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.18",
 ]
 
 [[package]]
@@ -701,6 +795,21 @@ version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
 
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+dependencies = [
+ "semver",
+]
+
 [[package]]
 name = "rustix"
 version = "0.37.19"
@@ -736,6 +845,12 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
+[[package]]
+name = "semver"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
+
 [[package]]
 name = "serde"
 version = "1.0.163"
@@ -753,7 +868,7 @@ checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.18",
 ]
 
 [[package]]
@@ -784,6 +899,17 @@ version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
 
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
 [[package]]
 name = "syn"
 version = "2.0.18"
@@ -818,7 +944,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.18",
 ]
 
 [[package]]
@@ -892,7 +1018,7 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.18",
  "wasm-bindgen-shared",
 ]
 
@@ -914,7 +1040,7 @@ checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.18",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
index a515fcc81f801cc4411ed6d9a99ccb5918e78397..30560cf5485aedb911091c35b1496ecf1ebd3ed4 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "metaforge"
-version = "0.1.2"
+version = "0.1.3"
 edition = "2021"
 
 [dependencies]
@@ -11,6 +11,7 @@ eyre = "0.6"
 pest = "2"
 pest_derive = "2"
 rayon = "1.7"
+minify-html = "0.11"
 
 [dev-dependencies]
 criterion = "0.4"
index 4614ad0b27226f2ead2beb1c7622b26af21c6430..6e2e3b8c31c439ac00c3352e69bfd5a0473c5b0d 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# metaforge - v0.1.2
+# metaforge - v0.1.3
 
 a pattern driven static site generator for extensible snippet insertion.
 
@@ -15,9 +15,10 @@ a pattern driven static site generator for extensible snippet insertion.
 ## about
 
 metaforge is a static site generator that lets you write something once, and re-use it
-across your site. it requires previous knowledge of html, and doesn't come with pre-made
-themes or templates except for a completely bare skeleton directory. it gives you extremely
-fine grained control over the generated html, customizing each pattern to a source file
+across your site.
+
+metaforge doesn't come with pre-made themes or templates except for a completely bare skeleton directory.
+it gives you extremely fine grained control over the generated html, customizing each pattern to a source file
 with variables and mappable arrays.
 
 metaforge also lets you write metapatterns that contain classes, masking choices to a
@@ -31,7 +32,7 @@ this can be set on both a site and file level, allowing single files in the site
 such as an rss feed. metaforge can also technically translate between any two document formats pandoc supports,
 but nothing other than the default markdown to html gets tested.
 
-the full documentation is available in this repository under the **files/README/source/docs**
+the full documentation is available in this repository under the **docs/source**
 directory. it's currently setup as a working example of a metaforge site, so you can poke around
 and see one way a site can be setup.
 
@@ -41,4 +42,4 @@ and see one way a site can be setup.
 
 this command can be run as many times as needed to regenerate the documentation, and is
 reccomended after upgrading to a new version to see what's changed. the generated docs will
-be available in **files/README/build**, and can be looked at in any web browser.
+be available in **docs/build**, and can be looked at in any web browser.
index b31ed6126cf15830e03a0ca4a4b19ad72bca1a7d..9e7a69448ea18e6bd9f5e5be4c2e03ca955ac951 100644 (file)
@@ -13,7 +13,7 @@ pub fn parallel_build_dir(c: &mut Criterion) {
     opts.clean = true;
     opts.parallel = true;
 
-    c.bench_function("build dir", |b| {
+    c.bench_function("parallel build", |b| {
         if opts.build.exists() {
             std::fs::remove_dir_all(&opts.build).expect("clean build dir");
         }
similarity index 72%
rename from files/README/source/default.meta
rename to docs/source/default.meta
index 3c3a9fbb1ebdbb07c08859e9e6f00cc24b52f401..6c8c8681f7a424ab5c8167c239e57044d32f9972 100644 (file)
@@ -1,5 +1,5 @@
 ${
     author = 'huck boles'
-    version = '0.1.2'
+    version = '0.1.3'
     home = './index.html'
 }
similarity index 65%
rename from files/README/source/docs/default.meta
rename to docs/source/docs/default.meta
index 810305831e2ced403b5a8f0ecd6834c9a41d5912..cf0bd608340d40118d7b86333cc996b7928c179d 100644 (file)
@@ -2,9 +2,9 @@ ${
     -{ index is a folder up in this directory }
     home = '../index.html'
     -{ using substitutions for example code so it doesn't mess up parsing }
-    var = '${ '
-    arr = '@{ '
-    pat = '&{ '
-    head = '#{ '
-    com = '-{ '
+    var = '${'
+    arr = '@{'
+    pat = '&{'
+    head = '#{'
+    com = '-{'
 }
similarity index 97%
rename from files/README/source/docs/definitions.meta
rename to docs/source/docs/definitions.meta
index 2d790ec41d4bcfba551b360be8f2445a15af0b4b..7543ffae12fa36ba3d0f81c67219912c039b90d6 100644 (file)
@@ -1,7 +1,6 @@
 ${
     title = 'definitions'
     description = 'definining variables and patterns'
-    arr_sub = '@{'
 }
 
 ## rules
@@ -73,7 +72,7 @@ value normally.
 
        foo.bar = [ 'foobar', 'foobaz' ]
        ${com} this will copy pattern/foo/*.meta twice, inserting 'foobar and 'foobaz'
-          once each at the location of ${arr_sub}bar} }
+          once each at the location of ${arr}bar} }
     }
 
     ${com} all of these patterns are only defined for this file }
similarity index 77%
rename from files/README/source/docs/expansions.meta
rename to docs/source/docs/expansions.meta
index f3d9212908239ceec4a0a3c16ac9f4a4294db7cb..2fb7ae0b017c178a518a3fcfeba1b3c975c89693 100644 (file)
@@ -1,9 +1,6 @@
 ${
     title = 'expansions'
     description = 'expanding variables and patterns in a file'
-    var_sub = '${'
-    arr_sub = '@{'
-    pat_sub = '&{'
 }
 
 ## syntax
@@ -15,11 +12,11 @@ when the file is built
 
 ### examples
 
-    ...this is a string with a ${var_sub}variable} to be expanded...
+    ...this is a string with a ${var}variable} to be expanded...
 
-    ...this line has a ${pat_sub}pattern} inside of it...
+    ...this line has a ${pat}pattern} inside of it...
 
-    ...this ${arr_sub}array} will be replaced...
+    ...this ${arr}array} will be replaced...
 
 ## behavior
 
@@ -41,11 +38,11 @@ don't need any extra expansion.
            quux = BLANK
         }
 
-    pattern [foo]: <p>${var_sub}baz} ${var}quux}</p>
+    pattern [foo]: <p>${var}baz} ${var}quux}</p>
 
     expanded [foo]: <p>foo </p>
 
-    pattern [bar]: <p>${var_sub}baz} ${var}quux}</p>
+    pattern [bar]: <p>${var}baz} ${var}quux}</p>
 
     expanded [bar]: <p>quux </p>
 
@@ -58,7 +55,7 @@ parts of patterns.
 
 #### example
 
-    pattern [foo]: <p>${arr_sub}bar}</p>
+    pattern [foo]: <p>${arr}bar}</p>
 
     defintion: ${arr} foo.bar = ['foo', 'bar', 'baz'] }
 
@@ -89,20 +86,28 @@ processed source from the original calling file in the source directory. this
 goes through an extra step right before insertion, calling pandoc on the file
 to convert between the chosen filetypes.
 
+***SOURCE*** can also be used as a standin for the source directory while writing expansions,
+allowing patterns to call the same source file every time, or source files to expand other
+source files.
+
+### example
+    ...lorem ${pat}SOURCE.foo.bar} ipsum dolor...
+
 once the filename is determined, it is parsed and expands any contained variables,
 arrays and patterns. if it is a ***SOURCE*** pattern, it is converted to html after
 the expansions. the expanded pattern is then inserted in place of the calling identifier.
 
 ## building
 
-as each file is built, the first thing expanded is the relevant **base/[FILE].meta** pattern,
-so it is required to have at least a **default.meta** in the **pattern/base** directory
+as each source file is built, the first thing expanded is the defined or default
+**[PATTERN]/base/[FILE].meta** pattern, so it is required to have at least a **default.meta**
+in the **pattern/base** directory
 
 ### example
 
-    pattern [base]: <html>${pat_sub}body}</html>
+    pattern [base]: <html>${pat}body}</html>
 
-    pattern [body]: <body>${pat_sub}SOURCE}</body>
+    pattern [body]: <body>${pat}SOURCE}</body>
 
     source [SOURCE]: foo *bar* baz
 
similarity index 93%
rename from files/README/source/docs/flags.meta
rename to docs/source/docs/flags.meta
index 4a00fbfa13faacdf58389a65e389d77c7424ee28..e5fa294c56f64ca1f383f7c6976719409e668e92 100644 (file)
@@ -62,5 +62,6 @@ ${
         --undefined
             panics and stops building site if any undefined variables are encountered
         --no-pandoc
-            don't call pandoc on source files
-            allows metaforge to run without pandoc installed
+            don't call pandoc on source files. allows metaforge to run without pandoc installed
+        --no-minify
+            don't minify resulting html
similarity index 88%
rename from files/README/source/docs/header.meta
rename to docs/source/docs/header.meta
index 88a535161e8cf270c923a847b657183a7ed76c1f..60900a7ed1acdd9eb5c696f24d7be635ec0d8ad2 100644 (file)
@@ -37,11 +37,13 @@ normal definition blocks.
 - blank = **BOOL** - if true, stops parsing and returns an empty string
 - panic_default = **BOOL** - if true, panics on an undefined default pattern
 - panic_undefined = **BOOL** - if true, panics on an undefined variable or array
+- source = **STRING** - change the the filetype of the source file
+- filetype = **STRING** - change the filetype of the output file
 - equal_arrays = **BOOL** - if true, panics if arrays in the same pattern have different sizes
+- minify = **BOOL** - toggles html minification
+- pandoc = **BOOL** - toggles if pandoc is ran on this file to convert between filetypes, defaults to *true* in **source** dir, and *false* in **pattern** dir.
 
 ### source
 
 - ignore = **BOOL** - stops parsing and skips this file, useful for ignoring directories with scoped definitions
-- source = **STRING** - change the the filetype of the source file
-- filetype = **STRING** - change the filetype of the output file
-- pandoc = **BOOL** - toggles if pandoc is ran on this file to convert between filetypes
+- copy_only = **BOOL** - copys file or directory without processing anything
similarity index 99%
rename from files/README/source/docs/structure.meta
rename to docs/source/docs/structure.meta
index b8c51dc3034be79e7bb9f7a4c4e0d74ac64a0338..22a5bef07ba1338cce2e5526250882930d47e35c 100644 (file)
@@ -22,6 +22,7 @@ files from the pattern directory the should generally contain html snippets,
 but can contain anything that you'd like to substitute.
 
 required directories are:
+
 - source (site structure and contents)
 - pattern (patterns for expansion)
 - pattern/base (gets expanded to start building each pattern)
similarity index 93%
rename from files/README/source/docs/syntax.meta
rename to docs/source/docs/syntax.meta
index 72deca72e5280a7e8b2857bdb2f74bc057b66a21..1f552554d584b09f8bec49d52585f8c7130e4d28 100644 (file)
@@ -63,8 +63,11 @@ anywhere in or across a line.
        foobaz }
 
 ## layout
-- optional header definition block
-- optional variable, array, pattern definition blocks
+
+*all sections are optional*
+
+- header definition block
+- variable, array, pattern definition blocks
 - source
 
 ### example
similarity index 55%
rename from files/README/source/index.meta
rename to docs/source/index.meta
index 8a2b15974ec8062a202133018d222c8eb22f7ca6..2c13574de6b0379fce3555ae2cb58ccbec551625 100644 (file)
@@ -6,13 +6,14 @@ this is the documentation for metaforge, generated by metaforge itself.
 
 currently it's unstyled html rendered by your browser, so it's pretty bare-bones.
 
-open **files/README** in metaforge's repository and explore the source and pattern
+open **docs/source** in metaforge's repository and explore the source and pattern
 files to get some examples of how this site works.
 
-you can change anything in the **README** directory and see how it affects the site once
+you can change anything in the **docs** directory and see how it affects the site once
 you rebuild it.
 
 ## contents
+
 - [syntax](docs/syntax.html)
 - [definitions](docs/definitions.html)
 - [expansions](docs/expansions.html)
@@ -20,6 +21,15 @@ you rebuild it.
 - [headers](docs/header.html)
 - [flags](docs/flags.html)
 
+## new in this version
+
+- spaces are correctly preserved between directly adjacent substitutions
+- include from source dir
+- copy_only header directive
+- pandoc header now works on pattern files
+- html minification header and flags
+
 ## versions
+- 0.1.3: grammar and headers
 - 0.1.2: multithreading
 - 0.1.1: initial release
diff --git a/files/test_site/pattern/test/expand_source.meta b/files/test_site/pattern/test/expand_source.meta
new file mode 100644 (file)
index 0000000..c2d0d56
--- /dev/null
@@ -0,0 +1 @@
+&{SOURCE.unit_tests.expand.source_expand}
diff --git a/files/test_site/pattern/test/pandoc.meta b/files/test_site/pattern/test/pandoc.meta
new file mode 100644 (file)
index 0000000..6d3869a
--- /dev/null
@@ -0,0 +1,3 @@
+#{ pandoc = true }
+
+# GOOD
diff --git a/files/test_site/source/unit_tests/expand/source.meta b/files/test_site/source/unit_tests/expand/source.meta
new file mode 100644 (file)
index 0000000..c97e3bc
--- /dev/null
@@ -0,0 +1,3 @@
+${ var = 'GOOD' }
+
+&{ test = 'expand_source' }
diff --git a/files/test_site/source/unit_tests/expand/source_expand.meta b/files/test_site/source/unit_tests/expand/source_expand.meta
new file mode 100644 (file)
index 0000000..c290b5a
--- /dev/null
@@ -0,0 +1,2 @@
+GOOD
+${var}
diff --git a/files/test_site/source/unit_tests/expand/spaces.meta b/files/test_site/source/unit_tests/expand/spaces.meta
new file mode 100644 (file)
index 0000000..073cf92
--- /dev/null
@@ -0,0 +1,6 @@
+${
+    var1 = 'GOOD'
+    var2 = 'GOOD'
+}
+
+${var1} ${var2}
diff --git a/files/test_site/source/unit_tests/header/copy.meta b/files/test_site/source/unit_tests/header/copy.meta
new file mode 100644 (file)
index 0000000..fa04ce3
--- /dev/null
@@ -0,0 +1,3 @@
+#{ copy_only = true }
+
+variable: ${this} should get copied verbatim
diff --git a/files/test_site/source/unit_tests/header/expandoc.meta b/files/test_site/source/unit_tests/header/expandoc.meta
new file mode 100644 (file)
index 0000000..aa6c241
--- /dev/null
@@ -0,0 +1,3 @@
+&{test = 'pandoc'}
+
+source
index 1f341057ef98043d89212ae7b63a3b8f849131df..696d5eb0ada24f6934fe759b76c4ac3489029021 100644 (file)
@@ -83,7 +83,7 @@ pub fn single_file(opts: &Options) -> Result<String> {
         })),
     }?;
 
-    let file = parse_string(source, opts)?;
+    let mut file = parse_string(source, opts)?;
 
     Ok(file.construct()?)
 }
index c23fa8b871854957f97057c9a4074df399d5ea6a..b3c1f5fcd9975601800a164bdb0f2655d1fc7f09 100644 (file)
@@ -11,6 +11,8 @@ pub use scope::*;
 #[cfg(test)]
 mod tests;
 
+use std::fmt::Display;
+
 #[derive(Debug, Clone, PartialEq)]
 pub enum Src {
     Str(String),
@@ -20,27 +22,29 @@ pub enum Src {
 }
 
 impl Src {
-    pub fn to_var(var: impl ToString) -> Self {
+    pub fn to_var(var: impl Display) -> Self {
         Src::Var(var.to_string())
     }
 
-    pub fn to_arr(arr: impl ToString) -> Self {
+    pub fn to_arr(arr: impl Display) -> Self {
         Src::Arr(arr.to_string())
     }
 
-    pub fn to_pat(pat: impl ToString) -> Self {
+    pub fn to_pat(pat: impl Display) -> Self {
         Src::Pat(pat.to_string())
     }
 
-    pub fn to_str(str: impl ToString) -> Self {
+    pub fn to_str(str: impl Display) -> Self {
         Src::Str(str.to_string())
     }
 }
 
-impl ToString for Src {
-    fn to_string(&self) -> String {
-        match self {
+impl Display for Src {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let str = match self {
             Src::Var(x) | Src::Arr(x) | Src::Pat(x) | Src::Str(x) => x.to_string(),
-        }
+        };
+
+        write!(f, "{str}")
     }
 }
index e57630e3ca8f534fee3b480518937a4870767430..d9b2a052980a1c61a25c73a9f4319f6d309826f3 100644 (file)
@@ -1,9 +1,26 @@
 use crate::{error::*, Options};
 use eyre::Result;
+use minify_html::{minify, Cfg};
 use std::{fs, path::PathBuf};
 
 use super::*;
 
+const HTML_CFG: Cfg = Cfg {
+    do_not_minify_doctype: false,
+    ensure_spec_compliant_unquoted_attribute_values: false,
+    keep_closing_tags: true,
+    keep_html_and_head_opening_tags: true,
+    keep_spaces_between_attributes: false,
+    keep_comments: false,
+    minify_css: true,
+    minify_css_level_1: false,
+    minify_css_level_2: true,
+    minify_css_level_3: false,
+    minify_js: true,
+    remove_bangs: true,
+    remove_processing_instructions: true,
+};
+
 impl<'a> DirNode<'a> {
     pub fn build(path: PathBuf, opts: &'a Options) -> Result<Self> {
         assert!(path.is_dir() && path.exists());
@@ -43,6 +60,12 @@ impl<'a> DirNode<'a> {
         for f in fs::read_dir(&self.path)? {
             let file = f?.path();
 
+            if self.global.header.copy_only {
+                let dest = self.global.dest()?;
+                fs::copy(file, &dest.parent().unwrap_or(&self.opts.build))?;
+                continue;
+            }
+
             if file.is_dir() {
                 let dir = DirNode::build(file, self.opts)?;
                 self.dirs.push(dir);
@@ -63,7 +86,11 @@ impl<'a> DirNode<'a> {
             file.merge(&self.global);
             match file.construct() {
                 Ok(str) => {
-                    fs::write(file.dest()?, str)?;
+                    if file.header.minify && self.opts.minify {
+                        fs::write(file.dest()?, minify(str.as_bytes(), &HTML_CFG))?;
+                    } else {
+                        fs::write(file.dest()?, str)?;
+                    }
                 }
                 Err(e) => {
                     // print a line to stderr about failure but continue with other files
index b664b0941fc39e782ce8bb5cd3e7997dc8adb442..b86570942cca1a019d91c64fbb425a7261e6788a 100644 (file)
@@ -10,6 +10,7 @@ use pandoc::{InputFormat, InputKind, OutputFormat, OutputKind, Pandoc};
 use std::{collections::HashMap, path::PathBuf};
 
 use super::*;
+
 #[derive(Debug, Clone)]
 pub struct MetaFile<'a> {
     pub opts: &'a Options,
@@ -54,7 +55,7 @@ impl<'a> MetaFile<'a> {
         Ok(metafile)
     }
 
-    pub fn construct(&self) -> Result<String, Box<MetaError>> {
+    pub fn construct(&mut self) -> Result<String, Box<MetaError>> {
         log!(self.opts, format!("building {}", self.path.display()), 1);
 
         if self.header.blank {
@@ -63,7 +64,19 @@ impl<'a> MetaFile<'a> {
             return Err(Box::new(MetaError::Ignored));
         }
 
-        let html = self.to_html().map_err(MetaError::from)?;
+        if self.header.copy_only {
+            let dest = self.dest().map_err(MetaError::from)?;
+            let source: String = self.source.iter().map(|s| s.to_string()).collect();
+            std::fs::write(dest, source).unwrap();
+            return Err(Box::new(MetaError::Ignored));
+        }
+
+        let src_str: String;
+        if self.header.pandoc.map_or(true, |x| x) {
+            src_str = self.pandoc().map_err(MetaError::from)?;
+        } else {
+            src_str = self.get_source().map_err(MetaError::from)?;
+        }
 
         let pattern = self.get_pattern("base").map_err(MetaError::from)?;
         let mut base = parse_string(pattern, self.opts).map_err(|e| MetaError::ParserError {
@@ -72,7 +85,16 @@ impl<'a> MetaFile<'a> {
         })?;
 
         base.merge(self);
-        base.patterns.insert(Scope::into_global("SOURCE"), html);
+        base.patterns
+            .insert(Scope::create_global("SOURCE"), src_str);
+        let mut base_path = self.opts.pattern.join("base").join(
+            self.patterns
+                .get(&Scope::create_global("base"))
+                .unwrap_or(&"default".into()),
+        );
+
+        base_path.set_extension("meta");
+        base.path = base_path;
 
         let output = base.get_source().map_err(MetaError::from)?;
 
index 122e8b1741415139d343714bef98ada2a1d3ddd0..1b38c0f423f8dff4e94f1e78af19da7994ec8d86 100644 (file)
@@ -29,15 +29,15 @@ impl<'a> MetaFile<'a> {
 
                 let value = if let Some(val) = self.arrays.get(&name_key) {
                     &val[..]
-                } else if let Some(val) = self.arrays.get(&name_key.to_global()) {
+                } else if let Some(val) = self.arrays.get(&name_key.global()) {
                     &val[..]
                 } else if let Some(val) = self.arrays.get(&class_key) {
                     &val[..]
-                } else if let Some(val) = self.arrays.get(&class_key.to_global()) {
+                } else if let Some(val) = self.arrays.get(&class_key.global()) {
                     &val[..]
-                } else if let Some(val) = self.arrays.get(&Scope::into_global(key)) {
+                } else if let Some(val) = self.arrays.get(&Scope::create_global(key)) {
                     &val[..]
-                } else if let Some(val) = self.arrays.get(&Scope::into_local(key)) {
+                } else if let Some(val) = self.arrays.get(&Scope::create_local(key)) {
                     &val[..]
                 } else if self.opts.undefined {
                     panic!(
index 1df58444fd9d3750cce0693bb18b55389d7f4a6d..304254f4088edf74c4cd428c7db37f53decc5aab 100644 (file)
@@ -5,22 +5,25 @@ impl<'a> MetaFile<'a> {
         log!(self.opts, format!("expanding {key}"), 2);
         // SOURCE is already expanded in the initial construct() call
         if key == "SOURCE" {
-            if let Some(source) = self.patterns.get(&Scope::into_global("SOURCE")) {
+            if let Some(source) = self.patterns.get(&Scope::create_global("SOURCE")) {
                 return Ok(source.to_string());
             } else {
                 return Ok(String::new());
             }
         }
 
-        let mut filename = if let Some(name) = self.patterns.get(&Scope::into_local(key)) {
+        let is_source = key.split('.').next().unwrap_or("") == "SOURCE";
+
+        let mut filename = if let Some(name) = self.patterns.get(&Scope::create_local(key)) {
             Ok(name.to_string())
-        } else if let Some(name) = self.patterns.get(&Scope::into_global(key)) {
+        } else if let Some(name) = self.patterns.get(&Scope::create_global(key)) {
             Ok(name.to_string())
         } else if self
             .opts
             .pattern
             .join(key.replace(".", "/") + ".meta")
             .exists()
+            || is_source
         {
             Ok(String::new())
         } else if self.header.panic_default {
@@ -61,14 +64,24 @@ impl<'a> MetaFile<'a> {
         }
 
         let pattern_path = key.replace('.', "/") + "/" + &filename;
-        let mut path = self.opts.pattern.join(pattern_path);
-        path.set_extension("meta");
 
+        let mut path = if is_source {
+            let pattern_path = pattern_path.replace("SOURCE/", "");
+            self.opts.source.join(pattern_path)
+        } else {
+            self.opts.pattern.join(pattern_path)
+        };
+
+        path.set_extension("meta");
         let mut pattern = MetaFile::build(path, self.opts)?;
 
         // copy over maps for expanding contained variables
         pattern.merge(self);
 
-        pattern.get_source()
+        if pattern.header.pandoc.unwrap_or(false) || is_source {
+            pattern.pandoc()
+        } else {
+            pattern.get_source()
+        }
     }
 }
index 6ffad587e85757090313f0d7c8edcac0d6260409..3aca3b4fb886f4bc0b031175319089f86a177cfb 100644 (file)
@@ -1,10 +1,10 @@
 use super::*;
 
 impl<'a> MetaFile<'a> {
-    pub fn to_html(&self) -> Result<String> {
+    pub fn pandoc(&mut self) -> Result<String> {
         let string = self.get_source()?;
 
-        if self.opts.no_pandoc || !self.header.pandoc || string.is_empty() {
+        if self.opts.no_pandoc || string.is_empty() {
             return Ok(string);
         }
 
@@ -28,6 +28,7 @@ impl<'a> MetaFile<'a> {
             .set_output_format(output, vec![]);
 
         if let pandoc::PandocOutput::ToBuffer(s) = pandoc.execute()? {
+            self.header.pandoc = Some(false);
             Ok(s)
         } else {
             Err(MetaError::Pandoc { file: self.name()? }.into())
index 033f38c2b125748b8d2155ea4f6a6c7df5c6596b..08f09f81fb7bba42ed88c3f3be0e76a0392b9fe8 100644 (file)
@@ -12,13 +12,13 @@ impl<'a> MetaFile<'a> {
             2
         );
         let long_key = self.name()? + "." + &key.to_string();
-        if let Some(val) = self.variables.get(&Scope::into_local(&long_key)) {
+        if let Some(val) = self.variables.get(&Scope::create_local(&long_key)) {
             Ok(val.clone())
-        } else if let Some(val) = self.variables.get(&Scope::into_global(&long_key)) {
+        } else if let Some(val) = self.variables.get(&Scope::create_global(&long_key)) {
             Ok(val.clone())
-        } else if let Some(val) = self.variables.get(&Scope::into_local(key)) {
+        } else if let Some(val) = self.variables.get(&Scope::create_local(key)) {
             Ok(val.clone())
-        } else if let Some(val) = self.variables.get(&Scope::into_global(key)) {
+        } else if let Some(val) = self.variables.get(&Scope::create_global(key)) {
             Ok(val.clone())
         } else if self.opts.undefined || self.header.panic_undefined {
             return Err(MetaError::UndefinedExpand {
index fdaed0aab50b02177a7c28240e57b04314a750a8..a895ac3492db11cd545f2025d9fdf78ac2383362 100644 (file)
@@ -8,8 +8,10 @@ pub struct Header {
     pub equal_arrays: bool,
     pub filetype: String,
     pub source: String,
-    pub pandoc: bool,
+    pub pandoc: Option<bool>,
     pub ignore: bool,
+    pub copy_only: bool,
+    pub minify: bool,
 }
 
 impl Header {
@@ -21,8 +23,10 @@ impl Header {
             equal_arrays: false,
             filetype: String::from("html"),
             source: String::from("markdown"),
-            pandoc: true,
+            pandoc: None,
             ignore: false,
+            copy_only: false,
+            minify: true,
         }
     }
 }
@@ -36,10 +40,12 @@ impl From<HashMap<String, String>> for Header {
                 "panic_default" => header.panic_default = val == "true",
                 "panic_undefined" => header.panic_undefined = val == "true",
                 "equal_arrays" => header.equal_arrays = val == "true",
-                "pandoc" => header.pandoc = val == "true",
+                "pandoc" => header.pandoc = Some(val == "true"),
                 "filetype" => header.filetype = val.to_string(),
                 "source" => header.source = val.to_string(),
                 "ignore" => header.ignore = val == "true",
+                "copy_only" => header.copy_only = val == "true",
+                "minify" => header.copy_only = val == "true",
                 _ => continue,
             }
         }
index 8e23b1db7f6a232e0bf00636fab8968c4c11a722..c1187c78f6693249a6bb71a06db393db45da5c64 100644 (file)
@@ -1,3 +1,5 @@
+use std::fmt::Display;
+
 #[derive(Debug, Clone, Eq, Hash, PartialEq)]
 pub enum Scope {
     Local(String),
@@ -5,11 +7,11 @@ pub enum Scope {
 }
 
 impl Scope {
-    pub fn into_local(str: impl ToString) -> Scope {
+    pub fn create_local(str: impl Display) -> Scope {
         Scope::Local(str.to_string())
     }
 
-    pub fn into_global(str: impl ToString) -> Scope {
+    pub fn create_global(str: impl ToString) -> Scope {
         Scope::Global(str.to_string())
     }
 
@@ -27,19 +29,21 @@ impl Scope {
         }
     }
 
-    pub fn to_local(&self) -> Scope {
+    pub fn local(&self) -> Scope {
         Scope::Local(self.to_string())
     }
 
-    pub fn to_global(&self) -> Scope {
+    pub fn global(&self) -> Scope {
         Scope::Global(self.to_string())
     }
 }
 
-impl ToString for Scope {
-    fn to_string(&self) -> String {
-        match self {
+impl Display for Scope {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let str = match self {
             Scope::Local(x) | Scope::Global(x) => x.to_string(),
-        }
+        };
+
+        write!(f, "{str}")
     }
 }
index 704d2cbc8404d9c659afbe38c75c511f17fdb288..0b021e74d0e4a7979ee9b9531d3f72ff8d5fea15 100644 (file)
@@ -4,7 +4,7 @@ use std::path::PathBuf;
 
 #[derive(Parser, Debug)]
 #[command(author = "huck boles")]
-#[command(version = "0.1.2")]
+#[command(version = "0.1.3")]
 #[command(about = "customizable template driven static site generator")]
 #[command(long_about = None)]
 pub struct Opts {
@@ -53,6 +53,9 @@ pub struct Opts {
     /// don't call pandoc on source files
     #[arg(long, default_value_t = false)]
     pub no_pandoc: bool,
+    /// don't minify resulting html
+    #[arg(long, default_value_t = false)]
+    pub no_minify: bool,
 }
 
 #[derive(Debug, Clone, Default)]
@@ -72,6 +75,7 @@ pub struct Options {
     pub clean: bool,
     pub no_pandoc: bool,
     pub new: bool,
+    pub minify: bool,
 }
 
 impl Options {
@@ -92,6 +96,7 @@ impl Options {
             clean: false,
             no_pandoc: false,
             new: false,
+            minify: true,
         }
     }
 }
@@ -109,6 +114,7 @@ impl TryFrom<crate::Opts> for Options {
         opts.no_pandoc = value.no_pandoc;
         opts.new = value.new;
         opts.parallel = value.parallel;
+        opts.minify = !value.no_minify;
 
         opts.root = if let Some(root) = value.root.as_deref() {
             PathBuf::from(root).canonicalize()
index 770515824e60b521ba8f8c54d85defd42b238057..d30dea521005f73a1104c0552f4458b808a42707 100644 (file)
@@ -11,7 +11,7 @@ use source::*;
 #[cfg(test)]
 mod tests;
 
-use crate::{log, Header, MetaError, MetaFile, Options};
+use crate::{Header, MetaError, MetaFile, Options};
 use eyre::Result;
 use pest::{
     iterators::{Pair, Pairs},
@@ -23,8 +23,6 @@ use pest::{
 pub struct MetaParser;
 
 pub fn parse_string(file: String, opts: &Options) -> Result<MetaFile> {
-    log!(opts, "parsing file", 3);
-
     let pair = MetaParser::parse(Rule::file, &file)?.next().unwrap();
 
     let mut meta_file = MetaFile::new(opts);
index 8358f586da7f629bd753e92c5eb3bde7891e8343..30b297998c6e83bfd135f537414233fd3a837ebe 100644 (file)
@@ -40,9 +40,9 @@ fn parse_assign_array(pair: Pair<Rule>) -> Result<(Scope, Vec<String>)> {
     }
 
     if global {
-        Ok((Scope::into_global(key), val))
+        Ok((Scope::create_global(key), val))
     } else {
-        Ok((Scope::into_local(key), val))
+        Ok((Scope::create_local(key), val))
     }
 }
 
index 26333efa0f0d4db5b4299e28a57590140182c791..080d1d48f443e0403fad886b4719f0ec08ff36a9 100644 (file)
@@ -55,8 +55,8 @@ fn parse_assign(pair: Pair<Rule>) -> Result<(Scope, &str)> {
     }
 
     if global {
-        Ok((Scope::into_global(key), val))
+        Ok((Scope::create_global(key), val))
     } else {
-        Ok((Scope::into_local(key), val))
+        Ok((Scope::create_local(key), val))
     }
 }
index a4aa0d74513b046f4bf5400a684414bffd7b51e9..1116c97b24f721075ff94fcf711c7d92056b98b0 100644 (file)
@@ -17,10 +17,10 @@ char   =  _{
 
 array = _{
     "[" ~ "]"
-  | "[" 
-  ~ WHITESPACE* 
-  ~ string 
-  ~ (WHITESPACE* ~ "," ~ WHITESPACE* ~ string)* 
+  | "["
+  ~ WHITESPACE*
+  ~ string
+  ~ (WHITESPACE* ~ "," ~ WHITESPACE* ~ string)*
   ~ WHITESPACE* ~ ","? ~ WHITESPACE*
   ~ "]"
 }
@@ -46,9 +46,9 @@ substitution = _{ sigil ~ key ~ "}" }
 var_sub      =  { &("$") ~ substitution }
 arr_sub      =  { &("@") ~ substitution }
 pat_sub      =  { &("&") ~ substitution }
-identifier   = _{ var_sub | pat_sub | arr_sub }
+identifier   = _{ var_sub | pat_sub | arr_sub | COMMENT}
 
-source = { (identifier | char_seq)* }
+source = ${ (identifier | char_seq)* }
 
 file = {
     SOI ~ header? ~ definition* ~ source? ~ EOI
index 26fb1779ff4480f8ec2972b1d87f5cc180339b2f..8564ce79a84504fbfb64d9d190030fdae8da3b53 100644 (file)
@@ -1,4 +1,4 @@
-use crate::{MetaFile, Options};
+use crate::{MetaError, MetaFile, Options};
 use eyre::Result;
 use std::{fs, path::PathBuf};
 
@@ -17,8 +17,18 @@ macro_rules! unit_test (
             let test_dir = opts.source.join("unit_tests");
             let mut path = test_dir.join($file);
             path.set_extension("meta");
-            let file = MetaFile::build(path, &opts)?;
-            assert_eq!(file.construct()?, $test);
+            let mut file = MetaFile::build(path, &opts)?;
+
+            let str = match file.construct() {
+                Ok(f) => f,
+                Err(e) => match *e {
+                    MetaError::Ignored => return Ok(()),
+                    e => return Err(e.into())
+                }
+
+            };
+
+            assert_eq!(str, $test);
             Ok(())
         }
     };
@@ -40,65 +50,69 @@ macro_rules! panic_test (
             let test_dir = opts.source.join("unit_tests");
             let mut path = test_dir.join($file);
             path.set_extension("meta");
-            let file = MetaFile::build(path, &opts).unwrap();
+            let mut file = MetaFile::build(path, &opts).unwrap();
             assert_eq!(file.construct().unwrap(), $test);
         }
     };
 );
 
 unit_test!(blank_pattern, "blank/blank_pattern", "");
-unit_test!(blank_variable, "blank/blank_variable", "<html>\n</html>\n");
-unit_test!(blank_array, "blank/blank_array", "<html>\n</html>\n");
-unit_test!(blank_comment, "blank/comment", "<html>\n</html>\n");
+unit_test!(
+    blank_variable,
+    "blank/blank_variable",
+    "<html>\n\n\n</html>\n"
+);
+unit_test!(blank_array, "blank/blank_array", "<html>\n\n\n</html>\n");
+unit_test!(blank_comment, "blank/comment", "<html>\n\n\n\n</html>\n");
 unit_test!(
     inline_comment,
     "blank/inline_comment",
-    "<html>\n<p>inline comment</p>\n</html>\n"
+    "<html>\n<p>inline comment</p>\n\n\n\n</html>\n"
 );
 unit_test!(
     expand_var_in_src,
     "expand/variable_in_source",
-    "<html>\n<p>GOOD</p>\n</html>\n"
+    "<html>\n<p>GOOD</p>\n\n\n\n</html>\n"
 );
 unit_test!(
     expand_var_in_pat,
     "expand/variable_in_pattern",
-    "<html>\nGOOD</html>\n"
+    "<html>\nGOOD\n\n\n</html>\n"
 );
 unit_test!(
     expand_arr_in_src,
     "expand/array_in_source",
-    "<html>\n<p>12345</p>\n</html>\n"
+    "<html>\n<p>1 2 3 4 5</p>\n\n\n\n</html>\n"
 );
 unit_test!(
     expand_arr_in_pat,
     "expand/array_in_pattern",
-    "<html>\n12345</html>\n"
+    "<html>\n1\n2\n3\n4\n5\n\n\n</html>\n"
 );
 unit_test!(
     expand_pat_in_src,
     "expand/pattern_in_source",
-    "<p>GOOD</p>\n"
+    "<p>GOOD</p>\n\n"
 );
 unit_test!(
     expand_pat_in_pat,
     "expand/pattern_in_pattern",
-    "<html>\nGOOD\nGOOD\n</html>\n"
+    "<html>\nGOOD\nGOOD\n\n\n\n</html>\n"
 );
 unit_test!(
     override_var,
     "override/variable",
-    "<html>\n<p>GOOD</p>\n</html>\n"
+    "<html>\n<p>GOOD</p>\n\n\n\n</html>\n"
 );
 unit_test!(
     override_pat,
     "override/pattern",
-    "<html>\nGOOD\nGOOD\n</html>\n"
+    "<html>\nGOOD\n GOOD\n\n\n\n</html>\n"
 );
 unit_test!(
     header_no_pandoc,
     "header/pandoc",
-    "# This should not become html\n"
+    "# This should not become html\n\n"
 );
 
 unit_test!(header_blank, "header/blank", "");
@@ -106,13 +120,37 @@ unit_test!(header_blank, "header/blank", "");
 unit_test!(
     pat_file,
     "expand/file.meta",
-    "<html>\n<p>GOOD</p>\n</html>\n"
+    "<html>\n<p>GOOD</p>\n\n\n\n</html>\n"
 );
 
 unit_test!(
     direct_call,
     "expand/direct_call",
-    "<html>\n<p>abcd</p>\n</html>\n"
+    "<html>\n<p>a b c d</p>\n\n\n\n</html>\n"
+);
+
+unit_test!(
+    expand_spaces,
+    "expand/spaces",
+    "<html>\n<p>GOOD GOOD</p>\n\n\n\n</html>\n"
+);
+
+unit_test!(
+    copy_header,
+    "header/copy",
+    r#"variable: ${this} should get copied verbatim"#
+);
+
+unit_test!(
+    expandoc,
+    "header/expandoc",
+    "<html>\n<h1 id=\"good\">GOOD</h1>\n\n\n</html>\n"
+);
+
+unit_test!(
+    include_source,
+    "expand/source",
+    "<html>\n<p>GOOD GOOD</p>\n\n\n\n</html>\n"
 );
 
 panic_test!(ignore, "ignore.meta", "");
@@ -157,12 +195,12 @@ fn test_global() -> Result<()> {
 
     assert_eq!(
         fs::read_to_string(dir.join("build/unit_tests/global/pattern.html"))?,
-        "<p>GOOD GOOD</p>\n"
+        "<p>GOOD</p><p>GOOD</p>"
     );
 
     assert_eq!(
         fs::read_to_string(dir.join("build/unit_tests/global/variable.html"))?,
-        "<p>GOODGOOD</p>\n"
+        "<p>GOOD GOOD</p>"
     );
 
     Ok(())
index 01279d7a915a5c5b73579936b967b70927933eed..543bf2ef7ec7b174a8ef53d82232aa07c32d465c 100644 (file)
@@ -3,7 +3,7 @@ use eyre::Result;
 #[test]
 #[ignore = "generates README site"]
 fn readme() -> Result<()> {
-    let dir = std::path::PathBuf::from("files/README")
+    let dir = std::path::PathBuf::from("docs")
         .canonicalize()
         .unwrap();