diff --git a/.crow/build.yml b/.crow/build.yml new file mode 100644 index 0000000..9163a4d --- /dev/null +++ b/.crow/build.yml @@ -0,0 +1,63 @@ +when: + - event: tag + +clone: + git: + image: codefloe.com/crow-plugins/clone:1.1.0 + settings: + tags: true + +variables: + - &zig_image 'ghcr.io/rust-cross/cargo-zigbuild:0.23' + +steps: + - name: build-linux-x86_64 + image: *zig_image + commands: + # - zig build -Dtarget=x86_64-linux-musl -Doptimize=ReleaseSafe --prefix zig-out-linux-x86_64 + - zig build -Dtarget=x86_64-linux-musl --prefix zig-out-linux-x86_64 + - cp zig-out-linux-x86_64/bin/htmlua htmlua-linux-x86_64 + - cp zig-out-linux-x86_64/bin/htmlua-cgi htmlua-cgi-linux-x86_64 + + - name: build-linux-aarch64 + image: *zig_image + commands: + # - zig build -Dtarget=aarch64-linux-musl -Doptimize=ReleaseSafe --prefix zig-out-linux-aarch64 + - zig build -Dtarget=aarch64-linux-musl --prefix zig-out-linux-aarch64 + - cp zig-out-linux-aarch64/bin/htmlua htmlua-linux-aarch64 + - cp zig-out-linux-aarch64/bin/htmlua-cgi htmlua-cgi-linux-aarch64 + + - name: build-macos-x86_64 + image: *zig_image + commands: + # - zig build -Dtarget=x86_64-macos -Doptimize=ReleaseSafe --prefix zig-out-macos-x86_64 --sysroot /opt/MacOSX11.3.sdk + - zig build -Dtarget=x86_64-macos --prefix zig-out-macos-x86_64 --sysroot /opt/MacOSX11.3.sdk + - cp zig-out-macos-x86_64/bin/htmlua htmlua-macos-x86_64 + - cp zig-out-macos-x86_64/bin/htmlua-cgi htmlua-cgi-macos-x86_64 + + - name: build-macos-aarch64 + image: *zig_image + commands: + # - zig build -Dtarget=aarch64-macos -Doptimize=ReleaseSafe --prefix zig-out-macos-aarch64 --sysroot /opt/MacOSX11.3.sdk + - zig build -Dtarget=aarch64-macos --prefix zig-out-macos-aarch64 --sysroot /opt/MacOSX11.3.sdk + - cp zig-out-macos-aarch64/bin/htmlua htmlua-macos-aarch64 + - cp zig-out-macos-aarch64/bin/htmlua-cgi htmlua-cgi-macos-aarch64 + + + - name: release + image: woodpeckerci/plugin-release + depends_on: [build-linux-x86_64, build-linux-aarch64, build-macos-x86_64, build-macos-aarch64] + settings: + api_key: + from_secret: forgejo_token + files: + - htmlua-linux-x86_64 + - htmlua-linux-aarch64 + - htmlua-macos-x86_64 + - htmlua-macos-aarch64 + - htmlua-cgi-linux-x86_64 + - htmlua-cgi-linux-aarch64 + - htmlua-cgi-macos-x86_64 + - htmlua-cgi-macos-aarch64 + checksum: sha256 + file_exists: overwrite diff --git a/.crow/release.yml b/.crow/release.yml new file mode 100644 index 0000000..3770f56 --- /dev/null +++ b/.crow/release.yml @@ -0,0 +1,23 @@ +# This file is a bit of a hack in order to run the real release CI +when: + - event: push + branch: ${CI_REPO_DEFAULT_BRANCH} + +clone: + git: + image: codefloe.com/crow-plugins/clone:1.1.0 + settings: + tags: true + + +steps: + - name: retag-latest + image: alpine:3.20 + environment: + FORGEJO_TOKEN: + from_secret: forgejo_token + commands: + - apk add --no-cache git + - git remote set-url origin "https://oauth2:$${FORGEJO_TOKEN}@$${CI_FORGE_URL#https://}/$${CI_REPO}.git" + - git tag -f latest + - git push -f origin latest diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index ad67955..8493d22 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1,19 @@ -# Generated by Cargo -# will have compiled files and executables -debug -target +# This file is for zig-specific build artifacts. +# If you have OS-specific or editor-specific files to ignore, +# such as *.swp or .DS_Store, put those in your global +# ~/.gitignore and put this in your ~/.gitconfig: +# +# [core] +# excludesfile = ~/.gitignore +# +# Cheers! +# -andrewrk -# These are backup files generated by rustfmt -**/*.rs.bk - -# MSVC Windows builds of rustc generate these, which store debugging information -*.pdb - -# Generated by cargo mutants -# Contains mutation testing data -**/mutants.out*/ - -# RustRover -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ +.zig-cache/ +zig-out/ +zig-pkg/ +/release/ +/debug/ +/build/ +/build-*/ +/docgen_tmp/ diff --git a/.rustfmt.toml b/.rustfmt.toml deleted file mode 100644 index 25b733d..0000000 --- a/.rustfmt.toml +++ /dev/null @@ -1,13 +0,0 @@ -unstable_features = true - -max_width = 120 -fn_params_layout = "Compressed" -fn_single_line = true -fn_call_width = 120 -where_single_line = true -brace_style = "PreferSameLine" -blank_lines_upper_bound = 5 -combine_control_expr = false -wrap_comments = false -group_imports = "StdExternalCrate" -imports_granularity = "Crate" diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index d31c5bd..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,2934 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" - -[[package]] -name = "bstr" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" -dependencies = [ - "memchr", - "regex-automata", - "serde", -] - -[[package]] -name = "bumpalo" -version = "3.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" - -[[package]] -name = "cc" -version = "1.2.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" -dependencies = [ - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "cssparser" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa 0.4.8", - "matches", - "phf 0.8.0", - "proc-macro2", - "quote", - "smallvec", - "syn 1.0.109", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote", - "syn 2.0.104", -] - -[[package]] -name = "deranged" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "derive_more" -version = "0.99.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.104", -] - -[[package]] -name = "dirs" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.60.2", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "dtoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" - -[[package]] -name = "dtoa-short" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" -dependencies = [ - "dtoa", -] - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "env_home" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "erased-serde" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" -dependencies = [ - "serde", - "typeid", -] - -[[package]] -name = "errno" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" -dependencies = [ - "libc", - "windows-sys 0.60.2", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "flate2" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "getopts" -version = "0.2.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "h2" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap 2.10.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" - -[[package]] -name = "html5ever" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" -dependencies = [ - "log", - "mac", - "markup5ever 0.11.0", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "html5ever" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55d958c2f74b664487a2035fe1dadb032c48718a03b63f3ab0b8537db8549ed4" -dependencies = [ - "log", - "markup5ever 0.35.0", - "match_token", -] - -[[package]] -name = "htmlua-apache-cgi" -version = "0.1.0" -dependencies = [ - "htmlua-parser", - "kuchikiki", -] - -[[package]] -name = "htmlua-parser" -version = "0.1.0" -dependencies = [ - "anyhow", - "dirs", - "html5ever 0.35.0", - "httptest", - "kuchikiki", - "markup5ever 0.11.0", - "mlua", - "pulldown-cmark", - "reqwest", - "serde", - "serde_json", - "syntect", - "tendril", - "toml", -] - -[[package]] -name = "htmlua-server" -version = "0.1.0" - -[[package]] -name = "http" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" -dependencies = [ - "bytes", - "fnv", - "itoa 1.0.15", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "httptest" -version = "0.16.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde82de3ef9bd882493c6a5edbc3363ad928925b30ccecc0f2ddeb42601b3021" -dependencies = [ - "bstr", - "bytes", - "crossbeam-channel", - "form_urlencoded", - "futures", - "http", - "http-body-util", - "hyper", - "hyper-util", - "log", - "once_cell", - "regex", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", -] - -[[package]] -name = "hyper" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa 1.0.15", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" -dependencies = [ - "http", - "hyper", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f66d5bd4c6f02bf0542fad85d626775bab9258cf795a4256dcaf3161114d1df" -dependencies = [ - "base64", - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http", - "http-body", - "hyper", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2", - "system-configuration", - "tokio", - "tower-service", - "tracing", - "windows-registry", -] - -[[package]] -name = "icu_collections" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" - -[[package]] -name = "icu_properties" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "potential_utf", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" - -[[package]] -name = "icu_provider" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" -dependencies = [ - "displaydoc", - "icu_locale_core", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" -dependencies = [ - "equivalent", - "hashbrown 0.15.4", -] - -[[package]] -name = "io-uring" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" -dependencies = [ - "bitflags 2.9.1", - "cfg-if", - "libc", -] - -[[package]] -name = "ipnet" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "iri-string" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "kuchikiki" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" -dependencies = [ - "cssparser", - "html5ever 0.26.0", - "indexmap 1.9.3", - "matches", - "selectors", -] - -[[package]] -name = "libc" -version = "0.2.174" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" - -[[package]] -name = "libredox" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" -dependencies = [ - "bitflags 2.9.1", - "libc", -] - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] -name = "linux-raw-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" - -[[package]] -name = "litemap" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" - -[[package]] -name = "lock_api" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "lua-src" -version = "547.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edaf29e3517b49b8b746701e5648ccb5785cde1c119062cbabbc5d5cd115e42" -dependencies = [ - "cc", -] - -[[package]] -name = "luajit-src" -version = "210.5.12+a4f56a4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3a8e7962a5368d5f264d045a5a255e90f9aa3fc1941ae15a8d2940d42cac671" -dependencies = [ - "cc", - "which", -] - -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - -[[package]] -name = "markup5ever" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" -dependencies = [ - "log", - "phf 0.10.1", - "phf_codegen 0.10.0", - "string_cache", - "string_cache_codegen", - "tendril", -] - -[[package]] -name = "markup5ever" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "311fe69c934650f8f19652b3946075f0fc41ad8757dbb68f1ca14e7900ecc1c3" -dependencies = [ - "log", - "tendril", - "web_atoms", -] - -[[package]] -name = "match_token" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - -[[package]] -name = "memchr" -version = "2.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - -[[package]] -name = "mio" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" -dependencies = [ - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", -] - -[[package]] -name = "mlua" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f5f8fbebc7db5f671671134b9321c4b9aa9adeafccfd9a8c020ae45c6a35d0" -dependencies = [ - "anyhow", - "bstr", - "either", - "erased-serde", - "mlua-sys", - "num-traits", - "parking_lot", - "rustc-hash", - "rustversion", - "serde", - "serde-value", -] - -[[package]] -name = "mlua-sys" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380c1f7e2099cafcf40e51d3a9f20a346977587aa4d012eae1f043149a728a93" -dependencies = [ - "cc", - "cfg-if", - "lua-src", - "luajit-src", - "pkg-config", -] - -[[package]] -name = "native-tls" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "onig" -version = "6.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" -dependencies = [ - "bitflags 2.9.1", - "libc", - "once_cell", - "onig_sys", -] - -[[package]] -name = "onig_sys" -version = "69.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f86c6eef3d6df15f23bcfb6af487cbd2fed4e5581d58d5bf1f5f8b7f6727dc" -dependencies = [ - "cc", - "pkg-config", -] - -[[package]] -name = "openssl" -version = "0.10.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" -dependencies = [ - "bitflags 2.9.1", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-sys" -version = "0.9.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "ordered-float" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" -dependencies = [ - "num-traits", -] - -[[package]] -name = "parking_lot" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_macros", - "phf_shared 0.8.0", - "proc-macro-hack", -] - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_shared 0.10.0", -] - -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_shared 0.11.3", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", -] - -[[package]] -name = "phf_codegen" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", -] - -[[package]] -name = "phf_codegen" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", -] - -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared 0.11.3", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher 1.0.1", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "plist" -version = "1.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3af6b589e163c5a788fab00ce0c0366f6efbb9959c2f9874b224936af7fce7e1" -dependencies = [ - "base64", - "indexmap 2.10.0", - "quick-xml", - "serde", - "time", -] - -[[package]] -name = "potential_utf" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" -dependencies = [ - "zerovec", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - -[[package]] -name = "proc-macro2" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "pulldown-cmark" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0" -dependencies = [ - "bitflags 2.9.1", - "getopts", - "memchr", - "pulldown-cmark-escape", - "unicase", -] - -[[package]] -name = "pulldown-cmark-escape" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" - -[[package]] -name = "quick-xml" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8927b0664f5c5a98265138b7e3f90aa19a6b21353182469ace36d4ac527b7b1b" -dependencies = [ - "memchr", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.16", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "redox_syscall" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" -dependencies = [ - "bitflags 2.9.1", -] - -[[package]] -name = "redox_users" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" -dependencies = [ - "getrandom 0.2.16", - "libredox", - "thiserror 2.0.12", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "reqwest" -version = "0.12.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-tls", - "hyper-util", - "js-sys", - "log", - "mime", - "native-tls", - "percent-encoding", - "pin-project-lite", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-native-tls", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.16", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" - -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" -dependencies = [ - "bitflags 2.9.1", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustls" -version = "0.23.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1" -dependencies = [ - "once_cell", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pki-types" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" -dependencies = [ - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.9.1", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "selectors" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" -dependencies = [ - "bitflags 1.3.2", - "cssparser", - "derive_more", - "fxhash", - "log", - "matches", - "phf 0.8.0", - "phf_codegen 0.8.0", - "precomputed-hash", - "servo_arc", - "smallvec", - "thin-slice", -] - -[[package]] -name = "semver" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" - -[[package]] -name = "serde" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-value" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" -dependencies = [ - "ordered-float", - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "serde_json" -version = "1.0.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" -dependencies = [ - "itoa 1.0.15", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_spanned" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa 1.0.15", - "ryu", - "serde", -] - -[[package]] -name = "servo_arc" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" -dependencies = [ - "nodrop", - "stable_deref_trait", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "siphasher" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" - -[[package]] -name = "slab" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "string_cache" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" -dependencies = [ - "new_debug_unreachable", - "parking_lot", - "phf_shared 0.11.3", - "precomputed-hash", - "serde", -] - -[[package]] -name = "string_cache_codegen" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", -] - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[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.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "syntect" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1" -dependencies = [ - "bincode", - "bitflags 1.3.2", - "flate2", - "fnv", - "once_cell", - "onig", - "plist", - "regex-syntax", - "serde", - "serde_derive", - "serde_json", - "thiserror 1.0.69", - "walkdir", - "yaml-rust", -] - -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags 2.9.1", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "tempfile" -version = "3.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" -dependencies = [ - "fastrand", - "getrandom 0.3.3", - "once_cell", - "rustix", - "windows-sys 0.59.0", -] - -[[package]] -name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - -[[package]] -name = "thin-slice" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" -dependencies = [ - "thiserror-impl 2.0.12", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "time" -version = "0.3.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" -dependencies = [ - "deranged", - "itoa 1.0.15", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" - -[[package]] -name = "time-macros" -version = "0.2.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinystr" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tokio" -version = "1.46.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" -dependencies = [ - "backtrace", - "bytes", - "io-uring", - "libc", - "mio", - "pin-project-lite", - "slab", - "socket2", - "tokio-macros", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-macros" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed0aee96c12fa71097902e0bb061a5e1ebd766a6636bb605ba401c45c1650eac" -dependencies = [ - "indexmap 2.10.0", - "serde", - "serde_spanned", - "toml_datetime", - "toml_parser", - "toml_writer", - "winnow", -] - -[[package]] -name = "toml_datetime" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_parser" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30" -dependencies = [ - "winnow", -] - -[[package]] -name = "toml_writer" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" - -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-http" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" -dependencies = [ - "bitflags 2.9.1", - "bytes", - "futures-util", - "http", - "http-body", - "iri-string", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "typeid" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" - -[[package]] -name = "unicase" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "unicode-width" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.104", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "web-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web_atoms" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ffde1dc01240bdf9992e3205668b235e59421fd085e8a317ed98da0178d414" -dependencies = [ - "phf 0.11.3", - "phf_codegen 0.11.3", - "string_cache", - "string_cache_codegen", -] - -[[package]] -name = "which" -version = "7.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762" -dependencies = [ - "either", - "env_home", - "rustix", - "winsafe", -] - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-registry" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" -dependencies = [ - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.2", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - -[[package]] -name = "winnow" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" - -[[package]] -name = "winsafe" -version = "0.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" - -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.1", -] - -[[package]] -name = "writeable" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" - -[[package]] -name = "yaml-rust" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map", -] - -[[package]] -name = "yoke" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.8.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" - -[[package]] -name = "zerotrie" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index f64ae5e..0000000 --- a/Cargo.toml +++ /dev/null @@ -1,5 +0,0 @@ -[workspace] -members = [ "htmlua-apache-cgi","htmlua-parser", "htmlua-server"] -resolver = "2" - - diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5c5954d --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright 2026 Grace Yoder + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the “Software”), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9232026 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# HTMLua + +### An HTML templating engine with (not yet reimplemented) Lua scripting abilities + +See in action at [grace.pink](https://grace.pink/index.htmlua) + +This is currently an incomplete rewrite. If you want to have the old rust +version you are able to checkout the `rust` tag. + diff --git a/build.zig b/build.zig new file mode 100755 index 0000000..42d6c20 --- /dev/null +++ b/build.zig @@ -0,0 +1,112 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const ezts = b.dependency("eazy_zig_tree_sitter", .{ + .target = target, + .optimize = optimize, + .use_all_langs = true, + .use_third_party = true, + }); + + const ts = b.dependency("tree_sitter", .{ + .target = target, + .optimize = optimize, + }); + + const mod = b.addModule("htmlua", .{ + .root_source_file = b.path("src/root.zig"), + .target = target, + .imports = &.{ + .{ .name = "easy-zig-tree-sitter", .module = ezts.module("eazy_zig_tree_sitter") }, + .{ .name = "tree-sitter", .module = ts.module("tree_sitter") }, + }, + }); + + // Debug bin + const exe = b.addExecutable(.{ + .name = "htmlua", + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + .imports = &.{ + .{ .name = "htmlua", .module = mod }, + }, + }), + }); + + b.installArtifact(exe); + + const run_step = b.step("run", "Run the app"); + + const run_cmd = b.addRunArtifact(exe); + run_step.dependOn(&run_cmd.step); + + run_cmd.step.dependOn(b.getInstallStep()); + + if (b.args) |args| { + run_cmd.addArgs(args); + } + + // CGI bin + const cgi = b.addExecutable(.{ + .name = "htmlua-cgi", + .root_module = b.createModule(.{ + .root_source_file = b.path("src/cgi.zig"), + .target = target, + .optimize = optimize, + .imports = &.{ + .{ .name = "htmlua", .module = mod }, + }, + }), + }); + + b.installArtifact(cgi); + + const mod_tests = b.addTest(.{ + .root_module = mod, + }); + + const run_mod_tests = b.addRunArtifact(mod_tests); + + const exe_tests = b.addTest(.{ + .root_module = exe.root_module, + }); + + const run_exe_tests = b.addRunArtifact(exe_tests); + + const test_step = b.step("test", "Run tests"); + test_step.dependOn(&run_mod_tests.step); + test_step.dependOn(&run_exe_tests.step); + + // https://zigtools.org/zls/guides/build-on-save/ + const exe_check = b.addExecutable(.{ + .name = "htmlua", + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + .imports = &.{ + .{ .name = "htmlua", .module = mod }, + }, + }), + }); + const cgi_check = b.addExecutable(.{ + .name = "htmlua-cgi", + .root_module = b.createModule(.{ + .root_source_file = b.path("src/cgi.zig"), + .target = target, + .optimize = optimize, + .imports = &.{ + .{ .name = "htmlua", .module = mod }, + }, + }), + }); + + const check = b.step("check", "Check if htmlua compiles"); + check.dependOn(&exe_check.step); + check.dependOn(&cgi_check.step); +} diff --git a/build.zig.zon b/build.zig.zon new file mode 100755 index 0000000..297ddc1 --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,24 @@ +.{ + .name = .htmlua, + .version = "1.0.0-alpha", + .fingerprint = 0xb94bab7ca04adb0c, + .minimum_zig_version = "0.16.0", + .dependencies = .{ + .tree_sitter = .{ + .url = "git+https://github.com/tree-sitter/zig-tree-sitter.git#b562510b5563dcf3b7fcac4a5fe9d60834c84667", + .hash = "tree_sitter-0.26.0-8heIf-vDAQDh0HhAAUVwVZFmLrwSKMZl5gRaVFqtas0W", + }, + .eazy_zig_tree_sitter = .{ + .url = "git+https://git.gae.moe/grace/eazy-zig-tree-sitter.git#8d1fa80a0e225282f607a1e2b2504cfdbf427cfa", + .hash = "eazy_zig_tree_sitter-0.0.0-QEABqToEAwCwlPVt4G7QS6E6vicz4SISg8N93xRr8t8K", + }, + }, + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + "examples", + "LICENSE", + "README.md", + }, +} diff --git a/cspell.json b/cspell.json deleted file mode 100644 index 44ee262..0000000 --- a/cspell.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "words": [ - "htmlua", - "headermap", - "reqwest", - "includeelement", - "exportelement" - ], - "userWords": [ - "mlua" - ] -} \ No newline at end of file diff --git a/examples/a.htmlua b/examples/a.htmlua new file mode 100755 index 0000000..4857b50 --- /dev/null +++ b/examples/a.htmlua @@ -0,0 +1,3 @@ +

