Changes
26 changed files (+1317/-4)
-
-
@@ -15,3 +15,7 @@ # Why: Although test cleans up the temporary directory, there could be a chance the# cleanup code does not work and the directory (accidentally) remains. # This prevents VCS picking up the directory in that case. filesystem_writer/.test # What: Docs website build output directory # Why: This directory contains build artifacts, not source code. docs/.dist
-
-
-
@@ -1,11 +1,15 @@{ "fmt": { "useTabs": true, "include": ["**/*.ts"] "include": ["**/*.ts", "**/*.tsx"] }, "lint": { "rules": { "exclude": ["require-await"] "exclude": ["require-await", "require-yield"] } }, "tasks": { "build-docs": "deno run --allow-read=docs --allow-write=docs/.dist docs/build.ts", "serve-docs": "cd docs/.dist && deno run --allow-read=. --allow-net https://deno.land/std/http/file_server.ts ." } }
-
-
-
@@ -1,7 +1,28 @@{ "version": "3", "packages": { "specifiers": { "npm:@types/node": "npm:@types/node@18.16.19" }, "npm": { "@types/node@18.16.19": { "integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==", "dependencies": {} } } }, "redirects": { "https://deno.land/std/encoding/base64.ts": "https://deno.land/std@0.221.0/encoding/base64.ts" "https://deno.land/std/encoding/base64.ts": "https://deno.land/std@0.221.0/encoding/base64.ts", "https://esm.sh/hast-util-is-element@3": "https://esm.sh/hast-util-is-element@3.0.0", "https://esm.sh/v128/@types/react@~18.2/index.d.ts": "https://esm.sh/v128/@types/react@18.2.38/index.d.ts", "https://esm.sh/v135/@types/react-dom@~18.2/server~.d.ts": "https://esm.sh/v135/@types/react-dom@18.2.24/server~.d.ts", "https://esm.sh/v135/hast-util-to-jsx-runtime@2": "https://esm.sh/v135/hast-util-to-jsx-runtime@2.3.0", "https://esm.sh/v135/hast-util-to-jsx-runtime@2?bundle": "https://esm.sh/v135/hast-util-to-jsx-runtime@2.3.0?bundle", "https://esm.sh/v135/mdast-util-from-markdown@2": "https://esm.sh/v135/mdast-util-from-markdown@2.0.0", "https://esm.sh/v135/mdast-util-from-markdown@2?bundle": "https://esm.sh/v135/mdast-util-from-markdown@2.0.0?bundle", "https://esm.sh/v135/mdast-util-to-hast@13": "https://esm.sh/v135/mdast-util-to-hast@13.1.0", "https://esm.sh/v135/mdast-util-to-hast@13?bundle": "https://esm.sh/v135/mdast-util-to-hast@13.1.0?bundle", "https://esm.sh/v135/mdast-util-toc@7": "https://esm.sh/v135/mdast-util-toc@7.0.0" }, "remote": { "https://deno.land/std@0.159.0/encoding/ascii85.ts": "f2b9cb8da1a55b3f120d3de2e78ac993183a4fd00dfa9cb03b51cf3a75bc0baa",
-
@@ -156,8 +177,121 @@ "https://deno.land/x/brotli@0.1.7/mod.ts": "08b913e51488b6e7fa181f2814b9ad087fdb5520041db0368f8156bfa45fd73e","https://deno.land/x/brotli@0.1.7/wasm.js": "77771b89e89ec7ff6e3e0939a7fb4f9b166abec3504cec0532ad5c127d6f35d2", "https://deno.land/x/lz4@v0.1.2/mod.ts": "4decfc1a3569d03fd1813bd39128b71c8f082850fe98ecfdde20025772916582", "https://deno.land/x/lz4@v0.1.2/wasm.js": "b9c65605327ba273f0c76a6dc596ec534d4cda0f0225d7a94ebc606782319e46", "https://deno.land/x/nano_jsx@v0.1.0/component.ts": "6bd3dab67754e91308df863e11e2b7945bbe0bf575b4bc529e8a9e02087eb732", "https://deno.land/x/nano_jsx@v0.1.0/components/helmet.ts": "59e598dc79c7b18620de175c61eb26f4aeb6905a6654cd63359208a26471541e", "https://deno.land/x/nano_jsx@v0.1.0/components/img.ts": "82a9f830394a7d6cd9b789b48fe1e70bc64eb151c4b410a3da74347c06acdae0", "https://deno.land/x/nano_jsx@v0.1.0/components/index.ts": "8855ee8302a9a19f38202d4a7ff5b17e22942600da02356bdfbc80c99c5c55f5", "https://deno.land/x/nano_jsx@v0.1.0/components/link.ts": "0f0b1c57dc8c466203105062335e0d9ded89a34e75d08b1bbeece198d42021cb", "https://deno.land/x/nano_jsx@v0.1.0/components/router.ts": "186e77064a96c31cb66ff1935c93d91904347647fcb13b56b5875ea64905397d", "https://deno.land/x/nano_jsx@v0.1.0/components/suspense.ts": "0711b7cdcd42b0b085972eca796d3ba7c436a736e1d2ce17db7e0cd1d3b928f5", "https://deno.land/x/nano_jsx@v0.1.0/components/visible.ts": "f19487f7faff0bad38a5549f1efac1df351e83ee4a77ca5886412b439f4b6b53", "https://deno.land/x/nano_jsx@v0.1.0/context.ts": "a65018beedf3e1863b96f9d99cf2d471c231a6ae0c77877a77754a398105f9fc", "https://deno.land/x/nano_jsx@v0.1.0/core.ts": "9346346ba7ddc52057131953a333c3ffa12e2a93aaceb25dabbab4bf8f1a171c", "https://deno.land/x/nano_jsx@v0.1.0/customElementsMode.ts": "61b9688ae89bfcc6109b72eaab4d82a69a8482d89770f3e2c1359b79bf57bb91", "https://deno.land/x/nano_jsx@v0.1.0/fragment.ts": "9cfb0dcdcb02d5cc53f027b4b55609e4f9d6d9322b665292e572856f4b688569", "https://deno.land/x/nano_jsx@v0.1.0/helpers.ts": "d904aa646534f1c0cf7c05a6c8e02231f906d962acb725c964aedbcf50216d85", "https://deno.land/x/nano_jsx@v0.1.0/htm.ts": "d8d9cd4fb4ad4645bff3698c7eb96e7798022c5519d04e709ebde236edde156b", "https://deno.land/x/nano_jsx@v0.1.0/htm/build.ts": "9d6b6eb407c0db2d1213a3f9c82efc66a2bec34c89976132ff13e3e095dcaaaf", "https://deno.land/x/nano_jsx@v0.1.0/htm/constants.ts": "3f296f87f03bd0ba8d7673884a1f6c4c927a2774648eaa4fd3ca9e3c46c3f7b8", "https://deno.land/x/nano_jsx@v0.1.0/htm/index.ts": "29912b9f7a760884fce79caca82649b9772cfa3c3272e0426a4ce377b67d70d5", "https://deno.land/x/nano_jsx@v0.1.0/index.ts": "0f39c911a39c61cb39f9bd8a2481500126dcb1b2a826d5b4523dd47a08b6938d", "https://deno.land/x/nano_jsx@v0.1.0/jsx-runtime/index.ts": "eb3d0884774eb3bf360d731bd7787aef2701f1be7e91aff8f88da59153d6aaa5", "https://deno.land/x/nano_jsx@v0.1.0/jsx.ts": "7d5b4d4a249fba1a42f2016f54f71ca049d96ff490e098db4a19b2a9b197b952", "https://deno.land/x/nano_jsx@v0.1.0/lazy.ts": "f8b8a2b915daff1fb70704ffad5171c805f1e28778b5cd0f8c827780762776c4", "https://deno.land/x/nano_jsx@v0.1.0/mod.ts": "3dda2bc0dbee9abd01c03acf43ab55a7854952afe0450245fc2ad12eb9bd9598", "https://deno.land/x/nano_jsx@v0.1.0/regexDom.ts": "de82fd3110c5a367e3d4ba9b774cfef3baf995deff455edc7363551d79089c90", "https://deno.land/x/nano_jsx@v0.1.0/ssr.ts": "1ab6c17f41f612fe409d29d81ce1f17692ff02e5abea6ef4080cabecafc246dd", "https://deno.land/x/nano_jsx@v0.1.0/state.ts": "cfc6ca6eb5e65f4cd60717a0a96ce604053bacf6e0b8835afbe22327e9979a1b", "https://deno.land/x/nano_jsx@v0.1.0/store.ts": "bf075833a656fc87b2a24c486bb3f77e13f19d6d9efcc42e31ffb6f24ec8eb93", "https://deno.land/x/nano_jsx@v0.1.0/types.ts": "fb338d7fa4422a92c442d14e073a2deb01d42b017fcd36013a1f6554e17c5449", "https://deno.land/x/nano_jsx@v0.1.0/version.ts": "d7f3813a3b1c490f16e77047483b0dc52cc0cec6cb1b73d6926cf9ad96129a59", "https://deno.land/x/nano_jsx@v0.1.0/withStyles.ts": "8aae4c8e79319fe991d49dd8ccc927c221786dfe58de640dba9d9885ce0dd4b7", "https://deno.land/x/zstd_wasm@0.0.21/deno/zstd.deno.js": "189187a43a4bdc8d695ff2f6525c8d3461cbd715333123e502a6a3bd84c272b4", "https://deno.land/x/zstd_wasm@0.0.21/deno/zstd.encoded.wasm.ts": "87e04064657bf5082b47a709931f8eb3f0d2fe537a8c650cfb5c997b7b460d07", "https://deno.land/x/zstd_wasm@0.0.21/deno/zstd.ts": "ba3889ee2b11f73ae7c6192da2851ec5f037b5ae7e3afa4c9129f33e856616ec" "https://deno.land/x/zstd_wasm@0.0.21/deno/zstd.ts": "ba3889ee2b11f73ae7c6192da2851ec5f037b5ae7e3afa4c9129f33e856616ec", "https://esm.sh/hast-util-is-element@3.0.0": "d5b1ded368a5fbbcb79687bebcf33d94a37020bd82116c1bec69a012f17e5cf2", "https://esm.sh/preact-render-to-string@6.4.1": "a9ca466e5daf03595e041d96829c74f8e493f928e35a64b56365d952fda04ec3", "https://esm.sh/preact@10.20.1": "5c0877793f441a58c8109d0f6b8e07cce501f3dc4389ee4405d87a50de44db3c", "https://esm.sh/preact@10.20.1/hooks.js": "3c7307938d2318feb8fa1d5aed0a7550a25bff23434cc0fa76e036b80d877e2a", "https://esm.sh/stable/preact@10.20.0/denonext/preact.mjs": "323ac0dab4ede066d3ef67ae2f51029ed1bd5f81f5a07982924a00aee3c54ada", "https://esm.sh/stable/preact@10.20.1/denonext/compat.js": "645c1935e3fa4096c9293d0a6a09a9b4a3d522ae0365d617b9abbfc41ffc4ea2", "https://esm.sh/stable/preact@10.20.1/denonext/compat/server.js": "4a08e5a7e1de3584c7b3a8e96493eb7f2e1f49057324d0f954902b2ac5390e83", "https://esm.sh/stable/preact@10.20.1/denonext/hooks.js": "dc0ad52e80dfe7c7c8c220b95f39474e6507c2427ae96f73c5264718eac01431", "https://esm.sh/stable/preact@10.20.1/denonext/preact.mjs": "eed417f1653718f3b8b4b5d1b61ad66967fc02ed2cf86f7589ce0c813c8ed0b6", "https://esm.sh/stable/preact@10.20.1/hooks.js": "3c7307938d2318feb8fa1d5aed0a7550a25bff23434cc0fa76e036b80d877e2a", "https://esm.sh/stable/react@18.2.0/denonext/react.mjs": "3c4f23bcfc53b256fcfaf6f834fa9f584c3bb7be667b2682c6cb6ba8ef88f8e6", "https://esm.sh/v128/preact-render-to-string@6.4.1": "c0161494cc78f56b695311b6645b1fe95138208452fde74e66a648e90d0f3c7e", "https://esm.sh/v128/preact-render-to-string@6.4.1/denonext/preact-render-to-string.mjs": "a23117196727aa230f09f037f4efc2e3704b47c7a4523087c23cf0a8f942e48d", "https://esm.sh/v128/preact@10.20.1": "5c0877793f441a58c8109d0f6b8e07cce501f3dc4389ee4405d87a50de44db3c", "https://esm.sh/v135/@shelf/fast-uslug@1.0.0": "46107bc12821cd3fd8605a1a837fc9288a254d8e4e406126059b5a6031695ad0", "https://esm.sh/v135/@shelf/fast-uslug@1.0.0/denonext/fast-uslug.mjs": "d140f64633d7ede6e407d8b9ea3236b6c614da96c5fce03297f353e735106cf0", "https://esm.sh/v135/@ungap/structured-clone@1.2.0/denonext/structured-clone.mjs": "e683ab48ef7a3afd3bce9d1589d14177ddbdbf76fa1483524dddbeb6b142469f", "https://esm.sh/v135/character-entities@2.0.2/denonext/character-entities.mjs": "9e8657f056310ac3ca8058eaf96cef695ee13a4bf6c302674796a882464f305c", "https://esm.sh/v135/comma-separated-tokens@2.0.3/denonext/comma-separated-tokens.mjs": "ad5df8a36487e0a63d15bbbb6bab8b153e08583d0d5eb6d0058cd0fc619252e0", "https://esm.sh/v135/decode-named-character-reference@1.0.2/denonext/decode-named-character-reference.mjs": "1a5a8f9cbe302be478e964ab701be8644dbdfd4d8ce9f14de186cf84ee2a4bc1", "https://esm.sh/v135/devlop@1.1.0/denonext/devlop.mjs": "05fffa5a5168daec45963b784734dbc468758e130a340af874adfe0d457e394a", "https://esm.sh/v135/estree-util-is-identifier-name@3.0.0/denonext/estree-util-is-identifier-name.mjs": "2d1080530be602e98e40807bbb760a08a017b315be59fe869b57afca5d667dca", "https://esm.sh/v135/github-slugger@2.0.0/denonext/github-slugger.mjs": "42ff6fe7ba4f63d8a048970e5a32cd5b0348905dde3f9e270d90e44a6e7635ae", "https://esm.sh/v135/hast-util-is-element@3.0.0": "d5b1ded368a5fbbcb79687bebcf33d94a37020bd82116c1bec69a012f17e5cf2", "https://esm.sh/v135/hast-util-is-element@3.0.0/denonext/hast-util-is-element.mjs": "d6abf8aaf1da9775a8731295649387cf59ceb0b50eae25953bee6ea9af8043af", "https://esm.sh/v135/hast-util-to-jsx-runtime@2.3.0": "d70b72b8ff9932e3953de3fbcf7690ca6174a30c9a48bd236b4aa743229c2cfb", "https://esm.sh/v135/hast-util-to-jsx-runtime@2.3.0/denonext/hast-util-to-jsx-runtime.bundle.mjs": "678749ee55e8610e6a2604c3f4cf2b9a173f7cecb640cd14c76b9dce3b6a7b87", "https://esm.sh/v135/hast-util-to-jsx-runtime@2.3.0/denonext/hast-util-to-jsx-runtime.mjs": "c94c36c11225b1d6f36dc7e3f13597a223058510eceb11fa97b844a3bd176fc4", "https://esm.sh/v135/hast-util-to-jsx-runtime@2.3.0?bundle": "cf9778fcf730b57bafbb99cd2ff4c76f82ea834748677cf3bb5d3fd296a15df9", "https://esm.sh/v135/hast-util-to-string@3.0.0": "efe413bc8cc4a67ac6b84b46e2fc2b0a79e4d7e4a31707cc8e60fab683b71080", "https://esm.sh/v135/hast-util-to-string@3.0.0/denonext/hast-util-to-string.mjs": "4f7c061733fa8e99e3055e443c09a8d4e7f6e95ccd7a06b61d38682989bf6ba8", "https://esm.sh/v135/hast-util-whitespace@3.0.0/denonext/hast-util-whitespace.mjs": "b2988a87d03b42636bca6ebee778326993a23953ba6638973be17ce03100a357", "https://esm.sh/v135/inline-style-parser@0.2.2/denonext/inline-style-parser.mjs": "6b516634a2a716b57fa335bdaf9910c568a01330bfb7686ca534228aff59149e", "https://esm.sh/v135/mdast-util-from-markdown@2.0.0": "6faa1f66f444b738c9cf8a0e97084ff0ab08008e0236379c1f25c250dd8457f1", "https://esm.sh/v135/mdast-util-from-markdown@2.0.0/denonext/mdast-util-from-markdown.bundle.mjs": "df1b3422a8b65ba9b34a1ff13c48f4b4838e31abfe2b959f21d1d72aa9b8c576", "https://esm.sh/v135/mdast-util-from-markdown@2.0.0/denonext/mdast-util-from-markdown.mjs": "30a0b1f34afa2c946dc1b401a8f42d7e3cc85a9c5b77ce95276f028b24c10fcf", "https://esm.sh/v135/mdast-util-from-markdown@2.0.0?bundle": "78b9052f4160970c245355728fdb09133ecd8ba65b0562989b1312932bac14eb", "https://esm.sh/v135/mdast-util-to-hast@13.1.0": "3a712fec5d7f4696ec135556925c8c2f7480b21dc39bd96077550d06220d2ba8", "https://esm.sh/v135/mdast-util-to-hast@13.1.0/denonext/mdast-util-to-hast.bundle.mjs": "98233d354e40ecc412381732a5a6c907d9722bcc94dd955e6afad647170dbe37", "https://esm.sh/v135/mdast-util-to-hast@13.1.0/denonext/mdast-util-to-hast.mjs": "e6ab97ff3f6c94f6c7ccaba485dac8a4fdd5edae1b311ae295b409b462ff5001", "https://esm.sh/v135/mdast-util-to-hast@13.1.0?bundle": "ee4ad3ffeaa1df751318c7d17c17b7f52e22f7e0e01c0c4538a60dc68af015e6", "https://esm.sh/v135/mdast-util-to-string@4.0.0/denonext/mdast-util-to-string.mjs": "eda9725fc0c7dc0e7b56998d2d8e4f29312cc5493cb7834c70f32fab2609103b", "https://esm.sh/v135/mdast-util-toc@7.0.0": "b4628c5babae460fa3452c52fe2f5aa810b2790dd74a6606784febbe0cad6ce6", "https://esm.sh/v135/mdast-util-toc@7.0.0/denonext/mdast-util-toc.mjs": "533c8f1317129350db102e9116b48b03e12e327a203852bb3d16d5ffb217d07c", "https://esm.sh/v135/micromark-core-commonmark@2.0.0/denonext/micromark-core-commonmark.mjs": "29686a813f2fa7fc1801c9c6142f71e32e605e6cf8bb8a9afeab78c814f0216c", "https://esm.sh/v135/micromark-factory-destination@2.0.0/denonext/micromark-factory-destination.mjs": "84dadab4182836ff8c4437e9a384a6e3488496848641c9868334d8a6b7658331", "https://esm.sh/v135/micromark-factory-label@2.0.0/denonext/micromark-factory-label.mjs": "0d4877dbb95c2bf635d48d8d44a243ab0c6830f68c76289c9d92730871b88170", "https://esm.sh/v135/micromark-factory-space@2.0.0/denonext/micromark-factory-space.mjs": "1ac7c90dec53f7f634767c5470c2dcf204f4df99ec318a27832786153d5c8110", "https://esm.sh/v135/micromark-factory-title@2.0.0/denonext/micromark-factory-title.mjs": "1b202816c09c57894c8e254962ffbd8ad559439b0eb90ff0eca743f0dbfff470", "https://esm.sh/v135/micromark-factory-whitespace@2.0.0/denonext/micromark-factory-whitespace.mjs": "f85efacaec053453a9445b4147d2fb7ce02c1d083f0b0da9a730a112ff934d9e", "https://esm.sh/v135/micromark-util-character@2.0.1/denonext/micromark-util-character.mjs": "18b451d148e1ccc3a9b18e5c4061d44a0485e8ec65ad805d20b2950a51c7213b", "https://esm.sh/v135/micromark-util-chunked@2.0.0/denonext/micromark-util-chunked.mjs": "531cf323ba53649fdc30cd39ebba54253dfd847a4b23f806058ecc6cf67bca69", "https://esm.sh/v135/micromark-util-classify-character@2.0.0/denonext/micromark-util-classify-character.mjs": "7e78c1341df2227c29cf5125c17f29bec3887bf8a3178476e129740271bdbd96", "https://esm.sh/v135/micromark-util-combine-extensions@2.0.0/denonext/micromark-util-combine-extensions.mjs": "68268c6cb6119bc8b0865156e81a360a3b94cd73bddbb9a2a33eda627e51573a", "https://esm.sh/v135/micromark-util-decode-numeric-character-reference@2.0.1/denonext/micromark-util-decode-numeric-character-reference.mjs": "284addb1c2303e02ca074d6a5e529c8c9c3cdb58b6815669e2ec65a2f717cf28", "https://esm.sh/v135/micromark-util-decode-string@2.0.0/denonext/micromark-util-decode-string.mjs": "c9abaf0b645a2ca8dd0a8d988a7a25173f4bc5e46154d2875890507c0d2e5a51", "https://esm.sh/v135/micromark-util-encode@2.0.0/denonext/micromark-util-encode.mjs": "6077703d774b2fd968ef53977add5d5d1e39ca0db74c5ee4359c540a5febcf48", "https://esm.sh/v135/micromark-util-html-tag-name@2.0.0/denonext/micromark-util-html-tag-name.mjs": "a32f6a4aa82498405a88103fd5b0b2e27a8c7f27dc506862f993bf1a1f1716b6", "https://esm.sh/v135/micromark-util-normalize-identifier@2.0.0/denonext/micromark-util-normalize-identifier.mjs": "f5b933ea50544d63e505ef11b7f257b97c5056e06417bac15ec02d3f00174c0e", "https://esm.sh/v135/micromark-util-resolve-all@2.0.0/denonext/micromark-util-resolve-all.mjs": "c11d87d63d808a26231323012295490931159830a66c00854693ec9279fa09fd", "https://esm.sh/v135/micromark-util-sanitize-uri@2.0.0/denonext/micromark-util-sanitize-uri.mjs": "cde22cced5a18a41dcdacbad2cc9e6fc930450118bff7dd764e60eea4aa6c5b5", "https://esm.sh/v135/micromark-util-subtokenize@2.0.0/denonext/micromark-util-subtokenize.mjs": "670326123b1f9d91218cee035248437b97e5b6828f1d1eb01d40bc46f89bdc64", "https://esm.sh/v135/micromark@4.0.0/denonext/micromark.mjs": "dc73ed793c5bbc49ad7201a326fc724d08bc94372a291c184167b22c4edc320d", "https://esm.sh/v135/preact-render-to-string@6.4.1": "a9ca466e5daf03595e041d96829c74f8e493f928e35a64b56365d952fda04ec3", "https://esm.sh/v135/preact-render-to-string@6.4.1/denonext/preact-render-to-string.mjs": "0226110b9ae616d3143c7ea00b822faa1cdd96588188fc3f28e2bf8ead94ba4f", "https://esm.sh/v135/preact@10.20.1": "5c0877793f441a58c8109d0f6b8e07cce501f3dc4389ee4405d87a50de44db3c", "https://esm.sh/v135/preact@10.20.1/compat.js": "aca08aaaf7cf8f09425ea84da121fc23a20fd36c3b431df1b2c58617c402a17b", "https://esm.sh/v135/preact@10.20.1/compat/server.js": "90c2f3a7a9d3fb9acd54f9553bb499b6f263b452a745217bb67523ec72b540c9", "https://esm.sh/v135/preact@10.20.1/hooks.js": "3c7307938d2318feb8fa1d5aed0a7550a25bff23434cc0fa76e036b80d877e2a", "https://esm.sh/v135/property-information@6.4.0/denonext/property-information.mjs": "8a61ad4cc589e3a30c752bd2eea7703cf286139c919f55f4fd289b90a7ac65a9", "https://esm.sh/v135/react-dom@18.2.0/denonext/server.js": "ead88af18fb70a507ccab7bc02732e9d225ef224a6de05f4829605008e796750", "https://esm.sh/v135/react-dom@18.2.0/server": "4e27b938451e1f25855754fe5149dd13f554ca75f3c5b387eb453144539c3dc7", "https://esm.sh/v135/react@18.2.0": "04ad7dc6d11fa27b24c136686a334ecdd19e972fae627cd98cbdc13cdac238c2", "https://esm.sh/v135/space-separated-tokens@2.0.2/denonext/space-separated-tokens.mjs": "f30773a9959cacfe7511c250e5d125a9f88ee00d3aef6e87b4d17fe49806b276", "https://esm.sh/v135/style-to-object@1.0.5/denonext/style-to-object.mjs": "fa46c0fbe36f636aec3f7a3f5af231c37b9265a444c343cd3067ec2d214c18d0", "https://esm.sh/v135/trim-lines@3.0.1/denonext/trim-lines.mjs": "f01a20253341eb2554f307ab05bc9cd93d6f33bcbb24fde2fc9fcd857564283e", "https://esm.sh/v135/unist-util-is@6.0.0/denonext/unist-util-is.mjs": "d92da46b3a1084450f150cc06c02f3bf85b93ab4c4b43a960d72a4f5678e95cc", "https://esm.sh/v135/unist-util-position@5.0.0/denonext/unist-util-position.mjs": "aaef05774a54f2b84400e98325219e2ba6cf966e318173bcd895647c56bb8871", "https://esm.sh/v135/unist-util-stringify-position@4.0.0/denonext/unist-util-stringify-position.mjs": "dabd32cb2b590bbb077fc6f6591a2e065cffd6c55646ba383455926a27ea64d7", "https://esm.sh/v135/unist-util-visit-parents@6.0.1/denonext/do-not-use-color.js": "a1c0a6b93471dd4ed996804dd8a2b9f753c83c4a2da98373253e6b312c8492e2", "https://esm.sh/v135/unist-util-visit-parents@6.0.1/denonext/unist-util-visit-parents.mjs": "5f7ececae47bea6d87b7e323153a7415ad8f299dc42e61aefda6d28eaf264c64", "https://esm.sh/v135/unist-util-visit@5.0.0": "39c6a28445ca31c6ad1e97c663c9d6f86d8820a2b5893c77e2d363cb630c8dc5", "https://esm.sh/v135/unist-util-visit@5.0.0/denonext/unist-util-visit.mjs": "6c1b5b3d517cc6dbc88406b2dbab1735d503a797e994dbd4a89f3764098318f7", "https://esm.sh/v135/vfile-message@4.0.2/denonext/vfile-message.mjs": "efc85b18bedda337fb1c20cdc452fac3addac32ee55948cebf2845396ae641ac" } }
-
-
-
@@ -0,0 +1,5 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 export * from "https://deno.land/x/nano_jsx@v0.1.0/jsx-runtime/index.ts";
-
-
-
@@ -0,0 +1,5 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 export * from "https://deno.land/x/nano_jsx@v0.1.0/mod.ts";
-
-
-
@@ -0,0 +1,5 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 export * from "https://esm.sh/v135/@shelf/fast-uslug@1.0.0";
-
-
-
@@ -0,0 +1,5 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 export * from "https://esm.sh/v135/hast-util-is-element@3.0.0";
-
-
-
@@ -0,0 +1,5 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 export * from "https://esm.sh/v135/hast-util-to-jsx-runtime@2.3.0";
-
-
-
@@ -0,0 +1,5 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 export * from "https://esm.sh/v135/hast-util-to-string@3.0.0";
-
-
-
@@ -0,0 +1,5 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 export * from "https://esm.sh/v135/@types/hast@3.0.4/index.d.ts";
-
-
-
@@ -0,0 +1,5 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 export * from "https://esm.sh/v135/mdast-util-from-markdown@2.0.0";
-
-
-
@@ -0,0 +1,5 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 export * from "https://esm.sh/v135/mdast-util-to-hast@13.1.0";
-
-
-
@@ -0,0 +1,5 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 export * from "https://esm.sh/v135/@types/mdast@4.0.3/index.d.ts";
-
-
-
@@ -0,0 +1,5 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 export * from "https://esm.sh/v135/unist-util-visit@5.0.0";
-
-
docs/build.ts (new)
-
@@ -0,0 +1,46 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 import { DenoFsReader } from "../filesystem_reader/deno_fs.ts"; import { DenoFsWriter } from "../filesystem_writer/deno_fs.ts"; import { SingleLocaleTreeBuilder } from "../tree_builder/single_locale_tree_builder.ts"; import { VaultParser } from "../metadata_parser/vault_parser.ts"; import { DefaultThemeBuilder } from "../page_builder/default_theme/builder.tsx"; const outDir = new URL("./.dist", import.meta.url); await Deno.permissions.request({ name: "write", path: outDir, }); const srcDir = new URL(".", import.meta.url); await Deno.permissions.request({ name: "read", path: srcDir, }); await Deno.mkdir(outDir, { recursive: true }); const fileSystemReader = new DenoFsReader(srcDir); const fileSystemWriter = new DenoFsWriter(outDir); const treeBuilder = new SingleLocaleTreeBuilder({ locale: "en", ignore(node) { return node.name.startsWith("."); }, }); const metadataParser = new VaultParser(); const pageBuilder = new DefaultThemeBuilder("© 2024 Shota FUJI"); const documentTree = await treeBuilder.build({ fileSystemReader, metadataParser, }); await pageBuilder.build({ documentTree, fileSystemReader, fileSystemWriter, });
-
-
-
@@ -0,0 +1,119 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 /** @jsx h */ import { h, renderSSR } from "../../deps/deno.land/x/nano_jsx/mod.ts"; import { fromMarkdown } from "../../deps/esm.sh/mdast-util-from-markdown/mod.ts"; import type { Document, DocumentDirectory, DocumentTree, } from "../../tree_builder/interface.ts"; import type { BuildParameters, PageBuilder } from "../interface.ts"; import * as css from "./css.ts"; import * as Html from "./components/html.tsx"; import { PathResolverProvider } from "./contexts/path_resolver.tsx"; interface InnerBuildParameters { items: ReadonlyArray<DocumentDirectory | Document>; tree: DocumentTree; locale: string; pathPrefix?: readonly string[]; buildParameters: Omit<BuildParameters, "documentTree">; } export class DefaultThemeBuilder implements PageBuilder { #copyright: string; constructor(copyright: string) { this.#copyright = copyright; } async build( { documentTree, fileSystemReader, fileSystemWriter }: BuildParameters, ) { const styles = css.serialize( Html.styles, ); await fileSystemWriter.write( ["assets", "global.css"], new TextEncoder().encode(styles), ); for (const [locale, items] of documentTree.locales) { await this.#buildLocale({ items, tree: documentTree, locale, pathPrefix: locale === documentTree.defaultLocale ? [] : [locale], buildParameters: { fileSystemWriter, fileSystemReader }, }); } } async #buildLocale( { items, tree, locale, pathPrefix = [], buildParameters }: InnerBuildParameters, ): Promise<void> { const { fileSystemWriter } = buildParameters; for (const item of items) { if ("file" in item) { const content = await item.file.read(); if (item.file.name.endsWith(".md")) { const html = "<!DOCTYPE html>" + renderSSR( () => ( // Adds 1 to depth due to `<name>/index.html` conversion. <PathResolverProvider depth={pathPrefix.length + 1}> <Html.View tree={tree} content={fromMarkdown(content)} document={item} locale={locale} copyright={this.#copyright} /> </PathResolverProvider> ), ); const enc = new TextEncoder(); await fileSystemWriter.write([ ...pathPrefix, item.file.name.replace(/\.md$/, ""), "index.html", ], enc.encode(html)); } if (item.file.name.endsWith(".canvas")) { // TODO: Proper logging console.warn( "Default theme page builder does not support Canvas yet.", ); } continue; } await this.#buildLocale({ items: item.entries, tree, locale, pathPrefix: [...pathPrefix, item.directory.name], buildParameters, }); } } }
-
-
-
@@ -0,0 +1,249 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 import { css } from "../css.ts"; export const globalStyles = css` /* Variables */ :root { font-size: 1em; --baseline: 1.75; line-height: var(--baseline); --color-primary: rgb(217, 59, 133); --color-bg: #fafafa; --color-bg-accent: #eaeaea; --color-fg: #333; --color-fg-sub: #534c37; --color-fg-light: #c5c5c5; --color-border: #b4af9d; color: var(--color-fg); } @media (prefers-color-scheme: dark) { :root { --color-bg: #222228; --color-bg-accent: #323135; --color-fg: #fafafa; --color-fg-sub: #f3edd9; --color-fg-light: #c5c5c5; --color-border: #b4af9d; } } /* Elements */ html { font-family: "Inter", sans-serif; } html[lang="ja"] { font-family: "Inter", "Noto Sans JP", sans-serif; } body { margin: 0; line-height: calc(var(--baseline) * 1rem); background: var(--color-bg); } *, ::before, ::after { box-sizing: border-box; } a { color: var(--color-fg-sub); font-weight: 500; text-decoration: underline; transition: color 0.15s ease; } a:hover { color: var(--color-primary); } p { margin: 0; margin-top: calc(var(--baseline) * 1rem); } pre { margin: 0; margin-top: calc(var(--baseline) * 1rem) !important; padding: calc(var(--baseline) * 1rem) 1em !important; line-height: calc(var(--baseline) * 1rem); max-width: 100%; font-size: 1rem; background-color: var(--color-fg); color: var(--color-bg); border-radius: calc(1rem / 4); overflow-x: auto; } pre > code { all: unset; } code { margin: 0 0.2em; padding: calc(1rem / 4); background-color: var(--color-bg-accent); color: var(--color-fg-sub); border-radius: calc(1rem / 4); /* NOTE: Prism.js's theme css automatically set annoying props */ font-family: "Ubuntu Mono", monospace !important; text-shadow: none !important; line-height: 1 !important; tab-size: unset !important; } pre > code .token.comment { font-style: italic; } a, time, span, code, sup, small, s, b, i { line-height: 1; } button { font-family: inherit; } s, del { color: var(--color-fg-sub); text-decoration: line-through; } b { font-weight: bold; } i { font-style: italic; } ul { margin: 0; margin-top: calc(var(--baseline) * 1rem); padding-left: 1.5em; } ul ul { margin-top: 0; } h1, h2, h3 { font-weight: 700; color: var(--color-fg-sub); } h1 { margin: 0; margin-top: calc(var(--baseline) * 2rem); line-height: calc(var(--baseline) * 2rem); } h2 { margin: 0; margin-top: calc(var(--baseline) * 2rem); } h3, h4, h5, h6 { margin: 0; margin-top: calc(var(--baseline) * 1rem); font-weight: 600; } table { border-spacing: 0; margin: 0; margin-top: calc(var(--baseline) * 0.5rem); width: 100%; } thead { background-color: var(--color-bg-accent); } th { font-weight: 500; padding: calc(var(--baseline) * 0.25rem) 1em; } td { padding: calc(var(--baseline) * 0.5rem) 1em; } tbody td { position: relative; } tbody td::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; border-bottom: 1px solid var(--color-fg-light); } h1:hover > a[data-hash-link], h2:hover > a[data-hash-link], h3:hover > a[data-hash-link], h4:hover > a[data-hash-link], h5:hover > a[data-hash-link], h6:hover > a[data-hash-link] { opacity: 1; } a[data-hash-link] { display: inline-block; margin-left: -1em; padding-right: 0.3em; text-decoration: none; opacity: 0; } a[data-hash-link]:hover { text-decoration: underline; } a[data-hash-link]:focus { opacity: 1; } img { max-width: 100%; box-shadow: 0 0 10px rgba(0, 0, 0, 0.05); } img:not(:first-child) { margin-top: calc(var(--baseline) * 1rem); } hr { margin: 0; margin-top: calc(var(--baseline) * 1rem); } `;
-
-
-
@@ -0,0 +1,118 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 /** @jsx h */ import { h } from "../../../deps/deno.land/x/nano_jsx/mod.ts"; import { Fragment, jsx, jsxs, } from "../../../deps/deno.land/x/nano_jsx/jsx-runtime/index.ts"; import type * as Mdast from "../../../deps/esm.sh/mdast/types.ts"; import { toHast } from "../../../deps/esm.sh/mdast-util-to-hast/mod.ts"; import { toJsxRuntime } from "../../../deps/esm.sh/hast-util-to-jsx-runtime/mod.ts"; import type { Document, DocumentTree, } from "../../../tree_builder/interface.ts"; import { usePathResolver } from "../contexts/path_resolver.tsx"; import * as css from "../css.ts"; import { globalStyles } from "./global_styles.ts"; import { mapTocItem, tocMut } from "../hast/hast_util_toc_mut.ts"; import * as DocumentTreeUI from "./organisms/document_tree.tsx"; import * as Footer from "./organisms/footer.tsx"; import * as Toc from "./organisms/toc.tsx"; import * as SiteLayout from "./templates/site_layout.tsx"; function toNode(hast: ReturnType<typeof toHast>) { return toJsxRuntime(hast, { Fragment, // @ts-ignore: library type being unnecessary narrow jsx, // @ts-ignore: library type being unnecessary narrow jsxs, }); } export const styles = css.join( globalStyles, DocumentTreeUI.styles, Footer.styles, SiteLayout.styles, Toc.styles, ); export interface ViewProps { document: Document; /** * Root document tree, for navigations and links. */ tree: DocumentTree; /** * The document's content HTML. */ content: Mdast.Root; locale: string; copyright: string; } export function View( { document, locale, content, tree, copyright }: ViewProps, ) { const path = usePathResolver(); const topLevelDocs = tree.locales.get(locale); if (!topLevelDocs) { const locales = Array.from(tree.locales.keys()); throw new Error( `Unknown locale: "${locale}" (available locales = ${locales.join(", ")})`, ); } const hast = toHast(content); const toc = tocMut(hast).map((item) => mapTocItem(item, (item) => toNode({ type: "root", children: item })) ); const contentNodes = toNode(hast); return ( <html lang={locale}> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>{document.metadata.title}</title> <link rel="stylesheet" href={path.resolve(["assets", "global.css"])} /> </head> <body> <SiteLayout.View aside={toc.length > 0 && <Toc.View toc={toc} />} nav={ <DocumentTreeUI.View tree={topLevelDocs} currentPath={document.file.path} /> } footer={<Footer.View copyright={copyright} />} > <h1>{document.metadata.title}</h1> {contentNodes} </SiteLayout.View> </body> </html> ); }
-
-
-
@@ -0,0 +1,95 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 /** @jsx h */ import { h } from "../../../../deps/deno.land/x/nano_jsx/mod.ts"; import type { Document, DocumentDirectory, } from "../../../../tree_builder/interface.ts"; import { css } from "../../css.ts"; import { usePathResolver } from "../../contexts/path_resolver.tsx"; const enum C { Root = "o-dt--root", List = "o-dt--list", Directory = "o-dt--dir", } export const styles = css` .${C.Root} { padding: calc(var(--baseline) * 0.25rem) 0.75em; font-size: 0.9em; } .${C.Root}, .${C.List} { list-style: none; } .${C.Directory} { cursor: pointer; } `; export interface ViewProps { tree: ReadonlyArray<Document | DocumentDirectory>; currentPath: readonly string[]; } export function View({ tree, currentPath }: ViewProps) { return ( <ul className={C.Root}> {tree.map((entry) => ( <Node value={entry} currentPath={currentPath} /> ))} </ul> ); } interface NodeProps { value: Document | DocumentDirectory; currentPath: readonly string[]; } function Node({ value, currentPath }: NodeProps) { const pathResolver = usePathResolver(); if ("file" in value) { const path = pathResolver.resolve([ ...value.file.path.slice(0, -1), value.file.name.replace(/\.md$/, ""), "", ]); return ( <li> <a href={path}>{value.metadata.title}</a> </li> ); } const defaultOpened = currentPath[0] === value.directory.name; return ( <li> <details className={C.Directory} open={defaultOpened ? "" : undefined}> <summary>{value.metadata.title}</summary> <ul className={C.List}> {value.entries.map((entry) => ( <Node value={entry} currentPath={currentPath.slice(1)} /> ))} </ul> </details> </li> ); }
-
-
-
@@ -0,0 +1,55 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 /** @jsx h */ import { h } from "../../../../deps/deno.land/x/nano_jsx/mod.ts"; import { css } from "../../css.ts"; const enum C { Root = "o-fo--root", Copyright = "o-fo--cpy", Links = "o-fo--links", } export const styles = css` .${C.Root} { display: flex; justify-content: space-between; align-items: center; gap: 2em; } .${C.Copyright} { font-size: 0.8em; } .${C.Links} { font-size: 0.9em; display: flex; gap: 0.25em 0.5em; justify-content: start; align-items: start; } `; export interface ViewProps { copyright: JSX.ElementChildrenAttribute["children"]; children?: JSX.ElementChildrenAttribute["children"]; } export function View({ copyright, children }: ViewProps) { return ( <div className={C.Root}> <small className={C.Copyright}>{copyright}</small> {children && ( <div className={C.Links}> {children} </div> )} </div> ); }
-
-
-
@@ -0,0 +1,47 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 /** @jsx h */ import { h } from "../../../../deps/deno.land/x/nano_jsx/mod.ts"; import { type TocItem } from "../../hast/hast_util_toc_mut.ts"; import { css } from "../../css.ts"; const enum C { Root = "o-toc--root", } export const styles = css` .${C.Root} { font-size: 0.8em; } `; export interface ViewProps { // nano-jsx does not ship any useful typings toc: readonly TocItem<unknown>[]; } export function View({ toc }: ViewProps) { return ( <div className={C.Root}> <Items toc={toc} /> </div> ); } export function Items({ toc }: ViewProps) { return ( <ul> {toc.map((item) => ( <li> <a href={`#${item.id}`}>{item.text}</a> {item.children.length > 0 && <Items toc={item.children} />} </li> ))} </ul> ); }
-
-
-
@@ -0,0 +1,151 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 /** @jsx h */ import { h } from "../../../../deps/deno.land/x/nano_jsx/mod.ts"; import { css } from "../../css.ts"; const enum C { Layout = "t-sl--root", NavBg = "t-sl--navbg", Header = "t-sl--head", Nav = "t-sl--nav", NavInner = "t-sl--nav-i", FooterBg = "t-sl--fbg", Footer = "t-sl--foot", Main = "t-sl--main", Aside = "t-sl--aside", AsideInner = "t-sl--aside-i", } export const styles = css` .${C.Layout} { display: grid; grid-template-columns: minmax(100vw, 1fr); min-height: 100vh; } .${C.Layout} > * { padding: calc(var(--baseline) * 1rem) 16px; } .${C.Layout} > * > :first-child { margin-block-start: 0; } .${C.NavBg} { grid-row: 1; grid-column: 1 / -1; margin-block-end: calc(var(--baseline) * 2rem); background-color: var(--color-bg-accent); } .${C.Header} { grid-row: 1; grid-column: 1; margin-block-end: calc(var(--baseline) * 2rem); } .${C.Nav} { grid-column: 1; } .${C.NavInner}, .${C.AsideInner} { position: sticky; top: calc(var(--baseline) * 1rem); opacity: 0.8; transition: opacity 0.2s ease; } .${C.NavInner}:hover { opacity: 1; } .${C.Main} { grid-column: 1 / -1; } .${C.Aside} { grid-column: 1 / -1; } .${C.FooterBg} { grid-row: 999; grid-column: 1 / -1; margin-block-start: calc(var(--baseline) * 2rem); background-color: var(--color-bg-accent); } .${C.Footer} { grid-row: 999; grid-column: 1; margin-block-start: calc(var(--baseline) * 2rem); color: var(--color-fg-sub); } @media (min-width: 700px) { .${C.Layout} { grid-template-columns: 200px minmax(0, 1fr); } .${C.Header}, .${C.Footer} { grid-column: 1 / -1; } } @media (min-width: 1000px) { .${C.Layout} { grid-template-columns: 1fr min(700px, 100%) 1fr; } .${C.Main}, .${C.Header}, .${C.Footer} { grid-column: 2; } .${C.Aside} { grid-column: 3; } .${C.NavInner}, .${C.AsideInner} { margin-inline-start: auto; margin-inline-end: 0; max-width: 400px; } } `; export interface ViewProps { children: JSX.ElementChildrenAttribute["children"]; nav: JSX.ElementChildrenAttribute["children"]; aside?: JSX.ElementChildrenAttribute["children"]; footer: JSX.ElementChildrenAttribute["children"]; } export function View({ children, nav, aside, footer }: ViewProps) { return ( <div className={C.Layout}> <div className={C.NavBg} /> <nav className={C.Nav}> <div className={C.NavInner}>{nav}</div> </nav> <main className={C.Main}>{children}</main> {aside && ( <aside className={C.Aside}> <div className={C.AsideInner}>{aside}</div> </aside> )} <div className={C.FooterBg} /> <footer className={C.Footer}>{footer}</footer> </div> ); }
-
-
-
@@ -0,0 +1,55 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 /** @jsx h */ import { createContext, h, useContext, } from "../../../deps/deno.land/x/nano_jsx/mod.ts"; interface PathResolver { resolve(path: readonly string[]): string; } const PathResolverContext = createContext({ resolve(path: readonly string[]) { return path.join("/"); }, }); export function usePathResolver(): PathResolver { return useContext(PathResolverContext); } export interface PathResolverProviderProps { /** * How deep the path from the root? * 0 for top-level documents. * For example, the depth for "foo/bar/baz.html" is 2. * * @default 0 */ depth?: number; children: JSX.ElementChildrenAttribute["children"]; } export function PathResolverProvider( { depth = 0, children }: PathResolverProviderProps, ) { const resolver: PathResolver = { resolve(path) { return Array.from({ length: depth }, () => "../").join("") + path.join("/"); }, }; return ( <PathResolverContext.Provider value={resolver}> {children} </PathResolverContext.Provider> ); }
-
-
-
@@ -0,0 +1,59 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 interface Css { readonly chunks: ReadonlySet<string>; } /** * Just for syntax highlighting. */ export function css( tmpl: readonly string[], ...params: readonly string[] ): Css { const code = cssTmplBuilder(tmpl, params); return { chunks: new Set([code]), }; } function cssTmplBuilder( tmpl: readonly string[], params: readonly string[], ): string { if (!tmpl.length) { return ""; } const [thead, ...trest] = tmpl; if (!params.length || trest.length === 0) { return thead; } const [phead, ...prest] = params; return thead + phead + cssTmplBuilder(trest, prest); } export function join(...units: readonly Css[]): Css { const result = new Set<string>(); // `Set.prototype.union` method is not widely implemented yet. for (const unit of units) { for (const chunk of unit.chunks) { result.add(chunk); } } return { chunks: result, }; } export function serialize(css: Css): string { return Array.from(css.chunks.values()).join("\n"); }
-
-
-
@@ -0,0 +1,102 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 import type * as Hast from "../../../deps/esm.sh/hast/types.ts"; import { SKIP, visit } from "../../../deps/esm.sh/unist-util-visit/mod.ts"; import { fastUslug } from "../../../deps/esm.sh/@shelf/fast-uslug/mod.ts"; import { isElement } from "../../../deps/esm.sh/hast-util-is-element/mod.ts"; import { toString } from "../../../deps/esm.sh/hast-util-to-string/mod.ts"; export interface TocItem<Node = Hast.ElementContent[]> { id: string; text: Node; level: number; children: TocItem<Node>[]; } export function mapTocItem<A, B>(item: TocItem<A>, f: (a: A) => B): TocItem<B> { return { id: item.id, level: item.level, text: f(item.text), children: item.children.map((child) => mapTocItem(child, f)), }; } function getParent(level: number, items: readonly TocItem[]): TocItem | null { if (!items.length) { return null; } const [head] = items; if (head.level >= level) { return null; } if (head.level === level + 1) { return items[items.length - 1]; } return getParent(level, items[items.length - 1].children); } /** * Mutates given Hast by adding ID to headings and Returns table of contents. */ export function tocMut<Node extends Hast.Node>( hast: Node, ): readonly TocItem<Hast.ElementContent[]>[] { const items: TocItem[] = []; visit(hast, (node) => { if (!isElement(node)) { return false; } switch (node.tagName) { case "h1": case "h2": case "h3": case "h4": case "h5": case "h6": return true; default: return false; } }, (node) => { if (!isElement(node)) { return SKIP; } const levelMatch = node.tagName.match(/^h(\d)$/); if (!levelMatch) { return SKIP; } const level = parseInt(levelMatch[1]); if (!Number.isFinite(level)) { return SKIP; } let id = node.properties.id; if (typeof id !== "string") { id = fastUslug(toString(node), { lower: false, }); node.properties.id = id; } const parent = getParent(level, items)?.children || items; parent.push({ id, level, text: node.children, children: [], }); }); return items; }
-
-
-
@@ -0,0 +1,20 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 import type { DocumentTree } from "../tree_builder/interface.ts"; import type { FileSystemWriter } from "../filesystem_writer/interface.ts"; import type { FileSystemReader } from "../filesystem_reader/interface.ts"; export interface BuildParameters { readonly documentTree: DocumentTree; readonly fileSystemReader: FileSystemReader; readonly fileSystemWriter: FileSystemWriter; } export interface PageBuilder { /** * Builds pages from document tree then write them to the filesystem. */ build(params: BuildParameters): Promise<void>; }
-