included file!

+ + diff --git a/examples/config.zon b/examples/config.zon new file mode 100755 index 0000000..2335fbe --- /dev/null +++ b/examples/config.zon @@ -0,0 +1,4 @@ +.{ + .component_path = "./examples", + .template_path = "./examples", +} diff --git a/examples/main.htmlua b/examples/main.htmlua new file mode 100755 index 0000000..d7827c2 --- /dev/null +++ b/examples/main.htmlua @@ -0,0 +1,21 @@ + + + + + main + + + +

hello

+ + +

exported from main!

+
+ +

exported from main but again!

+
+
+ + + + diff --git a/htmlua-apache-cgi/Cargo.toml b/htmlua-apache-cgi/Cargo.toml deleted file mode 100644 index 7a8052d..0000000 --- a/htmlua-apache-cgi/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "htmlua-apache-cgi" -version = "0.1.0" -edition = "2024" - -[dependencies] -htmlua-parser = { path = "../htmlua-parser" } -kuchikiki = "0.8.2" diff --git a/htmlua-apache-cgi/src/main.rs b/htmlua-apache-cgi/src/main.rs deleted file mode 100644 index 5998ff6..0000000 --- a/htmlua-apache-cgi/src/main.rs +++ /dev/null @@ -1,12 +0,0 @@ -use std::env; - -use htmlua_parser::serve::serve_content; - -fn main() { - println!("Content-Type: text/html\n"); - - let request_uri = env::var("PATH_INFO").unwrap_or_else(|_| "".to_string()); - let page = serve_content(request_uri.as_str()).unwrap(); - - println!("{page}"); -} diff --git a/htmlua-parser/Cargo.toml b/htmlua-parser/Cargo.toml deleted file mode 100644 index 8200513..0000000 --- a/htmlua-parser/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "htmlua-parser" -version = "0.1.0" -edition = "2024" - -[dependencies] -anyhow = "1.0.98" -dirs = "6.0.0" -html5ever = "0.35.0" -httptest = "0.16.3" -kuchikiki = "0.8.2" -markup5ever = "0.11.0" -mlua = { version = "0.10.5", features = ["lua54", "vendored", "serialize", "anyhow"] } -pulldown-cmark = "0.13.0" -reqwest = { version = "0.12.22", features = ["blocking", "json"] } -serde = { version = "1.0.219", features = ["derive"] } -serde_json = "1.0.140" -syntect = "5.2.0" -tendril = "0.4.3" -toml = "0.9.2" - -[lints.clippy] -pedantic = { level = "warn", priority = -1 } diff --git a/htmlua-parser/src/config.rs b/htmlua-parser/src/config.rs deleted file mode 100644 index de734ed..0000000 --- a/htmlua-parser/src/config.rs +++ /dev/null @@ -1,100 +0,0 @@ -use std::{fs, path::PathBuf}; - -use anyhow::{Context, Result}; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct Config { - pub paths: PathConfig, - pub server: ServerConfig, - pub syntax_highlighting: SyntaxConfig, -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct PathConfig { - pub pages: PathBuf, - pub components: PathBuf, - pub themes: PathBuf, -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct ServerConfig { - pub host: String, - pub port: u16, -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct SyntaxConfig { - pub default_theme: String, - pub load_custom_themes: bool, -} - -impl Default for Config { - fn default() -> Self { - Self { - paths: PathConfig { - pages: PathBuf::from("/var/www/htmlua/pages"), - components: PathBuf::from("/var/www/htmlua/components"), - themes: PathBuf::from("/var/www/htmlua/themes"), - }, - server: ServerConfig { - host: "127.0.0.1".to_string(), - port: 8080, - }, - syntax_highlighting: SyntaxConfig { - default_theme: "base16-ocean.dark".to_string(), - load_custom_themes: true, - }, - } - } -} - -impl Config { - pub fn load() -> Result { - let config_path = Self::get_config_path(); - if config_path.exists() { - let config_content = fs::read_to_string(&config_path) - .with_context(|| format!("Failed to read config file: {}", config_path.display()))?; - let config: Config = toml::from_str(&config_content) - .with_context(|| format!("Failed to parse config file: {}", config_path.display()))?; - Ok(config) - } else { - let default_config = Config::default(); - if let Some(parent) = config_path.parent() { - fs::create_dir_all(parent) - .with_context(|| format!("Failed to create config directory: {}", parent.display()))?; - } - let config_content = - toml::to_string_pretty(&default_config).context("Failed to serialize default config")?; - fs::write(&config_path, config_content) - .with_context(|| format!("Failed to write default config to: {}", config_path.display()))?; - Ok(default_config) - } - } - - fn get_config_path() -> PathBuf { - if cfg!(windows) { - dirs::config_dir() - .unwrap_or_else(|| PathBuf::from("C:\\ProgramData")) - .join("htmlua") - .join("config.toml") - } else { - PathBuf::from("/etc/htmlua.toml") - } - } - - pub fn save(&self) -> Result<()> { - let config_path = Self::get_config_path(); - if let Some(parent) = config_path.parent() { - fs::create_dir_all(parent) - .with_context(|| format!("Failed to create config directory: {}", parent.display()))?; - } - let config_content = toml::to_string_pretty(self).context("Failed to serialize config")?; - fs::write(&config_path, config_content) - .with_context(|| format!("Failed to write config to: {}", config_path.display()))?; - Ok(()) - } - - #[must_use] - pub fn config_file_path() -> PathBuf { Self::get_config_path() } -} diff --git a/htmlua-parser/src/helpers.rs b/htmlua-parser/src/helpers.rs deleted file mode 100644 index 2992f70..0000000 --- a/htmlua-parser/src/helpers.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::{ - fs::File, - io::{BufRead, BufReader, Read, Seek, SeekFrom}, - path::PathBuf, -}; - -use anyhow::Result; -use kuchikiki::NodeRef; -use markup5ever::{LocalName, QualName, namespace_url, ns}; -use tendril::TendrilSink; - - -pub fn read_doc_from_file(path: PathBuf) -> Result { - let mut file = File::open(path)?; - let mut reader = BufReader::new(&mut file); - - let mut first_line = String::new(); - reader.read_line(&mut first_line)?; - let first_line_trimmed = first_line.trim(); - - let is_whole_doc = first_line_trimmed.eq_ignore_ascii_case(""); - - file.seek(SeekFrom::Start(0))?; - let mut page_string = String::new(); - file.read_to_string(&mut page_string)?; - - if is_whole_doc { - Ok(kuchikiki::parse_html().one(page_string)) - } else { - let ctx_name = QualName::new(None, ns!(), LocalName::from("div")); - Ok(kuchikiki::parse_fragment(ctx_name, Vec::new()).one(page_string)) - } -} diff --git a/htmlua-parser/src/htmlua_stdlib.rs b/htmlua-parser/src/htmlua_stdlib.rs deleted file mode 100644 index d36620e..0000000 --- a/htmlua-parser/src/htmlua_stdlib.rs +++ /dev/null @@ -1,228 +0,0 @@ -use std::{ - cell::{LazyCell, RefCell}, - collections::HashMap, - fmt::Write, - rc::Rc, - str::FromStr, - time::Duration, -}; - -use mlua::{Error, Lua, Table, prelude::*}; -use reqwest::{ - Method, Url, - blocking::{Client, Response}, - header::HeaderMap, -}; -use serde::{Deserialize, Serialize}; - - -pub fn create_htmlua_stdlib(l: &Lua, stdout: &Rc>) -> mlua::Result { - let t = l.create_table()?; - - // This cannot be the best way to do this - - let stdout_println = stdout.clone(); - t.set( - "println", - l.create_function(move |_, text: String| { - let mut stdout_ref = stdout_println.borrow_mut(); - writeln!(stdout_ref, "{text}").map_err(mlua::Error::external) - })?, - )?; - - let stdout_print = stdout.clone(); - t.set( - "print", - l.create_function(move |_, text: String| { - let mut stdout_ref = stdout_print.borrow_mut(); - write!(stdout_ref, "{text}").map_err(mlua::Error::external) - })?, - )?; - - t.set("http", create_http_lib(l)?)?; - Ok(t) -} - -#[allow(clippy::too_many_lines)] -fn create_http_lib(l: &Lua) -> mlua::Result
{ - let t = l.create_table()?; - let http_client: Rc> = Rc::new(LazyCell::new(|| { - Client::builder() - .timeout(std::time::Duration::from_secs(3)) - .user_agent("htmlua/0.1.0") - .build() - .unwrap() - })); - - - let client = http_client.clone(); - t.set( - "get", - l.create_function(move |_, url: String| { - let res = client.get(url).send().map_err(|e| Error::RuntimeError(e.to_string()))?; - let lua_res: LuaHttpResponse = TryFrom::try_from(res)?; - Ok(lua_res) - })?, - )?; - - let client = http_client.clone(); - t.set( - "post", - l.create_function(move |_, url: String| { - let res = client - .post(url) - .send() - .map_err(|e| Error::RuntimeError(e.to_string()))?; - let lua_res: LuaHttpResponse = TryFrom::try_from(res)?; - Ok(lua_res) - })?, - )?; - - let client = http_client.clone(); - t.set( - "get_with_data", - l.create_function(move |_, (url, data): (String, HashMap)| { - let res = client - .get(url) - .query(&data) - .send() - .map_err(|e| Error::RuntimeError(e.to_string()))?; - let lua_res: LuaHttpResponse = TryFrom::try_from(res)?; - Ok(lua_res) - })?, - )?; - - let client = http_client.clone(); - t.set( - "post_with_data_form", - l.create_function(move |_, (url, data): (String, HashMap)| { - let res = client - .post(url) - .form(&data) - .send() - .map_err(|e| Error::RuntimeError(e.to_string()))?; - let lua_res: LuaHttpResponse = TryFrom::try_from(res)?; - Ok(lua_res) - })?, - )?; - - let client = http_client.clone(); - t.set( - "post_with_data_json", - l.create_function(move |_, (url, data): (String, HashMap)| { - let res = client - .post(url) - .json(&data) - .send() - .map_err(|e| Error::RuntimeError(e.to_string()))?; - let lua_res: LuaHttpResponse = TryFrom::try_from(res)?; - Ok(lua_res) - })?, - )?; - - let client = http_client.clone(); - t.set( - "request", - l.create_function(move |_, table: mlua::Table| { - let mut request = client.request( - Method::from_bytes(table.get::("method")?.as_bytes()) - .map_err(|e| Error::RuntimeError(e.to_string()))?, - Url::from_str(table.get::("url")?.as_str()).map_err(|e| Error::RuntimeError(e.to_string()))?, - ); - - if let Ok(header_tbl) = table.get::("headers") { - request = header_tbl - .pairs::() - .filter_map(std::result::Result::ok) - .fold(request, |req, (k, v)| req.header(k, v)); - } - - if let Ok(basic_auth) = table.get::("basic_auth") { - request = request - .basic_auth(basic_auth.get::("username")?, basic_auth.get::("password").ok()); - } - - if let Ok(bearer_auth) = table.get::("bearer_auth") { - request = request.bearer_auth(bearer_auth.get::("token")?); - } - - if let Ok(body) = table.get::("body") { - request = request.body(body); - } - - if let Ok(json) = table.get::("json") { - request = request.json(&json); - } - - if let Ok(timeout) = table.get::("timeout") { - request = request.timeout(Duration::from_secs(timeout)); - } - - - let res = request.send().map_err(|e| Error::RuntimeError(e.to_string()))?; - let lua_res: LuaHttpResponse = TryFrom::try_from(res)?; - Ok(lua_res) - })?, - )?; - - t.set( - "decode_json", - l.create_function(move |l, text: String| { - let table: serde_json::Value = - serde_json::from_str(&text).map_err(|e| Error::RuntimeError(e.to_string()))?; - Ok(l.to_value(&table)) - })?, - )?; - - Ok(t) -} - - -#[derive(Serialize, Deserialize)] -struct LuaHttpResponse { - headers: HashMap, - body: String, - status: u16, -} - -impl TryFrom for LuaHttpResponse { - fn try_from(value: Response) -> Result { - Ok(LuaHttpResponse { - headers: headermap_to_hashmap(value.headers()), - status: value.status().as_u16(), - body: value.text().map_err(|e| Error::RuntimeError(e.to_string()))?, - }) - } - - type Error = Error; -} - -fn headermap_to_hashmap(headers: &HeaderMap) -> HashMap { - let mut map = HashMap::new(); - - for (name, value) in headers { - if let Ok(value_str) = value.to_str() { - map.insert(name.as_str().to_string(), value_str.to_string()); - } - } - - map -} - - -impl IntoLua for LuaHttpResponse { - fn into_lua(self, lua: &Lua) -> LuaResult { - let table = lua.create_table()?; - - table.set("status", self.status)?; - table.set("body", self.body)?; - - let headers_table = lua.create_table()?; - for (key, value) in self.headers { - headers_table.set(key, value)?; - } - table.set("headers", headers_table)?; - - Ok(LuaValue::Table(table)) - } -} diff --git a/htmlua-parser/src/lib.rs b/htmlua-parser/src/lib.rs deleted file mode 100644 index d2d5599..0000000 --- a/htmlua-parser/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod config; -pub mod helpers; -pub mod htmlua_stdlib; -pub mod render; -pub mod serve; diff --git a/htmlua-parser/src/render.rs b/htmlua-parser/src/render.rs deleted file mode 100644 index 6a70315..0000000 --- a/htmlua-parser/src/render.rs +++ /dev/null @@ -1,670 +0,0 @@ -use std::{ - cell::{LazyCell, RefCell}, - fmt::Write, - path::PathBuf, - rc::Rc, -}; - -use anyhow::{Result, anyhow}; -use kuchikiki::{NodeRef, traits::TendrilSink}; -use markup5ever::{LocalName, Namespace, QualName}; -use mlua::Lua; -use pulldown_cmark::{Options, Parser, html}; -use syntect::{ - easy::HighlightLines, - highlighting::{Style, ThemeSet}, - html::{IncludeBackground, styled_line_to_highlighted_html}, - parsing::SyntaxSet, - util::LinesWithEndings, -}; - -use crate::{helpers::read_doc_from_file, htmlua_stdlib::create_htmlua_stdlib, serve::get_config}; - - -fn build_lua_with_stdout(stdout: &Rc>) -> Result { - let lua = Lua::new(); - let globals = lua.globals(); - - let htmlua_table = create_htmlua_stdlib(&lua, stdout).map_err(|e| anyhow!("Failed to create Lua stdlib: {}", e))?; - - globals - .set("htmlua", htmlua_table) - .map_err(|e| anyhow!("Failed to set global: {}", e))?; - - Ok(lua) -} - -pub fn execute_lua(document: NodeRef) -> Result { - let stdout: Rc> = Rc::new(RefCell::new(String::new())); - let lua = LazyCell::new(|| build_lua_with_stdout(&stdout).unwrap_or_default()); - let lua_elements: Vec<_> = match document.select("lua") { - Ok(e) => e.collect(), - Err(()) => return Err(anyhow!("Unable to find Lua")), - }; - - for node in lua_elements { - if let Some(text_node) = node.as_node().first_child() { - if let Some(lua_code) = text_node.as_text() { - stdout.borrow_mut().clear(); - lua.load(lua_code.borrow().as_str()) - .exec() - .map_err(|e| anyhow!("Failed to execute Lua: {}", e))?; - node.as_node() - .insert_before(NodeRef::new_text(stdout.borrow().as_str())); - node.as_node().detach(); - } - } - } - - Ok(document) -} - -pub fn process_markdown(document: NodeRef) -> Result { - let markdown_elements: Vec<_> = match document.select("markdown") { - Ok(e) => e.collect(), - Err(()) => return Err(anyhow!("Unable to find markdown elements")), - }; - for node in markdown_elements { - if let Some(text_node) = node.as_node().first_child() { - if let Some(markdown_text) = text_node.as_text() { - let borrowed_text = markdown_text.borrow(); - let parser = Parser::new_ext(&borrowed_text, Options::all()); - let mut html_output = String::new(); - html::push_html(&mut html_output, parser); - let html_fragment = kuchikiki::parse_html().one(html_output); - for child in html_fragment.children() { - node.as_node().insert_before(child); - } - // Remove the original markdown node. - node.as_node().detach(); - } - } - } - Ok(document) -} - -pub fn expand_template(document: NodeRef, component_path: &PathBuf, include_from: Option<&NodeRef>) -> Result { - if let Some(from_node) = include_from { - for i in document - .select("includeelement") - .map_err(|()| anyhow!("Error finding includeelement"))? - { - if let Some(name) = i.attributes.borrow().get("name") { - let exported = from_node - .select_first(format!("exportelement.{name}").as_str()) - .map_err(|()| anyhow!("Error finding exportelement"))?; - exported - .as_node() - .children() - .rev() - .for_each(|c| i.as_node().insert_after(c)); - } - } - while let Ok(i) = document.select_first("includeelement") { - i.as_node().detach(); - } - } - - for i in document - .select("include") - .map_err(|()| anyhow!("Error finding include"))? - .collect::>() - { - let attrs = match i.as_node().as_element() { - Some(e) => e.attributes.borrow(), - None => continue, - }; - if let Some(include_path) = attrs.get("path") { - let mut item_path = component_path.clone(); - item_path.push(include_path); - let new_node = read_doc_from_file(item_path)?; - let replaced_node = expand_template(new_node, component_path, Some(i.as_node()))?; - replaced_node - .select_first("html") - .map_err(|()| anyhow!("Error finding html"))? - .as_node() - .children() - .rev() - .for_each(|c| i.as_node().insert_after(c)); - } - } - while let Ok(i) = document.select_first("include") { - i.as_node().detach(); - } - Ok(document) -} - -pub fn process_syntax_highlighting(document: NodeRef) -> Result { - let config = get_config(); - let ps = SyntaxSet::load_defaults_newlines(); - let mut ts = ThemeSet::load_defaults(); - let syntax_elements: Vec<_> = match document.select("syntaxhighlight") { - Ok(e) => e.collect(), - Err(()) => return Err(anyhow!("Unable to find syntaxhighlight elements")), - }; - if !syntax_elements.is_empty() && config.syntax_highlighting.load_custom_themes { - let _ = ts.add_from_folder(&config.paths.themes); - } - for node in syntax_elements { - let attrs = match node.as_node().as_element() { - Some(e) => e.attributes.borrow(), - None => continue, - }; - let language = attrs.get("lang").unwrap_or("text"); - let theme_name = attrs.get("theme").unwrap_or(&config.syntax_highlighting.default_theme); - if let Some(text_node) = node.as_node().first_child() { - if let Some(code_text) = text_node.as_text() { - let syntax = ps - .find_syntax_by_extension(language) - .or_else(|| ps.find_syntax_by_name(language)) - .unwrap_or_else(|| ps.find_syntax_plain_text()); - let theme = &ts.themes[theme_name]; - let mut h = HighlightLines::new(syntax, theme); - let mut html_output = String::new(); - write!(html_output, r#"
"#)?;
-                html_output.push_str("");
-                for line in LinesWithEndings::from(&code_text.borrow()) {
-                    let ranges: Vec<(Style, &str)> = h.highlight_line(line, &ps)?;
-                    let escaped = styled_line_to_highlighted_html(&ranges[..], IncludeBackground::No)?;
-                    html_output.push_str(&escaped);
-                }
-                html_output.push_str("
"); - let html_fragment = kuchikiki::parse_html().one(html_output); - for child in html_fragment.children() { - node.as_node().insert_before(child); - } - // Remove the original syntaxhighlight node. - node.as_node().detach(); - } - } - } - Ok(document) -} - -pub fn generate_footnotes(document: NodeRef) -> Result { - let Ok(footnote_container) = document.select_first("footnotecontainer") else { - return Ok(document); - }; - - let ctx_name = QualName::new(None, Namespace::from("http://www.w3.org/1999/xhtml"), LocalName::from("div")); - for (i, footnote) in document - .select("footnote") - .map_err(|()| anyhow!("Failed to get footnote"))? - .enumerate() - { - let i = i + 1; - let fn_text = footnote.text_contents(); - let sup_tag = kuchikiki::parse_fragment(ctx_name.clone(), Vec::new()) - .one(format!("{i}")) - .select_first("a") - .map_err(|()| anyhow!("parse err"))?; - footnote.as_node().insert_after(sup_tag.as_node().clone()); - let text_tag = kuchikiki::parse_fragment(ctx_name.clone(), Vec::new()) - .one(format!("

{i}: {fn_text}

")) - .select_first("p") - .map_err(|()| anyhow!("parse err"))?; - footnote_container.as_node().insert_before(text_tag.as_node().clone()); - } - while let Ok(i) = document.select_first("footnote") { - i.as_node().detach(); - } - footnote_container.as_node().detach(); - Ok(document) -} - -#[cfg(test)] -mod tests { - use httptest::{Expectation, ServerPool, matchers::*, responders::*}; - use markup5ever::{namespace_url, ns}; - - use super::*; - - #[test] - fn basic_lua() { - let page = r#" - - - - Basic HTML Page - - -

Hello World

-

This is a paragraph.

- - htmlua.println("Test from Lua!") - - - "#; - let document = kuchikiki::parse_html().one(page); - let d = execute_lua(document).unwrap(); - let text = d.select_first("span").unwrap().as_node().text_contents(); - assert_eq!(text, "Test from Lua!\n"); - assert!(d.select_first("lua").is_err()); - } - - #[test] - fn multiple_lua() { - let page = r#" - - - - Basic HTML Page - - -

Hello World

-

This is a paragraph.

- - htmlua.println("Test from Lua!") - -
- htmlua.println("test 2") -
- - "#; - let document = kuchikiki::parse_html().one(page); - let d = execute_lua(document).unwrap(); - let text = d.select_first("#ta").unwrap().as_node().text_contents(); - assert_eq!(text, "Test from Lua!\n"); - let text = d.select_first("#tb").unwrap().as_node().text_contents(); - assert_eq!(text, "test 2\n"); - assert!(d.select_first("lua").is_err()); - } - - #[test] - fn basic_include() { - let page = r#" - - - - Basic HTML Page - - -

Hello World

-

This is a paragraph.

- - - htmlua.println("Test from Lua!") - - - "#; - let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - p.push("tests/components"); - let document = kuchikiki::parse_html().one(page); - let d = expand_template(document, &p, None).unwrap(); - let text = d.select_first("span").unwrap().as_node().text_contents(); - assert_eq!(text, "included1"); - assert!(d.select_first("include").is_err()); - } - - #[test] - fn multiple_include() { - let page = r#" - - - - Basic HTML Page - - -

Hello World

-

This is a paragraph.

- - - - - "#; - let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - p.push("tests/components"); - let document = kuchikiki::parse_html().one(page); - let d = expand_template(document, &p, None).unwrap(); - let text = d.select_first("#inc1").unwrap().as_node().text_contents(); - assert_eq!(text, "included1"); - let text = d.select_first("#inc2").unwrap().as_node().text_contents(); - assert_eq!(text, "included2"); - let text = d.select_first("#inc3").unwrap().as_node().text_contents(); - assert_eq!(text, "included3"); - assert!(d.select_first("include").is_err()); - } - - #[test] - fn basic_lua_include() { - let page = r#" - - - - Basic HTML Page - - -

Hello World

-

This is a paragraph.

- - htmlua.println("Test from Lua!") - - - - "#; - let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - p.push("tests/components"); - let document = kuchikiki::parse_html().one(page); - let d = execute_lua(expand_template(document, &p, None).unwrap()).unwrap(); - let text = d.select_first("span").unwrap().as_node().text_contents(); - assert_eq!(text, "Test from Lua!\n"); - assert!(d.select_first("lua").is_err()); - let text = d.select_first("#inc1").unwrap().as_node().text_contents(); - assert_eq!(text, "included1"); - assert!(d.select_first("include").is_err()); - } - - #[test] - fn recursive_include() { - let page = r#" - - - - Basic HTML Page - - -

Hello World

- - - "#; - let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - p.push("tests/components"); - let document = kuchikiki::parse_html().one(page); - let d = expand_template(document, &p, None).unwrap(); - let text = d.select_first("span").unwrap().as_node().text_contents(); - assert_eq!(text, "included_twice"); - assert!(d.select_first("include").is_err()); - } - - #[test] - fn export_element_include() { - let page = r#" - - - - Basic HTML Page - - -

Hello World

- - element 1 - element 2 - - - "#; - let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - p.push("tests/components"); - let document = kuchikiki::parse_html().one(page); - let d = expand_template(document, &p, None).unwrap(); - let text = d.select_first("#ta").unwrap().as_node().text_contents(); - assert_eq!(text, "element 1"); - let text = d.select_first("#tb").unwrap().as_node().text_contents(); - assert_eq!(text, "element 2"); - assert!(d.select_first("exportelement").is_err()); - assert!(d.select_first("includeelement").is_err()); - } - - #[test] - fn include_base() { - let page = r#" - - title_test - body_el - - "#; - let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - p.push("tests/components"); - let ctx_name = QualName::new(None, ns!(html), LocalName::from("div")); - let document = kuchikiki::parse_fragment(ctx_name, Vec::new()).one(page); - let d = expand_template(document, &p, None).unwrap(); - let text = d - .select_first("head") - .unwrap() - .as_node() - .select_first("title") - .unwrap() - .as_node() - .text_contents(); - assert_eq!(text, "title_test"); - let text = d.select_first("#tb").unwrap().as_node().text_contents(); - assert_eq!(text, "body_el"); - assert!(d.select_first("exportelement").is_err()); - assert!(d.select_first("includeelement").is_err()); - } - - #[test] - fn footnotes() { - let page = r" - - - - Basic HTML Page - - -
-

asdf

-

asdfum actually

-

asdf

-

asdfno

-
-
- -
- - "; - let document = kuchikiki::parse_html().one(page); - let d = generate_footnotes(document).unwrap(); - let sup1 = d.select_first("#ft-sup-1").unwrap(); - assert_eq!(sup1.attributes.borrow().get("title").unwrap(), "um actually"); - assert_eq!(sup1.text_contents(), "1"); - - let sup2 = d.select_first("#ft-sup-2").unwrap(); - assert_eq!(sup2.attributes.borrow().get("title").unwrap(), "no"); - assert_eq!(sup2.text_contents(), "2"); - - let ft_text_1 = d.select_first("#ft-text-1").unwrap(); - assert!(ft_text_1.text_contents().contains("um actually")); - - let ft_text_2 = d.select_first("#ft-text-2").unwrap(); - assert!(ft_text_2.text_contents().contains("no")); - - assert!(d.select_first("footnote").is_err()); - assert!(d.select_first("footnotecontainer").is_err()); - } - - #[test] - fn basic_markdown() { - let page = r" - - - - Markdown Test - - -

Hello World

-
- -# This is a heading -This is a paragraph with **bold text** and *italic text*. - -- Item 1 -- Item 2 -- Item 3 - -
- - "; - let document = kuchikiki::parse_html().one(page); - let d = process_markdown(document).unwrap(); - assert!(d.select_first("markdown").is_err()); - assert!(d.select_first("p").is_ok()); - assert!(d.select_first("ul").is_ok()); - } - - #[test] - fn basic_syntax_highlighting() { - let page = r#" - - - - Syntax Highlighting Test - - -

Code Example

- -fn main() { - println!("Hello, world!"); - let x = 42; - let y = "test"; -} - - - "#; - let document = kuchikiki::parse_html().one(page); - let d = process_syntax_highlighting(document).unwrap(); - assert!(d.select_first("syntaxhighlight").is_err()); - assert!(d.select_first("pre").is_ok()); - assert!(d.select_first("code").is_ok()); - let pre = d.select_first("pre").unwrap(); - let attrs = pre.attributes.borrow(); - assert_eq!(attrs.get("data-lang"), Some("rust")); - assert!(attrs.get("class").unwrap().contains("syntax-highlight")); - } - - static SERVER_POOL: ServerPool = ServerPool::new(2); - - #[test] - fn basic_get() { - let server = SERVER_POOL.get_server(); - - server.expect( - Expectation::matching(request::method_path("GET", "/test/1")).respond_with(status_code(200).body("ret")), - ); - - let stdout = Rc::new(RefCell::new(String::new())); - let lua = build_lua_with_stdout(&stdout).unwrap(); - let code = format!("htmlua.print(htmlua.http.get(\"{}\").body)", server.url("/test/1")); - lua.load(code).exec().unwrap(); - assert_eq!(stdout.borrow().as_str(), "ret"); - } - - #[test] - fn basic_post() { - let server = SERVER_POOL.get_server(); - - server.expect( - Expectation::matching(request::method_path("POST", "/test/1")).respond_with(status_code(200).body("ret")), - ); - - let stdout = Rc::new(RefCell::new(String::new())); - let lua = build_lua_with_stdout(&stdout).unwrap(); - let code = format!("htmlua.print(htmlua.http.post(\"{}\").body)", server.url("/test/1")); - lua.load(code).exec().unwrap(); - assert_eq!(stdout.borrow().as_str(), "ret"); - } - - #[test] - fn get_with_data() { - let server = SERVER_POOL.get_server(); - - server.expect( - Expectation::matching(request::query(url_decoded(contains(("a", "b"))))) - .respond_with(status_code(200).body("ret")), - ); - - let stdout = Rc::new(RefCell::new(String::new())); - let lua = build_lua_with_stdout(&stdout).unwrap(); - let code = format!( - " - data = {{}} - data.a = \"b\" - htmlua.print(htmlua.http.get_with_data(\"{}\", data).body) - ", - server.url("/test/1") - ); - lua.load(code).exec().unwrap(); - assert_eq!(stdout.borrow().as_str(), "ret"); - } - - #[test] - fn post_with_data_form() { - let server = SERVER_POOL.get_server(); - - server.expect( - Expectation::matching(all_of![request::method_path("POST", "/test/1"), request::body("a=b")]) - .respond_with(status_code(200).body("ret")), - ); - - let stdout = Rc::new(RefCell::new(String::new())); - let lua = build_lua_with_stdout(&stdout).unwrap(); - let code = format!( - " - data = {{}} - data.a = \"b\" - htmlua.print(htmlua.http.post_with_data_form(\"{}\", data).body) - ", - server.url("/test/1") - ); - lua.load(code).exec().unwrap(); - assert_eq!(stdout.borrow().as_str(), "ret"); - } - - #[test] - fn post_with_data_json() { - let server = SERVER_POOL.get_server(); - - server.expect( - Expectation::matching(all_of![request::method_path("POST", "/test/1"), request::body(r#"{"a":"b"}"#)]) - .respond_with(status_code(200).body("ret")), - ); - - let stdout = Rc::new(RefCell::new(String::new())); - let lua = build_lua_with_stdout(&stdout).unwrap(); - let code = format!( - " - data = {{}} - data.a = \"b\" - htmlua.print(htmlua.http.post_with_data_json(\"{}\", data).body) - ", - server.url("/test/1") - ); - lua.load(code).exec().unwrap(); - assert_eq!(stdout.borrow().as_str(), "ret"); - } - - #[test] - fn table_request() { - let server = SERVER_POOL.get_server(); - - server.expect( - Expectation::matching(all_of![ - request::method_path("GET", "/test/1"), - request::body("cool"), - request::headers(contains(("testhdr", "val"))), - request::headers(contains(("authorization", "Basic dXNlcjpwYXNz"))), - ]) - .respond_with(status_code(200).body("ret")), - ); - - let stdout = Rc::new(RefCell::new(String::new())); - let lua = build_lua_with_stdout(&stdout).unwrap(); - let code = format!( - " - req = {{}} - req.url = \"{}\" - req.method = \"GET\" - req.headers = {{}} - req.headers.testhdr = \"val\" - req.basic_auth = {{}} - req.basic_auth.username = \"user\" - req.basic_auth.password = \"pass\" - req.body = \"cool\" - - htmlua.print(htmlua.http.request(req).body) - ", - server.url("/test/1") - ); - lua.load(code).exec().unwrap(); - assert_eq!(stdout.borrow().as_str(), "ret"); - } -} diff --git a/htmlua-parser/src/serve.rs b/htmlua-parser/src/serve.rs deleted file mode 100644 index 375e885..0000000 --- a/htmlua-parser/src/serve.rs +++ /dev/null @@ -1,35 +0,0 @@ -use std::{path::Path, sync::OnceLock}; - -use anyhow::{Result, anyhow}; - -use crate::{ - config::Config, - helpers::read_doc_from_file, - render::{execute_lua, expand_template, process_markdown, process_syntax_highlighting}, -}; - -static CONFIG: OnceLock = OnceLock::new(); - -pub fn get_config() -> &'static Config { - CONFIG.get_or_init(|| { - Config::load().unwrap_or_else(|e| { - eprintln!("Warning: Failed to load config: {e}"); - eprintln!("Using default configuration"); - Config::default() - }) - }) -} - -pub fn serve_content(request_uri: &str) -> Result { - let config = get_config(); - let safe_path = Path::new(request_uri).strip_prefix("/")?; - let page_path = config.paths.pages.join(safe_path); - let doc = read_doc_from_file(page_path)? - .select_first("html") - .map_err(|()| anyhow!("failed to read doc"))?; - let full_doc = expand_template(doc.as_node().to_owned(), &config.paths.components, None)?; - let markdown_doc = process_markdown(full_doc)?; - let highlighted_doc = process_syntax_highlighting(markdown_doc)?; - let executed_doc = execute_lua(highlighted_doc)?; - Ok(executed_doc.to_string()) -} diff --git a/htmlua-parser/tests/components/comp1.html b/htmlua-parser/tests/components/comp1.html deleted file mode 100644 index 4110604..0000000 --- a/htmlua-parser/tests/components/comp1.html +++ /dev/null @@ -1 +0,0 @@ -included1 diff --git a/htmlua-parser/tests/components/comp2_level1.html b/htmlua-parser/tests/components/comp2_level1.html deleted file mode 100644 index 086a939..0000000 --- a/htmlua-parser/tests/components/comp2_level1.html +++ /dev/null @@ -1,4 +0,0 @@ -
-

test

- -
diff --git a/htmlua-parser/tests/components/comp2_level2.html b/htmlua-parser/tests/components/comp2_level2.html deleted file mode 100644 index 5a8bced..0000000 --- a/htmlua-parser/tests/components/comp2_level2.html +++ /dev/null @@ -1 +0,0 @@ -included_twice diff --git a/htmlua-parser/tests/components/include_base.html b/htmlua-parser/tests/components/include_base.html deleted file mode 100644 index fa86fe6..0000000 --- a/htmlua-parser/tests/components/include_base.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - -

Hello World

- - - diff --git a/htmlua-parser/tests/components/multi1_1.html b/htmlua-parser/tests/components/multi1_1.html deleted file mode 100644 index 4110604..0000000 --- a/htmlua-parser/tests/components/multi1_1.html +++ /dev/null @@ -1 +0,0 @@ -included1 diff --git a/htmlua-parser/tests/components/multi1_2.html b/htmlua-parser/tests/components/multi1_2.html deleted file mode 100644 index 0799d2f..0000000 --- a/htmlua-parser/tests/components/multi1_2.html +++ /dev/null @@ -1,2 +0,0 @@ - -included2 diff --git a/htmlua-parser/tests/components/multi1_3.html b/htmlua-parser/tests/components/multi1_3.html deleted file mode 100644 index 05b221c..0000000 --- a/htmlua-parser/tests/components/multi1_3.html +++ /dev/null @@ -1 +0,0 @@ -included3 diff --git a/htmlua-parser/tests/components/with_include1.html b/htmlua-parser/tests/components/with_include1.html deleted file mode 100644 index 4902bf1..0000000 --- a/htmlua-parser/tests/components/with_include1.html +++ /dev/null @@ -1,7 +0,0 @@ -
- -
-
- -
-
diff --git a/htmlua-server/Cargo.toml b/htmlua-server/Cargo.toml deleted file mode 100644 index 13df255..0000000 --- a/htmlua-server/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "htmlua-server" -version = "0.1.0" -edition = "2024" - -[dependencies] diff --git a/htmlua-server/src/main.rs b/htmlua-server/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/htmlua-server/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/src/cgi.zig b/src/cgi.zig new file mode 100755 index 0000000..849ef8c --- /dev/null +++ b/src/cgi.zig @@ -0,0 +1,79 @@ +const std = @import("std"); +const Io = std.Io; +const File = Io.File; +const Allocator = std.mem.Allocator; +const ArenaAllocator = std.heap.ArenaAllocator; +const ArrayList = std.ArrayList; +const StringArrayHashMap = std.StringArrayHashMapUnmanaged; + +const HTMLua = @import("htmlua"); + +const Config = struct { + component_path: []const u8, + template_path: []const u8, +}; + +var component_dir: Io.Dir = undefined; + +pub fn main(init: std.process.Init) !void { + const io = init.io; + + var arena = std.heap.ArenaAllocator.init(init.gpa); + defer arena.deinit(); + const alloc = arena.allocator(); + + var args = init.minimal.args.iterate(); + + const cwd = std.Io.Dir.cwd(); + + if (!args.skip()) unreachable; + const config_file_path = args.next().?; + const config_buf = try cwd.readFileAllocOptions(io, config_file_path, alloc, .unlimited, std.mem.Alignment.@"1", '\x00'); + const config = try std.zon.parse.fromSliceAlloc( + Config, + alloc, + config_buf, + null, + .{}, + ); + + component_dir = try cwd.openDir(io, config.component_path, .{}); + const template_dir = try cwd.openDir(io, config.template_path, .{}); + + var state: HTMLua.Parser = .{ + .tags = &[_]HTMLua.ParserTag{ + HTMLua.tags.Include, + HTMLua.tags.Export, + HTMLua.tags.Use, + HTMLua.tags.Syntax, + }, + .tag_stack = try ArrayList([]const u8).initCapacity(alloc, 256), + .exported_parts = try StringArrayHashMap([]const u8).init(alloc, &[0][]const u8{}, &[0][]const u8{}), + .component_resolver = struct { + pub fn resolve(arena_inner: *ArenaAllocator, io_inner: Io, path: []const u8) anyerror!*Io.Reader { + const read_buff = try arena_inner.allocator().alloc(u8, 16384); + const clean_path = try HTMLua.utils.sanitizePath(arena_inner.allocator(), path); + var file = try component_dir.openFile(io_inner, clean_path, .{ .mode = .read_only }); + const reader = try arena_inner.allocator().create(File.Reader); + reader.* = file.reader(io_inner, read_buff); + return &reader.interface; + } + }.resolve, + }; + + const request_path = init.environ_map.get("PATH_INFO").?; + const clean_request_path = try HTMLua.utils.sanitizePath(alloc, request_path); + const file = try template_dir.openFile(io, clean_request_path, .{ .mode = .read_only }); + defer file.close(io); + + const in_buf = try alloc.alloc(u8, 16384); + var in = file.reader(io, in_buf); + + const out_buf = try alloc.alloc(u8, 16384); + var out = File.stdout().writer(io, out_buf); + + try out.interface.writeAll("Content-type: text/html\n"); + try HTMLua.parseTemplate(&arena, io, &state, &in.interface, &out.interface); + + try out.flush(); +} diff --git a/src/main.zig b/src/main.zig new file mode 100755 index 0000000..18b8872 --- /dev/null +++ b/src/main.zig @@ -0,0 +1,59 @@ +const std = @import("std"); +const Io = std.Io; +const File = Io.File; +const Allocator = std.mem.Allocator; +const ArenaAllocator = std.heap.ArenaAllocator; +const ArrayList = std.ArrayList; +const StringArrayHashMap = std.StringArrayHashMapUnmanaged; + +const HTMLua = @import("root.zig"); + +pub fn main(init: std.process.Init) !void { + const io = init.io; + + var arena = std.heap.ArenaAllocator.init(init.gpa); + defer arena.deinit(); + const alloc = arena.allocator(); + + var state: HTMLua.Parser = .{ + .component_resolver = &resolver, + .tags = &[_]HTMLua.ParserTag{ + HTMLua.tags.Include, + HTMLua.tags.Export, + HTMLua.tags.Use, + }, + .tag_stack = try ArrayList([]const u8).initCapacity(alloc, 256), + .exported_parts = try StringArrayHashMap([]const u8).init(alloc, &[0][]const u8{}, &[0][]const u8{}), + }; + + // I dont like this but this is temporary so its ok + const args = try init.minimal.args.toSlice(alloc); + const file_path = if (args.len != 1) args[1] else null; + const file = if (file_path) |fp| + try Io.Dir.cwd().openFile(io, fp, .{ .mode = .read_only }) + else + null; + defer if (file) |f| f.close(io); + + const in_buf = try alloc.alloc(u8, 1024); + var in = + if (file) |f| f.reader(io, in_buf) else File.stdin().reader(io, in_buf); + + const out_buf = try alloc.alloc(u8, 1024); + var out = File.stdout().writer(io, out_buf); + + try HTMLua.parseTemplate(&arena, io, &state, &in.interface, &out.interface); + + try out.flush(); +} + +// https://ziggit.dev/t/zig-0-15-1-reader-writer-dont-make-copies-of-fieldparentptr-based-interfaces/11719 +fn resolver(arena: *ArenaAllocator, io: Io, path: []const u8) anyerror!*Io.Reader { + const read_buff = try arena.allocator().alloc(u8, 1024); + const cwd = std.Io.Dir.cwd(); + + var file = try cwd.openFile(io, path, .{ .mode = .read_only }); + const reader = try arena.allocator().create(Io.File.Reader); + reader.* = file.reader(io, read_buff); + return &reader.interface; +} diff --git a/src/root.zig b/src/root.zig new file mode 100755 index 0000000..3ddfe78 --- /dev/null +++ b/src/root.zig @@ -0,0 +1,76 @@ +const std = @import("std"); +const Io = std.Io; +const Allocator = std.mem.Allocator; +const ArenaAllocator = std.heap.ArenaAllocator; +const SplitIterator = std.mem.SplitIterator; +const DelimiterType = std.mem.DelimiterType; +const ArrayList = std.ArrayList; +const StringArrayHashMap = std.StringArrayHashMapUnmanaged; + +pub const tags = @import("tags.zig"); +pub const utils = @import("utils.zig"); + +pub const ParserFn = + fn ( + arena: *ArenaAllocator, + io: Io, + state: *Parser, + reader: *Io.Reader, + writer: *Io.Writer, + attrs: *SplitIterator(u8, DelimiterType.scalar), + ) anyerror!void; + +pub const ParserTag = struct { + name: []const u8, + parse_fn: *const ParserFn, +}; + +pub const Parser = struct { + component_resolver: *const fn (alloc: *ArenaAllocator, io: Io, path: []const u8) anyerror!*Io.Reader, + exported_parts: StringArrayHashMap([]const u8), + tags: []const ParserTag, + tag_stack: ArrayList([]const u8), +}; + +pub fn parseTemplate(arena: *ArenaAllocator, io: Io, state: *Parser, reader: *Io.Reader, writer: *Io.Writer) !void { + outer: while (true) { + _ = reader.streamDelimiter(writer, '<') catch |err| { + if (err == Io.Reader.Error.EndOfStream) break else return err; + }; + // consume '<' + _ = try reader.takeByte(); + if (try reader.peekByte() == '/') { + // consume '/' + _ = try reader.takeByte(); + const last_tag = state.tag_stack.getLastOrNull() orelse ""; + // if reached closing tag, send execution back up the stack + if (std.mem.eql(u8, last_tag, try reader.peekDelimiterExclusive('>'))) { + // consume closing tag + _ = try reader.takeDelimiterInclusive('>'); + return; + } else { + try writer.writeAll("') catch |err| { + if (err == error.StreamTooLong) { + try writer.writeByte('<'); + break :outer; + } else return err; + }; + var it = std.mem.splitScalar(u8, inside, ' '); + const tag_name = it.first(); + for (state.tags) |tag| { + if (std.mem.eql(u8, tag.name, tag_name) == true) { + // consume '>' + _ = try reader.takeByte(); + try tag.parse_fn(arena, io, state, reader, writer, &it); + continue :outer; + } + } + + try writer.writeByte('<'); + try writer.writeAll(inside); + } +} diff --git a/src/tags.zig b/src/tags.zig new file mode 100755 index 0000000..3f4169e --- /dev/null +++ b/src/tags.zig @@ -0,0 +1,4 @@ +pub const Include = @import("tags/Include.zig").Include; +pub const Export = @import("tags/Export.zig").Export; +pub const Use = @import("tags/Use.zig").Use; +pub const Syntax = @import("tags/Syntax.zig").Syntax; diff --git a/src/tags/Export.zig b/src/tags/Export.zig new file mode 100755 index 0000000..4b64048 --- /dev/null +++ b/src/tags/Export.zig @@ -0,0 +1,52 @@ +const std = @import("std"); +const Io = std.Io; +const Allocator = std.mem.Allocator; +const ArenaAllocator = std.heap.ArenaAllocator; +const SplitIterator = std.mem.SplitIterator; +const DelimiterType = std.mem.DelimiterType; + +const parser = @import("../root.zig"); +const Parser = parser.Parser; + +pub const ExportTagError = error{ + NoPartAttribute, +}; + +pub const Export: parser.ParserTag = .{ + .name = "export", + .parse_fn = &parse, +}; + +fn parse( + arena: *ArenaAllocator, + io: Io, + state: *Parser, + reader: *Io.Reader, + writer: *Io.Writer, + attrs: *SplitIterator(u8, DelimiterType.scalar), +) anyerror!void { + _ = writer; + + const raw_part_attr: []const u8 = while (attrs.next()) |attr| { + var it = std.mem.splitScalar(u8, attr, '='); + if (std.mem.eql(u8, it.first(), "part")) { + break it.next() orelse return ExportTagError.NoPartAttribute; + } + } else return ExportTagError.NoPartAttribute; + + const part = try arena.allocator().dupe(u8, raw_part_attr); + + var part_buffer = try Io.Writer.Allocating.initCapacity(arena.allocator(), 1024); + + try state.tag_stack.append(arena.allocator(), "export"); + try parser.parseTemplate( + arena, + io, + state, + reader, + &part_buffer.writer, + ); + _ = state.tag_stack.pop(); + + try state.exported_parts.put(arena.allocator(), part, try part_buffer.toOwnedSlice()); +} diff --git a/src/tags/Include.zig b/src/tags/Include.zig new file mode 100755 index 0000000..87f0b3f --- /dev/null +++ b/src/tags/Include.zig @@ -0,0 +1,58 @@ +const std = @import("std"); +const Io = std.Io; +const Allocator = std.mem.Allocator; +const ArenaAllocator = std.heap.ArenaAllocator; +const SplitIterator = std.mem.SplitIterator; +const DelimiterType = std.mem.DelimiterType; + +const parser = @import("../root.zig"); +const Parser = parser.Parser; + +pub const IncludeTagError = error{ + NoPathAttribute, + PathOpenFailure, +}; + +pub const Include: parser.ParserTag = .{ + .name = "include", + .parse_fn = &parse, +}; + +fn parse( + arena: *ArenaAllocator, + io: Io, + state: *Parser, + reader: *Io.Reader, + writer: *Io.Writer, + attrs: *SplitIterator(u8, DelimiterType.scalar), +) anyerror!void { + const raw_path_attr: []const u8 = while (attrs.next()) |attr| { + var it = std.mem.splitScalar(u8, attr, '='); + if (std.mem.eql(u8, it.first(), "path")) { + const raw_path = it.next() orelse return IncludeTagError.NoPathAttribute; + if (raw_path.len == 0) return IncludeTagError.NoPathAttribute; + if ((raw_path[0] == '"' and raw_path[raw_path.len - 1] == '"') or + (raw_path[0] == '\'' and raw_path[raw_path.len - 1] == '\'')) + { + if (raw_path.len <= 2) return IncludeTagError.NoPathAttribute; + break raw_path[1 .. raw_path.len - 1]; + } else { + break raw_path; + } + } + } else return IncludeTagError.NoPathAttribute; + + const path = try arena.allocator().dupe(u8, raw_path_attr); + + // parse through to gather tags + try state.tag_stack.append(arena.allocator(), "include"); + try parser.parseTemplate(arena, io, state, reader, writer); + _ = state.tag_stack.pop(); + + const included_reader = state.component_resolver(arena, io, path) catch { + std.log.err("Include Tag: failed to open file {s}", .{path}); + return IncludeTagError.PathOpenFailure; + }; + + try parser.parseTemplate(arena, io, state, included_reader, writer); +} diff --git a/src/tags/Syntax.zig b/src/tags/Syntax.zig new file mode 100755 index 0000000..03930b1 --- /dev/null +++ b/src/tags/Syntax.zig @@ -0,0 +1,169 @@ +const std = @import("std"); +const Io = std.Io; +const Allocator = std.mem.Allocator; +const ArenaAllocator = std.heap.ArenaAllocator; +const SplitIterator = std.mem.SplitIterator; +const DelimiterType = std.mem.DelimiterType; + +const ezts = @import("easy-zig-tree-sitter"); +const ts = @import("tree-sitter"); + +const parser = @import("../root.zig"); +const Parser = parser.Parser; + +pub const SyntaxTagError = error{InvalidLanguage}; +pub const Syntax: parser.ParserTag = .{ + .name = "syntax", + .parse_fn = &parse, +}; + +fn parse( + arena: *ArenaAllocator, + io: Io, + state: *Parser, + reader: *Io.Reader, + writer: *Io.Writer, + attrs: *SplitIterator(u8, DelimiterType.scalar), +) anyerror!void { + _ = state; + _ = io; + + const raw_lang_attr: []const u8 = while (attrs.next()) |attr| { + var it = std.mem.splitScalar(u8, attr, '='); + if (std.mem.eql(u8, it.first(), "lang")) { + break it.next() orelse ""; + } + } else ""; + + const lang_key = try arena.allocator().dupe(u8, raw_lang_attr); + + _ = try reader.takeDelimiterInclusive('\n'); + const first_line = try reader.peekDelimiterInclusive('\n'); + const whitespace_chr = for (first_line, 0..) |chr, idx| { + if (!(chr == ' ' or chr == '\t')) break idx; + } else 0; + + var code = try std.ArrayList(u8).initCapacity(arena.allocator(), 1024); + + while (true) { + const line = try reader.takeDelimiterInclusive('\n'); + if (std.mem.indexOf(u8, line, "")) |idx| { + try code.appendSlice(arena.allocator(), line[0..idx]); + // TODO: tags at the end will break the parser + break; + } + const whitespace_lem = @min(line.len, whitespace_chr); + + if (std.mem.countScalar(u8, line[0..whitespace_lem], ' ') + std.mem.countScalar(u8, line[0..whitespace_lem], '\t') < whitespace_lem) { + try code.appendSlice(arena.allocator(), line); + } else { + try code.appendSlice(arena.allocator(), line[whitespace_lem..line.len]); + } + } + + // Alignment issues? + // ts.setAllocator(arena.allocator()); + // TODO: TS Thread Mutex + + // TODO: null handeling + var hlp = HLParser.create(lang_key, code.items) orelse { + std.log.warn("Failed to make Parser for {s}", .{lang_key}); + return; + }; + defer hlp.destroy(); + var next_hl = hlp.nextHL(); + + var end_stack = try std.ArrayList(u32).initCapacity(arena.allocator(), 1024); + var code_idx: u32 = 0; + + try writer.writeAll("
");
+
+    while (code_idx != code.items.len) {
+        var next_idx: u32 = @intCast(code.items.len);
+        if (end_stack.getLastOrNull()) |last| {
+            if (last == code_idx) {
+                try writer.writeAll("");
+                _ = end_stack.pop();
+                continue;
+            } else if (last < next_idx) {
+                next_idx = last;
+            }
+        }
+        if (next_hl) |hl| {
+            if (hl.start == code_idx) {
+                try writer.writeAll("");
+                try end_stack.append(arena.allocator(), hl.end);
+                next_hl = hlp.nextHL();
+                continue;
+            } else if (hl.start < next_idx) {
+                next_idx = hl.start;
+            }
+        }
+        try writer.writeAll(code.items[code_idx..next_idx]);
+        code_idx = next_idx;
+    }
+
+    try writer.writeAll("
"); +} + +const HLGroup = struct { + name: []const u8, + start: u32, + end: u32, +}; + +const HLParser = struct { + lang: *ts.Language, + tree: *ts.Tree, + query: *ts.Query, + cursor: *ts.QueryCursor, + fn create(lang_key: []const u8, code: []const u8) ?HLParser { + const lang = ezts.getLang(lang_key) orelse return null; + const query_string = ezts.getQuery(lang_key, "highlights") orelse return null; + + const ps = ts.Parser.create(); + + ps.setLanguage(lang) catch return null; + const tree = ps.parseString(code, null) orelse return null; + + var error_offset: u32 = 0; + const query = ts.Query.create(lang, query_string, &error_offset) catch return null; + + const cursor = ts.QueryCursor.create(); + cursor.exec(query, tree.rootNode()); + + return .{ + .lang = lang, + .tree = tree, + .query = query, + .cursor = cursor, + }; + } + + fn destroy(self: *HLParser) void { + self.cursor.destroy(); + self.query.destroy(); + self.tree.destroy(); + self.lang.destroy(); + } + + fn nextHL(self: *HLParser) ?HLGroup { + if (self.cursor.nextCapture()) |data| { + const idx, const match = data; + const c = match.captures[idx]; + + return .{ + .start = c.node.startByte(), + .end = c.node.endByte(), + .name = self.query.captureNameForId(c.index) orelse return null, + }; + } else return null; + } +}; diff --git a/src/tags/Use.zig b/src/tags/Use.zig new file mode 100755 index 0000000..6ba1b1b --- /dev/null +++ b/src/tags/Use.zig @@ -0,0 +1,48 @@ +const std = @import("std"); +const Io = std.Io; +const Allocator = std.mem.Allocator; +const ArenaAllocator = std.heap.ArenaAllocator; +const SplitIterator = std.mem.SplitIterator; +const DelimiterType = std.mem.DelimiterType; + +const parser = @import("../root.zig"); +const Parser = parser.Parser; + +pub const UseTagError = error{ NoPartAttribute, NoPartExported }; + +pub const Use: parser.ParserTag = .{ + .name = "use", + .parse_fn = &parse, +}; + +fn parse( + arena: *ArenaAllocator, + io: Io, + state: *Parser, + reader: *Io.Reader, + writer: *Io.Writer, + attrs: *SplitIterator(u8, DelimiterType.scalar), +) anyerror!void { + _ = io; + + const raw_part_attr: []const u8 = while (attrs.next()) |attr| { + var it = std.mem.splitScalar(u8, attr, '='); + if (std.mem.eql(u8, it.first(), "part")) { + break it.next() orelse return UseTagError.NoPartAttribute; + } + } else return UseTagError.NoPartAttribute; + + const part = try arena.allocator().dupe(u8, raw_part_attr); + + const part_text = state.exported_parts.get(part) orelse return UseTagError.NoPartExported; + + var part_reader = Io.Reader.fixed(part_text); + + _ = try part_reader.streamRemaining(writer); + + while (true) { + _ = try reader.discardDelimiterInclusive('<'); + const inside = try reader.takeDelimiterInclusive('>'); + if (std.mem.eql(u8, "/use>", inside)) return; + } +} diff --git a/src/utils.zig b/src/utils.zig new file mode 100755 index 0000000..ae03d76 --- /dev/null +++ b/src/utils.zig @@ -0,0 +1,23 @@ +const std = @import("std"); +const Io = std.Io; +const File = Io.File; +const Allocator = std.mem.Allocator; +const ArenaAllocator = std.heap.ArenaAllocator; +const ArrayList = std.ArrayList; +const StringArrayHashMap = std.StringArrayHashMapUnmanaged; + +pub fn sanitizePath(alloc: Allocator, path: []const u8) ![]const u8 { + const clean = try alloc.alloc(u8, path.len); + var list = ArrayList(u8).initBuffer(clean); + var pit = std.mem.splitScalar(u8, path, '/'); + while (pit.next()) |part| { + if (part.len == 0) continue; + if (std.mem.eql(u8, part, "..")) continue; + // This should never actually allocate + try list.appendSlice(alloc, part); + try list.append(alloc, '/'); + } + const new_len = list.items.len - 1; + _ = alloc.resize(clean, new_len); + return clean[0..new_len]; +}