diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 84e75b4..75eabf5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ repos: stages: - commit-msg repo: https://github.com/commitizen-tools/commitizen - rev: v2.38.0 + rev: v3.28.0 - hooks: - id: fmt - id: cargo-check diff --git a/Cargo.lock b/Cargo.lock index e8eb333..d3ecdbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,31 +2,20 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "bitflags" @@ -34,11 +23,17 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "cfg-if" @@ -48,15 +43,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "deunicode" -version = "1.3.3" +version = "1.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1bba4f227a4a53d12b653f50ca7bf10c9119ae2aba56aff9e0338b5c98f36a" +checksum = "322ef0094744e63628e6f0eb2295517f79276a5b342a4c2ff3042566ca181d4e" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -82,9 +77,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "js-sys", @@ -93,15 +88,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] - [[package]] name = "html5ever" version = "0.26.0" @@ -118,9 +104,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -128,30 +114,30 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] [[package]] name = "libc" -version = "0.2.140" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -159,12 +145,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "mac" @@ -188,9 +171,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "minimal-lexical" @@ -210,9 +193,9 @@ dependencies = [ [[package]] name = "new_debug_unreachable" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nom" @@ -226,9 +209,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "parking_lot" @@ -242,40 +225,42 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-targets", ] [[package]] name = "parsedown" -version = "1.4.0" +version = "1.4.1" dependencies = [ "aho-corasick", "deunicode", "getrandom", "html5ever", + "js-sys", "mrml", "nom", "pulldown-cmark", "serde", "serde-wasm-bindgen", "textwrap", + "thiserror", "url", "wasm-bindgen", ] [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "phf" @@ -329,20 +314,20 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.54" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] [[package]] name = "pulldown-cmark" -version = "0.9.2" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags", + "bitflags 2.5.0", "getopts", "memchr", "unicase", @@ -350,9 +335,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.26" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -389,47 +374,30 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] -[[package]] -name = "regex" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.159" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" +checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" dependencies = [ "serde_derive", ] @@ -447,20 +415,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.159" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" +checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.12", + "syn 2.0.60", ] [[package]] name = "serde_json" -version = "1.0.95" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ "itoa", "ryu", @@ -469,21 +437,21 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "smallvec" -version = "1.10.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smawk" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "string_cache" @@ -524,9 +492,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.12" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79d9531f94112cfc3e4c8f5f02cb2b58f72c97b7efd85f70203cc6d8efda5927" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", @@ -546,15 +514,35 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" dependencies = [ "smawk", "unicode-linebreak", "unicode-width", ] +[[package]] +name = "thiserror" +version = "1.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.60", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -572,55 +560,51 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "unicase" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" dependencies = [ "version_check", ] [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-linebreak" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5faade31a542b8b35855fff6e8def199853b2da8da256da52f52f1316ee3137" -dependencies = [ - "hashbrown", - "regex", -] +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "url" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -647,9 +631,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "serde", @@ -659,24 +643,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.60", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -684,37 +668,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.60", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" - -[[package]] -name = "windows-sys" -version = "0.45.0" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets", -] +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -727,48 +702,48 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "xmlparser" -version = "0.13.5" +version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" diff --git a/Cargo.toml b/Cargo.toml index 1764c97..6e06807 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,15 +17,17 @@ lto = true opt-level = "z" [dependencies] -aho-corasick = "0.7.20" -deunicode = "1.3.3" -getrandom = { version = "0.2.8", features = ["js"] } +aho-corasick = "1.1.2" +deunicode = "1.4.4" +getrandom = { version = "0.2.14", features = ["js"] } html5ever = "0.26.0" +js-sys = "0.3.69" mrml = { version = "1.2.11", features = ["parse", "render"], default-features = false } nom = { version = "7.1.3", features = ["alloc"] } pulldown-cmark = "0.9.2" serde = { version = "1.0", features = ["derive"] } serde-wasm-bindgen = "0.5.0" -textwrap = "0.16.0" -url = "2.3.1" -wasm-bindgen = { version = "=0.2.84", features = ["serde-serialize"] } +textwrap = "0.16.1" +thiserror = "1.0.57" +url = "2.5.0" +wasm-bindgen = { version = "=0.2.92", features = ["serde-serialize"] } diff --git a/deno.json b/deno.json index 8d9d21c..fd0f0ec 100644 --- a/deno.json +++ b/deno.json @@ -1,9 +1,9 @@ { "tasks": { "test": "deno test -A", - "wasmbuild": "deno run -A https://deno.land/x/wasmbuild@0.10.4/main.ts --project=parsedown" + "wasmbuild": "deno run -A jsr:@deno/wasmbuild@0.17.2 --project=parsedown" }, "imports": { - "$std/": "https://deno.land/std@0.182.0/" + "@std/assert": "jsr:@std/assert@^1.0.0" } } diff --git a/deno.lock b/deno.lock index 3d37db9..dd9274f 100644 --- a/deno.lock +++ b/deno.lock @@ -1,5 +1,22 @@ { - "version": "2", + "version": "3", + "packages": { + "specifiers": { + "jsr:@std/assert@^1.0.0": "jsr:@std/assert@1.0.0", + "jsr:@std/internal@^1.0.1": "jsr:@std/internal@1.0.1" + }, + "jsr": { + "@std/assert@1.0.0": { + "integrity": "0e4f6d873f7f35e2a1e6194ceee39686c996b9e5d134948e644d35d4c4df2008", + "dependencies": [ + "jsr:@std/internal@^1.0.1" + ] + }, + "@std/internal@1.0.1": { + "integrity": "6f8c7544d06a11dd256c8d6ba54b11ed870aac6c5aeafff499892662c57673e6" + } + } + }, "remote": { "https://deno.land/std@0.167.0/fmt/colors.ts": "03ad95e543d2808bc43c17a3dd29d25b43d0f16287fe562a0be89bf632454a12", "https://deno.land/std@0.167.0/testing/_diff.ts": "a23e7fc2b4d8daa3e158fa06856bedf5334ce2a2831e8bf9e509717f455adb2c", @@ -8,6 +25,80 @@ "https://deno.land/std@0.182.0/fmt/colors.ts": "d67e3cd9f472535241a8e410d33423980bec45047e343577554d3356e1f0ef4e", "https://deno.land/std@0.182.0/testing/_diff.ts": "1a3c044aedf77647d6cac86b798c6417603361b66b54c53331b312caeb447aea", "https://deno.land/std@0.182.0/testing/_format.ts": "a69126e8a469009adf4cf2a50af889aca364c349797e63174884a52ff75cf4c7", - "https://deno.land/std@0.182.0/testing/asserts.ts": "e16d98b4d73ffc4ed498d717307a12500ae4f2cbe668f1a215632d19fcffc22f" + "https://deno.land/std@0.182.0/testing/asserts.ts": "e16d98b4d73ffc4ed498d717307a12500ae4f2cbe668f1a215632d19fcffc22f", + "https://deno.land/std@0.222.1/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975", + "https://deno.land/std@0.222.1/assert/_diff.ts": "4bf42969aa8b1a33aaf23eb8e478b011bfaa31b82d85d2ff4b5c4662d8780d2b", + "https://deno.land/std@0.222.1/assert/_format.ts": "0ba808961bf678437fb486b56405b6fefad2cf87b5809667c781ddee8c32aff4", + "https://deno.land/std@0.222.1/assert/assert.ts": "09d30564c09de846855b7b071e62b5974b001bb72a4b797958fe0660e7849834", + "https://deno.land/std@0.222.1/assert/assert_almost_equals.ts": "9e416114322012c9a21fa68e187637ce2d7df25bcbdbfd957cd639e65d3cf293", + "https://deno.land/std@0.222.1/assert/assert_array_includes.ts": "167b2c29997defd49a1835de52b54ae3cbb2bcba52df7c7ee45fe64b473264f1", + "https://deno.land/std@0.222.1/assert/assert_equals.ts": "cc1f4b0ff4ad511e69f965535b56a6cdbbbc0f086bf376e0243214df6039c883", + "https://deno.land/std@0.222.1/assert/assert_exists.ts": "43420cf7f956748ae6ed1230646567b3593cb7a36c5a5327269279c870c5ddfd", + "https://deno.land/std@0.222.1/assert/assert_false.ts": "3e9be8e33275db00d952e9acb0cd29481a44fa0a4af6d37239ff58d79e8edeff", + "https://deno.land/std@0.222.1/assert/assert_greater.ts": "26903fc7170a9eb37ee6c6606c772b5a0465a85e719cfe46f57de35555931419", + "https://deno.land/std@0.222.1/assert/assert_greater_or_equal.ts": "10527cf379a71a55a88b96d9b3373d0346ea2bdd8d73d2faaab1224e2cedb727", + "https://deno.land/std@0.222.1/assert/assert_instance_of.ts": "e22343c1fdcacfaea8f37784ad782683ec1cf599ae9b1b618954e9c22f376f2c", + "https://deno.land/std@0.222.1/assert/assert_is_error.ts": "f856b3bc978a7aa6a601f3fec6603491ab6255118afa6baa84b04426dd3cc491", + "https://deno.land/std@0.222.1/assert/assert_less.ts": "091f0cc80f53425be22b14c9b6ae410fea08e16eca391a476303c5f4852fcd9e", + "https://deno.land/std@0.222.1/assert/assert_less_or_equal.ts": "9418b2f809023f778d58fd6834410814900eacb8a91708647970ae1085553813", + "https://deno.land/std@0.222.1/assert/assert_match.ts": "ace1710dd3b2811c391946954234b5da910c5665aed817943d086d4d4871a8b7", + "https://deno.land/std@0.222.1/assert/assert_not_equals.ts": "78d45dd46133d76ce624b2c6c09392f6110f0df9b73f911d20208a68dee2ef29", + "https://deno.land/std@0.222.1/assert/assert_not_instance_of.ts": "3434a669b4d20cdcc5359779301a0588f941ffdc2ad68803c31eabdb4890cf7a", + "https://deno.land/std@0.222.1/assert/assert_not_match.ts": "df30417240aa2d35b1ea44df7e541991348a063d9ee823430e0b58079a72242a", + "https://deno.land/std@0.222.1/assert/assert_not_strict_equals.ts": "61e4adfd80eddaab5da5e5444431dfb19457f26b1f1e7a8be27c5d981b7f50b9", + "https://deno.land/std@0.222.1/assert/assert_object_match.ts": "411450fd194fdaabc0089ae68f916b545a49d7b7e6d0026e84a54c9e7eed2693", + "https://deno.land/std@0.222.1/assert/assert_rejects.ts": "4bee1d6d565a5b623146a14668da8f9eb1f026a4f338bbf92b37e43e0aa53c31", + "https://deno.land/std@0.222.1/assert/assert_strict_equals.ts": "dbcdcb5b8b74e6c06bce6a9fa43ff4d1089793e7832baff251e514954b9b266b", + "https://deno.land/std@0.222.1/assert/assert_string_includes.ts": "496b9ecad84deab72c8718735373feb6cdaa071eb91a98206f6f3cb4285e71b8", + "https://deno.land/std@0.222.1/assert/assert_throws.ts": "c6508b2879d465898dab2798009299867e67c570d7d34c90a2d235e4553906eb", + "https://deno.land/std@0.222.1/assert/assertion_error.ts": "ba8752bd27ebc51f723702fac2f54d3e94447598f54264a6653d6413738a8917", + "https://deno.land/std@0.222.1/assert/equal.ts": "bddf07bb5fc718e10bb72d5dc2c36c1ce5a8bdd3b647069b6319e07af181ac47", + "https://deno.land/std@0.222.1/assert/fail.ts": "0eba674ffb47dff083f02ced76d5130460bff1a9a68c6514ebe0cdea4abadb68", + "https://deno.land/std@0.222.1/assert/mod.ts": "48b8cb8a619ea0b7958ad7ee9376500fe902284bb36f0e32c598c3dc34cbd6f3", + "https://deno.land/std@0.222.1/assert/unimplemented.ts": "8c55a5793e9147b4f1ef68cd66496b7d5ba7a9e7ca30c6da070c1a58da723d73", + "https://deno.land/std@0.222.1/assert/unreachable.ts": "5ae3dbf63ef988615b93eb08d395dda771c96546565f9e521ed86f6510c29e19", + "https://deno.land/std@0.222.1/fmt/colors.ts": "d239d84620b921ea520125d778947881f62c50e78deef2657073840b8af9559a", + "https://deno.land/std@0.222.1/testing/asserts.ts": "0cb9c745d9b157bed062a4aa8647168d2221f6456c385a548b0ca24de9e0f3ca", + "https://deno.land/std@0.223.0/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975", + "https://deno.land/std@0.223.0/assert/_diff.ts": "4bf42969aa8b1a33aaf23eb8e478b011bfaa31b82d85d2ff4b5c4662d8780d2b", + "https://deno.land/std@0.223.0/assert/_format.ts": "0ba808961bf678437fb486b56405b6fefad2cf87b5809667c781ddee8c32aff4", + "https://deno.land/std@0.223.0/assert/assert.ts": "09d30564c09de846855b7b071e62b5974b001bb72a4b797958fe0660e7849834", + "https://deno.land/std@0.223.0/assert/assert_almost_equals.ts": "9e416114322012c9a21fa68e187637ce2d7df25bcbdbfd957cd639e65d3cf293", + "https://deno.land/std@0.223.0/assert/assert_array_includes.ts": "167b2c29997defd49a1835de52b54ae3cbb2bcba52df7c7ee45fe64b473264f1", + "https://deno.land/std@0.223.0/assert/assert_equals.ts": "cc1f4b0ff4ad511e69f965535b56a6cdbbbc0f086bf376e0243214df6039c883", + "https://deno.land/std@0.223.0/assert/assert_exists.ts": "43420cf7f956748ae6ed1230646567b3593cb7a36c5a5327269279c870c5ddfd", + "https://deno.land/std@0.223.0/assert/assert_false.ts": "3e9be8e33275db00d952e9acb0cd29481a44fa0a4af6d37239ff58d79e8edeff", + "https://deno.land/std@0.223.0/assert/assert_greater.ts": "26903fc7170a9eb37ee6c6606c772b5a0465a85e719cfe46f57de35555931419", + "https://deno.land/std@0.223.0/assert/assert_greater_or_equal.ts": "10527cf379a71a55a88b96d9b3373d0346ea2bdd8d73d2faaab1224e2cedb727", + "https://deno.land/std@0.223.0/assert/assert_instance_of.ts": "e22343c1fdcacfaea8f37784ad782683ec1cf599ae9b1b618954e9c22f376f2c", + "https://deno.land/std@0.223.0/assert/assert_is_error.ts": "f856b3bc978a7aa6a601f3fec6603491ab6255118afa6baa84b04426dd3cc491", + "https://deno.land/std@0.223.0/assert/assert_less.ts": "091f0cc80f53425be22b14c9b6ae410fea08e16eca391a476303c5f4852fcd9e", + "https://deno.land/std@0.223.0/assert/assert_less_or_equal.ts": "9418b2f809023f778d58fd6834410814900eacb8a91708647970ae1085553813", + "https://deno.land/std@0.223.0/assert/assert_match.ts": "ace1710dd3b2811c391946954234b5da910c5665aed817943d086d4d4871a8b7", + "https://deno.land/std@0.223.0/assert/assert_not_equals.ts": "78d45dd46133d76ce624b2c6c09392f6110f0df9b73f911d20208a68dee2ef29", + "https://deno.land/std@0.223.0/assert/assert_not_instance_of.ts": "3434a669b4d20cdcc5359779301a0588f941ffdc2ad68803c31eabdb4890cf7a", + "https://deno.land/std@0.223.0/assert/assert_not_match.ts": "df30417240aa2d35b1ea44df7e541991348a063d9ee823430e0b58079a72242a", + "https://deno.land/std@0.223.0/assert/assert_not_strict_equals.ts": "61e4adfd80eddaab5da5e5444431dfb19457f26b1f1e7a8be27c5d981b7f50b9", + "https://deno.land/std@0.223.0/assert/assert_object_match.ts": "411450fd194fdaabc0089ae68f916b545a49d7b7e6d0026e84a54c9e7eed2693", + "https://deno.land/std@0.223.0/assert/assert_rejects.ts": "4bee1d6d565a5b623146a14668da8f9eb1f026a4f338bbf92b37e43e0aa53c31", + "https://deno.land/std@0.223.0/assert/assert_strict_equals.ts": "dbcdcb5b8b74e6c06bce6a9fa43ff4d1089793e7832baff251e514954b9b266b", + "https://deno.land/std@0.223.0/assert/assert_string_includes.ts": "496b9ecad84deab72c8718735373feb6cdaa071eb91a98206f6f3cb4285e71b8", + "https://deno.land/std@0.223.0/assert/assert_throws.ts": "c6508b2879d465898dab2798009299867e67c570d7d34c90a2d235e4553906eb", + "https://deno.land/std@0.223.0/assert/assertion_error.ts": "ba8752bd27ebc51f723702fac2f54d3e94447598f54264a6653d6413738a8917", + "https://deno.land/std@0.223.0/assert/equal.ts": "bddf07bb5fc718e10bb72d5dc2c36c1ce5a8bdd3b647069b6319e07af181ac47", + "https://deno.land/std@0.223.0/assert/fail.ts": "0eba674ffb47dff083f02ced76d5130460bff1a9a68c6514ebe0cdea4abadb68", + "https://deno.land/std@0.223.0/assert/mod.ts": "48b8cb8a619ea0b7958ad7ee9376500fe902284bb36f0e32c598c3dc34cbd6f3", + "https://deno.land/std@0.223.0/assert/unimplemented.ts": "8c55a5793e9147b4f1ef68cd66496b7d5ba7a9e7ca30c6da070c1a58da723d73", + "https://deno.land/std@0.223.0/assert/unreachable.ts": "5ae3dbf63ef988615b93eb08d395dda771c96546565f9e521ed86f6510c29e19", + "https://deno.land/std@0.223.0/fmt/colors.ts": "d239d84620b921ea520125d778947881f62c50e78deef2657073840b8af9559a", + "https://deno.land/std@0.223.0/testing/asserts.ts": "0cb9c745d9b157bed062a4aa8647168d2221f6456c385a548b0ca24de9e0f3ca", + "https://deno.land/x/dir@1.5.1/data_local_dir/mod.ts": "91eb1c4bfadfbeda30171007bac6d85aadacd43224a5ed721bbe56bc64e9eb66", + "https://deno.land/x/wasmbuild@0.15.6/loader/cache.ts": "362d03a2ceb3d3e130373102a5de6d54ffda659a0911c2fcc090c29c3555f7ef", + "https://deno.land/x/wasmbuild@0.15.6/loader/fetch.ts": "7d015203a93cbadd05034cbb6e726d35f47e1f51140d91e69aeddc5d71b06ec8" + }, + "workspace": { + "dependencies": [ + "jsr:@std/assert@^1.0.0" + ] } } diff --git a/lib/parsedown.generated.d.ts b/lib/parsedown.generated.d.ts new file mode 100644 index 0000000..07e2661 --- /dev/null +++ b/lib/parsedown.generated.d.ts @@ -0,0 +1,56 @@ +// deno-lint-ignore-file +// deno-fmt-ignore-file + +export interface InstantiateResult { + instance: WebAssembly.Instance; + exports: { + markdown_to_html: typeof markdown_to_html; + markdown_to_plaintext: typeof markdown_to_plaintext; + mjml_to_html: typeof mjml_to_html + }; +} + +/** Gets if the Wasm module has been instantiated. */ +export function isInstantiated(): boolean; + +/** Options for instantiating a Wasm instance. */ +export interface InstantiateOptions { + /** Optional url to the Wasm file to instantiate. */ + url?: URL; + /** Callback to decompress the raw Wasm file bytes before instantiating. */ + decompress?: (bytes: Uint8Array) => Uint8Array; +} + +/** Instantiates an instance of the Wasm module returning its functions. +* @remarks It is safe to call this multiple times and once successfully +* loaded it will always return a reference to the same object. */ +export function instantiate(opts?: InstantiateOptions): Promise; + +/** Instantiates an instance of the Wasm module along with its exports. + * @remarks It is safe to call this multiple times and once successfully + * loaded it will always return a reference to the same object. */ +export function instantiateWithInstance(opts?: InstantiateOptions): Promise; + +/** +* # Panics +* +* Will panic if unable to parse options +* @param {string} markdown +* @param {any} options +* @returns {any} +*/ +export function markdown_to_html(markdown: string, options: any): any; +/** +* # Panics +* +* Will panic if unable to parse options +* @param {string} markdown +* @param {any} options +* @returns {string} +*/ +export function markdown_to_plaintext(markdown: string, options: any): string; +/** +* @param {string} mjml +* @returns {string} +*/ +export function mjml_to_html(mjml: string): string; diff --git a/lib/parsedown.generated.js b/lib/parsedown.generated.js index 7e43d44..5dbaf69 100644 --- a/lib/parsedown.generated.js +++ b/lib/parsedown.generated.js @@ -1,7 +1,10 @@ // @generated file from wasmbuild -- do not edit +// @ts-nocheck: generated // deno-lint-ignore-file // deno-fmt-ignore-file -// source-hash: bfbf62f1ae20afdcb9ce3f185162876be656f9b8 +/// + +// source-hash: 3b71a818b54b2c49ca8a82f65eca2c05911e9418 let wasm; const heap = new Array(128).fill(undefined); @@ -12,23 +15,15 @@ function getObject(idx) { return heap[idx]; } -let heap_next = heap.length; - -function addHeapObject(obj) { - if (heap_next === heap.length) heap.push(heap.length + 1); - const idx = heap_next; - heap_next = heap[idx]; - - heap[idx] = obj; - return idx; -} - -const cachedTextDecoder = new TextDecoder("utf-8", { - ignoreBOM: true, - fatal: true, -}); +const cachedTextDecoder = typeof TextDecoder !== "undefined" + ? new TextDecoder("utf-8", { ignoreBOM: true, fatal: true }) + : { + decode: () => { + throw Error("TextDecoder not available"); + }, + }; -cachedTextDecoder.decode(); +if (typeof TextDecoder !== "undefined") cachedTextDecoder.decode(); let cachedUint8Memory0 = null; @@ -40,12 +35,30 @@ function getUint8Memory0() { } function getStringFromWasm0(ptr, len) { + ptr = ptr >>> 0; return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); } +let heap_next = heap.length; + +function addHeapObject(obj) { + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; + + heap[idx] = obj; + return idx; +} + let WASM_VECTOR_LEN = 0; -const cachedTextEncoder = new TextEncoder("utf-8"); +const cachedTextEncoder = typeof TextEncoder !== "undefined" + ? new TextEncoder("utf-8") + : { + encode: () => { + throw Error("TextEncoder not available"); + }, + }; const encodeString = function (arg, view) { return cachedTextEncoder.encodeInto(arg, view); @@ -54,14 +67,14 @@ const encodeString = function (arg, view) { function passStringToWasm0(arg, malloc, realloc) { if (realloc === undefined) { const buf = cachedTextEncoder.encode(arg); - const ptr = malloc(buf.length); + const ptr = malloc(buf.length, 1) >>> 0; getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); WASM_VECTOR_LEN = buf.length; return ptr; } let len = arg.length; - let ptr = malloc(len); + let ptr = malloc(len, 1) >>> 0; const mem = getUint8Memory0(); @@ -77,11 +90,12 @@ function passStringToWasm0(arg, malloc, realloc) { if (offset !== 0) { arg = arg.slice(offset); } - ptr = realloc(ptr, len, len = offset + arg.length * 3); + ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; const view = getUint8Memory0().subarray(ptr + offset, ptr + len); const ret = encodeString(arg, view); offset += ret.written; + ptr = realloc(ptr, len, offset, 1) >>> 0; } WASM_VECTOR_LEN = offset; @@ -186,19 +200,10 @@ function debugString(val) { // TODO we could test for more things here, like `Set`s and `Map`s. return className; } - -function handleError(f, args) { - try { - return f.apply(this, args); - } catch (e) { - wasm.__wbindgen_exn_store(addHeapObject(e)); - } -} - -function getArrayU8FromWasm0(ptr, len) { - return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len); -} /** + * # Panics + * + * Will panic if unable to parse options * @param {string} markdown * @param {any} options * @returns {any} @@ -215,11 +220,16 @@ export function markdown_to_html(markdown, options) { } /** + * # Panics + * + * Will panic if unable to parse options * @param {string} markdown * @param {any} options * @returns {string} */ export function markdown_to_plaintext(markdown, options) { + let deferred2_0; + let deferred2_1; try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); const ptr0 = passStringToWasm0( @@ -231,10 +241,12 @@ export function markdown_to_plaintext(markdown, options) { wasm.markdown_to_plaintext(retptr, ptr0, len0, addHeapObject(options)); var r0 = getInt32Memory0()[retptr / 4 + 0]; var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; return getStringFromWasm0(r0, r1); } finally { wasm.__wbindgen_add_to_stack_pointer(16); - wasm.__wbindgen_free(r0, r1); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); } } @@ -243,6 +255,8 @@ export function markdown_to_plaintext(markdown, options) { * @returns {string} */ export function mjml_to_html(mjml) { + let deferred2_0; + let deferred2_1; try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); const ptr0 = passStringToWasm0( @@ -254,37 +268,103 @@ export function mjml_to_html(mjml) { wasm.mjml_to_html(retptr, ptr0, len0); var r0 = getInt32Memory0()[retptr / 4 + 0]; var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; return getStringFromWasm0(r0, r1); } finally { wasm.__wbindgen_add_to_stack_pointer(16); - wasm.__wbindgen_free(r0, r1); + wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); + } +} + +function handleError(f, args) { + try { + return f.apply(this, args); + } catch (e) { + wasm.__wbindgen_exn_store(addHeapObject(e)); } } const imports = { __wbindgen_placeholder__: { + __wbg_new_72fb9a18b5ae2624: function () { + const ret = new Object(); + return addHeapObject(ret); + }, + __wbg_set_841ac57cff3d672b: function (arg0, arg1, arg2) { + getObject(arg0)[takeObject(arg1)] = takeObject(arg2); + }, + __wbg_new_16b304a2cfa7ff4a: function () { + const ret = new Array(); + return addHeapObject(ret); + }, + __wbg_set_d4638f722068f043: function (arg0, arg1, arg2) { + getObject(arg0)[arg1 >>> 0] = takeObject(arg2); + }, __wbindgen_is_object: function (arg0) { const val = getObject(arg0); - const ret = typeof (val) === "object" && val !== null; + const ret = typeof val === "object" && val !== null; return ret; }, + __wbg_getwithrefkey_5e6d9547403deab8: function (arg0, arg1) { + const ret = getObject(arg0)[getObject(arg1)]; + return addHeapObject(ret); + }, + __wbindgen_is_undefined: function (arg0) { + const ret = getObject(arg0) === undefined; + return ret; + }, + __wbindgen_in: function (arg0, arg1) { + const ret = getObject(arg0) in getObject(arg1); + return ret; + }, + __wbindgen_boolean_get: function (arg0) { + const v = getObject(arg0); + const ret = typeof v === "boolean" ? (v ? 1 : 0) : 2; + return ret; + }, + __wbindgen_string_new: function (arg0, arg1) { + const ret = getStringFromWasm0(arg0, arg1); + return addHeapObject(ret); + }, + __wbindgen_number_new: function (arg0) { + const ret = arg0; + return addHeapObject(ret); + }, + __wbindgen_string_get: function (arg0, arg1) { + const obj = getObject(arg1); + const ret = typeof obj === "string" ? obj : undefined; + var ptr1 = isLikeNone(ret) + ? 0 + : passStringToWasm0( + ret, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + var len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; + }, + __wbg_log_986f64974292da8a: function (arg0, arg1) { + console.log(getStringFromWasm0(arg0, arg1)); + }, __wbindgen_object_clone_ref: function (arg0) { const ret = getObject(arg0); return addHeapObject(ret); }, - __wbg_crypto_e1d53a1d73fb10b8: function (arg0) { + __wbg_crypto_566d7465cdbb6b7a: function (arg0) { const ret = getObject(arg0).crypto; return addHeapObject(ret); }, - __wbg_process_038c26bf42b093f8: function (arg0) { + __wbg_process_dc09a8c7d59982f6: function (arg0) { const ret = getObject(arg0).process; return addHeapObject(ret); }, - __wbg_versions_ab37218d2f0b24a8: function (arg0) { + __wbg_versions_d98c6400c6ca2bd8: function (arg0) { const ret = getObject(arg0).versions; return addHeapObject(ret); }, - __wbg_node_080f4b19d15bc1fe: function (arg0) { + __wbg_node_caaf83d002149bd5: function (arg0) { const ret = getObject(arg0).node; return addHeapObject(ret); }, @@ -292,7 +372,7 @@ const imports = { const ret = typeof (getObject(arg0)) === "string"; return ret; }, - __wbg_require_78a3dcfbdba9cbce: function () { + __wbg_require_94a9da52636aacbf: function () { return handleError(function () { const ret = module.require; return addHeapObject(ret); @@ -302,105 +382,52 @@ const imports = { const ret = typeof (getObject(arg0)) === "function"; return ret; }, - __wbindgen_string_new: function (arg0, arg1) { - const ret = getStringFromWasm0(arg0, arg1); - return addHeapObject(ret); - }, - __wbg_call_9495de66fdbe016b: function () { + __wbg_call_b3ca7c6051f9bec1: function () { return handleError(function (arg0, arg1, arg2) { const ret = getObject(arg0).call(getObject(arg1), getObject(arg2)); return addHeapObject(ret); }, arguments); }, - __wbg_msCrypto_6e7d3e1f92610cbb: function (arg0) { + __wbg_msCrypto_0b84745e9245cdf6: function (arg0) { const ret = getObject(arg0).msCrypto; return addHeapObject(ret); }, - __wbg_newwithlength_b56c882b57805732: function (arg0) { + __wbg_newwithlength_e9b4878cebadb3d3: function (arg0) { const ret = new Uint8Array(arg0 >>> 0); return addHeapObject(ret); }, - __wbg_new_f9876326328f45ed: function () { - const ret = new Object(); - return addHeapObject(ret); - }, - __wbg_set_841ac57cff3d672b: function (arg0, arg1, arg2) { - getObject(arg0)[takeObject(arg1)] = takeObject(arg2); - }, - __wbg_new_b525de17f44a8943: function () { - const ret = new Array(); - return addHeapObject(ret); - }, - __wbg_set_17224bc548dd1d7b: function (arg0, arg1, arg2) { - getObject(arg0)[arg1 >>> 0] = takeObject(arg2); - }, - __wbg_getwithrefkey_5e6d9547403deab8: function (arg0, arg1) { - const ret = getObject(arg0)[getObject(arg1)]; - return addHeapObject(ret); - }, - __wbindgen_is_undefined: function (arg0) { - const ret = getObject(arg0) === undefined; - return ret; - }, - __wbindgen_in: function (arg0, arg1) { - const ret = getObject(arg0) in getObject(arg1); - return ret; - }, - __wbindgen_boolean_get: function (arg0) { - const v = getObject(arg0); - const ret = typeof (v) === "boolean" ? (v ? 1 : 0) : 2; - return ret; - }, - __wbindgen_number_new: function (arg0) { - const ret = arg0; - return addHeapObject(ret); - }, - __wbindgen_string_get: function (arg0, arg1) { - const obj = getObject(arg1); - const ret = typeof (obj) === "string" ? obj : undefined; - var ptr0 = isLikeNone(ret) - ? 0 - : passStringToWasm0( - ret, - wasm.__wbindgen_malloc, - wasm.__wbindgen_realloc, - ); - var len0 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len0; - getInt32Memory0()[arg0 / 4 + 0] = ptr0; - }, - __wbg_log_6243127f7214ac87: function (arg0, arg1) { - console.log(getStringFromWasm0(arg0, arg1)); + __wbindgen_object_drop_ref: function (arg0) { + takeObject(arg0); }, - __wbg_self_e7c1f827057f6584: function () { + __wbg_self_ce0dbfc45cf2f5be: function () { return handleError(function () { const ret = self.self; return addHeapObject(ret); }, arguments); }, - __wbg_window_a09ec664e14b1b81: function () { + __wbg_window_c6fb939a7f436783: function () { return handleError(function () { const ret = window.window; return addHeapObject(ret); }, arguments); }, - __wbg_globalThis_87cbb8506fecf3a9: function () { + __wbg_globalThis_d1e6af4856ba331b: function () { return handleError(function () { const ret = globalThis.globalThis; return addHeapObject(ret); }, arguments); }, - __wbg_global_c85a9259e621f3db: function () { + __wbg_global_207b558942527489: function () { return handleError(function () { const ret = global.global; return addHeapObject(ret); }, arguments); }, - __wbg_newnoargs_2b8b6bd7753c76ba: function (arg0, arg1) { + __wbg_newnoargs_e258087cd0daa0ea: function (arg0, arg1) { const ret = new Function(getStringFromWasm0(arg0, arg1)); return addHeapObject(ret); }, - __wbg_call_95d1ea488d03e4e8: function () { + __wbg_call_27c0f87801dedf93: function () { return handleError(function (arg0, arg1) { const ret = getObject(arg0).call(getObject(arg1)); return addHeapObject(ret); @@ -410,38 +437,43 @@ const imports = { const ret = wasm.memory; return addHeapObject(ret); }, - __wbg_buffer_cf65c07de34b9a08: function (arg0) { + __wbg_buffer_12d079cc21e14bdb: function (arg0) { const ret = getObject(arg0).buffer; return addHeapObject(ret); }, - __wbg_new_537b7341ce90bb31: function (arg0) { + __wbg_new_63b92bc8671ed464: function (arg0) { const ret = new Uint8Array(getObject(arg0)); return addHeapObject(ret); }, - __wbg_set_17499e8aa4003ebd: function (arg0, arg1, arg2) { + __wbg_set_a47bac70306a19a7: function (arg0, arg1, arg2) { getObject(arg0).set(getObject(arg1), arg2 >>> 0); }, - __wbg_length_27a2afe8ab42b09f: function (arg0) { + __wbg_length_c20a40f15020d68a: function (arg0) { const ret = getObject(arg0).length; return ret; }, - __wbg_randomFillSync_6894564c2c334c42: function () { - return handleError(function (arg0, arg1, arg2) { - getObject(arg0).randomFillSync(getArrayU8FromWasm0(arg1, arg2)); + __wbg_newwithbyteoffsetandlength_aa4a17c33a06e5cb: function ( + arg0, + arg1, + arg2, + ) { + const ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0); + return addHeapObject(ret); + }, + __wbg_randomFillSync_290977693942bf03: function () { + return handleError(function (arg0, arg1) { + getObject(arg0).randomFillSync(takeObject(arg1)); }, arguments); }, - __wbg_subarray_7526649b91a252a6: function (arg0, arg1, arg2) { + __wbg_subarray_a1f73cd4b5b42fe1: function (arg0, arg1, arg2) { const ret = getObject(arg0).subarray(arg1 >>> 0, arg2 >>> 0); return addHeapObject(ret); }, - __wbg_getRandomValues_805f1c3d65988a5a: function () { + __wbg_getRandomValues_260cc23a41afad9a: function () { return handleError(function (arg0, arg1) { getObject(arg0).getRandomValues(getObject(arg1)); }, arguments); }, - __wbindgen_object_drop_ref: function (arg0) { - takeObject(arg0); - }, __wbindgen_error_new: function (arg0, arg1) { const ret = new Error(getStringFromWasm0(arg0, arg1)); return addHeapObject(ret); @@ -452,25 +484,25 @@ const imports = { }, __wbindgen_number_get: function (arg0, arg1) { const obj = getObject(arg1); - const ret = typeof (obj) === "number" ? obj : undefined; + const ret = typeof obj === "number" ? obj : undefined; getFloat64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? 0 : ret; getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); }, - __wbg_instanceof_Uint8Array_01cebe79ca606cca: function (arg0) { + __wbg_instanceof_Uint8Array_2b3bbecd033d19f6: function (arg0) { let result; try { result = getObject(arg0) instanceof Uint8Array; - } catch { + } catch (_) { result = false; } const ret = result; return ret; }, - __wbg_instanceof_ArrayBuffer_a69f02ee4c4f5065: function (arg0) { + __wbg_instanceof_ArrayBuffer_836825be07d4c9d2: function (arg0) { let result; try { result = getObject(arg0) instanceof ArrayBuffer; - } catch { + } catch (_) { result = false; } const ret = result; @@ -478,14 +510,14 @@ const imports = { }, __wbindgen_debug_string: function (arg0, arg1) { const ret = debugString(getObject(arg1)); - const ptr0 = passStringToWasm0( + const ptr1 = passStringToWasm0( ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc, ); - const len0 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len0; - getInt32Memory0()[arg0 / 4 + 0] = ptr0; + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; }, __wbindgen_throw: function (arg0, arg1) { throw new Error(getStringFromWasm0(arg0, arg1)); @@ -493,128 +525,302 @@ const imports = { }, }; -/** - * Decompression callback - * - * @callback DecompressCallback - * @param {Uint8Array} compressed - * @return {Uint8Array} decompressed - */ +class WasmBuildLoader { + #options; + #lastLoadPromise; + #instantiated; -/** - * Options for instantiating a Wasm instance. - * @typedef {Object} InstantiateOptions - * @property {URL=} url - Optional url to the Wasm file to instantiate. - * @property {DecompressCallback=} decompress - Callback to decompress the - * raw Wasm file bytes before instantiating. - */ + constructor(options) { + this.#options = options; + } -/** Instantiates an instance of the Wasm module returning its functions. - * @remarks It is safe to call this multiple times and once successfully - * loaded it will always return a reference to the same object. - * @param {InstantiateOptions=} opts - */ -export async function instantiate(opts) { - return (await instantiateWithInstance(opts)).exports; -} + get instance() { + return this.#instantiated?.instance; + } -let instanceWithExports; -let lastLoadPromise; + get module() { + return this.#instantiated?.module; + } -/** Instantiates an instance of the Wasm module along with its exports. - * @remarks It is safe to call this multiple times and once successfully - * loaded it will always return a reference to the same object. - * @param {InstantiateOptions=} opts - * @returns {Promise<{ - * instance: WebAssembly.Instance; - * exports: { markdown_to_html: typeof markdown_to_html; markdown_to_plaintext: typeof markdown_to_plaintext; mjml_to_html: typeof mjml_to_html } - * }>} - */ -export function instantiateWithInstance(opts) { - if (instanceWithExports != null) { - return Promise.resolve(instanceWithExports); + load( + url, + decompress, + ) { + if (this.#instantiated) { + return Promise.resolve(this.#instantiated); + } else if (this.#lastLoadPromise == null) { + this.#lastLoadPromise = (async () => { + try { + this.#instantiated = await this.#instantiate(url, decompress); + return this.#instantiated; + } finally { + this.#lastLoadPromise = undefined; + } + })(); + } + return this.#lastLoadPromise; } - if (lastLoadPromise == null) { - lastLoadPromise = (async () => { + + async #instantiate(url, decompress) { + const imports = this.#options.imports; + if (this.#options.cache != null && url.protocol !== "file:") { try { - const instance = (await instantiateModule(opts ?? {})).instance; - wasm = instance.exports; - cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); - cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); - instanceWithExports = { - instance, - exports: getWasmInstanceExports(), - }; - return instanceWithExports; - } finally { - lastLoadPromise = null; + const result = await this.#options.cache( + url, + decompress ?? ((bytes) => bytes), + ); + if (result instanceof URL) { + url = result; + decompress = undefined; // already decompressed + } else if (result != null) { + return WebAssembly.instantiate(result, imports); + } + } catch { + // ignore if caching ever fails (ex. when on deploy) + } + } + + const isFile = url.protocol === "file:"; + + // make file urls work in Node via dnt + const isNode = globalThis.process?.versions?.node != null; + if (isFile && typeof Deno !== "object") { + throw new Error( + "Loading local files are not supported in this environment", + ); + } + if (isNode && isFile) { + // the deno global will be shimmed by dnt + const wasmCode = await Deno.readFile(url); + return WebAssembly.instantiate( + decompress ? decompress(wasmCode) : wasmCode, + imports, + ); + } + + switch (url.protocol) { + case "file:": + case "https:": + case "http:": { + const wasmResponse = await fetchWithRetries(url); + if (decompress) { + const wasmCode = new Uint8Array(await wasmResponse.arrayBuffer()); + return WebAssembly.instantiate(decompress(wasmCode), imports); + } + if ( + isFile || + wasmResponse.headers.get("content-type")?.toLowerCase() + .startsWith("application/wasm") + ) { + return WebAssembly.instantiateStreaming(wasmResponse, imports); + } else { + return WebAssembly.instantiate( + await wasmResponse.arrayBuffer(), + imports, + ); + } } - })(); + default: + throw new Error(`Unsupported protocol: ${url.protocol}`); + } } - return lastLoadPromise; +} +const isNodeOrDeno = typeof Deno === "object" || + (typeof process !== "undefined" && process.versions != null && + process.versions.node != null); + +const loader = new WasmBuildLoader({ + imports, + cache: isNodeOrDeno ? cacheToLocalDir : undefined, +}); + +export async function instantiate(opts) { + return (await instantiateWithInstance(opts)).exports; +} + +export async function instantiateWithInstance(opts) { + const { instance } = await loader.load( + opts?.url ?? new URL("parsedown_bg.wasm", import.meta.url), + opts?.decompress, + ); + wasm = wasm ?? instance.exports; + cachedInt32Memory0 = cachedInt32Memory0 ?? new Int32Array(wasm.memory.buffer); + cachedUint8Memory0 = cachedUint8Memory0 ?? new Uint8Array(wasm.memory.buffer); + return { + instance, + exports: getWasmInstanceExports(), + }; } function getWasmInstanceExports() { return { markdown_to_html, markdown_to_plaintext, mjml_to_html }; } -/** Gets if the Wasm module has been instantiated. */ export function isInstantiated() { - return instanceWithExports != null; + return loader.instance != null; } - -/** - * @param {InstantiateOptions} opts - */ -async function instantiateModule(opts) { - const wasmUrl = opts.url ?? new URL("parsedown_bg.wasm", import.meta.url); - const decompress = opts.decompress; - const isFile = wasmUrl.protocol === "file:"; - - // make file urls work in Node via dnt - const isNode = globalThis.process?.versions?.node != null; - if (isNode && isFile) { - // the deno global will be shimmed by dnt - const wasmCode = await Deno.readFile(wasmUrl); - return WebAssembly.instantiate( - decompress ? decompress(wasmCode) : wasmCode, - imports, - ); +export async function cacheToLocalDir(url, decompress) { + const localPath = await getUrlLocalPath(url); + if (localPath == null) { + return undefined; } - - switch (wasmUrl.protocol) { - case "file:": - case "https:": - case "http:": { - if (isFile) { - if (typeof Deno !== "object") { - throw new Error("file urls are not supported in this environment"); - } - if ("permissions" in Deno) { - await Deno.permissions.request({ name: "read", path: wasmUrl }); - } - } else if (typeof Deno === "object" && "permissions" in Deno) { - await Deno.permissions.request({ name: "net", host: wasmUrl.host }); + if (!await exists(localPath)) { + const fileBytes = decompress(new Uint8Array(await getUrlBytes(url))); + try { + await Deno.writeFile(localPath, fileBytes); + } catch { + // ignore and return the wasm bytes + return fileBytes; + } + } + return toFileUrl(localPath); +} +async function getUrlLocalPath(url) { + try { + const dataDirPath = await getInitializedLocalDataDirPath(); + const hash = await getUrlHash(url); + return `${dataDirPath}/${hash}.wasm`; + } catch { + return undefined; + } +} +async function getInitializedLocalDataDirPath() { + const dataDir = localDataDir(); + if (dataDir == null) { + throw new Error(`Could not find local data directory.`); + } + const dirPath = `${dataDir}/deno-wasmbuild`; + await ensureDir(dirPath); + return dirPath; +} +async function exists(filePath) { + try { + await Deno.lstat(filePath); + return true; + } catch (error) { + if (error instanceof Deno.errors.NotFound) { + return false; + } + throw error; + } +} +async function ensureDir(dir) { + try { + const fileInfo = await Deno.lstat(dir); + if (!fileInfo.isDirectory) { + throw new Error(`Path was not a directory '${dir}'`); + } + } catch (err) { + if (err instanceof Deno.errors.NotFound) { + // if dir not exists. then create it. + await Deno.mkdir(dir, { recursive: true }); + return; + } + throw err; + } +} +async function getUrlHash(url) { + // Taken from MDN: https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest + const hashBuffer = await crypto.subtle.digest( + "SHA-256", + new TextEncoder().encode(url.href), + ); + // convert buffer to byte array + const hashArray = Array.from(new Uint8Array(hashBuffer)); + // convert bytes to hex string + const hashHex = hashArray + .map((b) => b.toString(16).padStart(2, "0")) + .join(""); + return hashHex; +} +async function getUrlBytes(url) { + const response = await fetchWithRetries(url); + return await response.arrayBuffer(); +} +// the below is extracted from deno_std/path +const WHITESPACE_ENCODINGS = { + "\u0009": "%09", + "\u000A": "%0A", + "\u000B": "%0B", + "\u000C": "%0C", + "\u000D": "%0D", + "\u0020": "%20", +}; +function encodeWhitespace(string) { + return string.replaceAll(/[\s]/g, (c) => { + return WHITESPACE_ENCODINGS[c] ?? c; + }); +} +function toFileUrl(path) { + return Deno.build.os === "windows" + ? windowsToFileUrl(path) + : posixToFileUrl(path); +} +function posixToFileUrl(path) { + const url = new URL("file:///"); + url.pathname = encodeWhitespace( + path.replace(/%/g, "%25").replace(/\\/g, "%5C"), + ); + return url; +} +function windowsToFileUrl(path) { + const [, hostname, pathname] = path.match( + /^(?:[/\\]{2}([^/\\]+)(?=[/\\](?:[^/\\]|$)))?(.*)/, + ); + const url = new URL("file:///"); + url.pathname = encodeWhitespace(pathname.replace(/%/g, "%25")); + if (hostname != null && hostname != "localhost") { + url.hostname = hostname; + if (!url.hostname) { + throw new TypeError("Invalid hostname."); + } + } + return url; +} +export async function fetchWithRetries(url, maxRetries = 5) { + let sleepMs = 250; + let iterationCount = 0; + while (true) { + iterationCount++; + try { + const res = await fetch(url); + if (res.ok || iterationCount > maxRetries) { + return res; } - const wasmResponse = await fetch(wasmUrl); - if (decompress) { - const wasmCode = new Uint8Array(await wasmResponse.arrayBuffer()); - return WebAssembly.instantiate(decompress(wasmCode), imports); + } catch (err) { + if (iterationCount > maxRetries) { + throw err; } - if ( - isFile || - wasmResponse.headers.get("content-type")?.toLowerCase() - .startsWith("application/wasm") - ) { - return WebAssembly.instantiateStreaming(wasmResponse, imports); - } else { - return WebAssembly.instantiate( - await wasmResponse.arrayBuffer(), - imports, - ); + } + console.warn(`Failed fetching. Retrying in ${sleepMs}ms...`); + await new Promise((resolve) => setTimeout(resolve, sleepMs)); + sleepMs = Math.min(sleepMs * 2, 10000); + } +} +// MIT License - Copyright (c) justjavac. +// https://github.com/justjavac/deno_dirs/blob/e8c001bbef558f08fd486d444af391729b0b8068/data_local_dir/mod.ts +function localDataDir() { + switch (Deno.build.os) { + case "linux": { + const xdg = Deno.env.get("XDG_DATA_HOME"); + if (xdg) { + return xdg; + } + const home = Deno.env.get("HOME"); + if (home) { + return `${home}/.local/share`; + } + break; + } + case "darwin": { + const home = Deno.env.get("HOME"); + if (home) { + return `${home}/Library/Application Support`; } + break; } - default: - throw new Error(`Unsupported protocol: ${wasmUrl.protocol}`); + case "windows": + return Deno.env.get("LOCALAPPDATA") ?? undefined; } + return undefined; } diff --git a/lib/parsedown_bg.wasm b/lib/parsedown_bg.wasm index 5118793..e278210 100644 Binary files a/lib/parsedown_bg.wasm and b/lib/parsedown_bg.wasm differ diff --git a/mod.ts b/mod.ts index 1a1f93a..e0133b3 100644 --- a/mod.ts +++ b/mod.ts @@ -1,9 +1,4 @@ -import { - instantiate, - markdown_to_html, - markdown_to_plaintext, - mjml_to_html, -} from "./lib/parsedown.generated.js"; +import { instantiate } from "./lib/parsedown.generated.js"; interface MarkdownToHtmlOKOutput { errors?: never; @@ -35,11 +30,12 @@ const markdownToHtml: ( options?: MarkdownToHtmlOptions, ) => Promise = async function markdownToHtml(markdown, options) { - await instantiate(); + const { markdown_to_html } = await instantiate(); const { canonicalRootUrl, enableSmartPunctuation, searchTerm } = options ?? {}; return markdown_to_html(markdown, { + enable_smart_punctuation: true, ...(typeof canonicalRootUrl !== "undefined" ? { canonical_root_url: canonicalRootUrl } : {}), @@ -54,7 +50,7 @@ const markdownToPlaintext: ( markdown: string, options?: MarkdownToPlaintextOptions, ) => Promise = async function markdownToPlaintext(markdown, options) { - await instantiate(); + const { markdown_to_plaintext } = await instantiate(); const { canonicalRootUrl, enableSmartPunctuation } = options ?? {}; return markdown_to_plaintext(markdown, { ...(typeof canonicalRootUrl !== "undefined" @@ -69,7 +65,7 @@ const markdownToPlaintext: ( const mjmlToHtml: (mjml: string) => Promise = async function mjmlToHtml( mjml, ) { - await instantiate(); + const { mjml_to_html } = await instantiate(); return mjml_to_html(mjml); }; diff --git a/mod_test.ts b/mod_test.ts index bc1f35d..019ae6b 100644 --- a/mod_test.ts +++ b/mod_test.ts @@ -1,4 +1,4 @@ -import { assert, assertEquals } from "$std/testing/asserts.ts"; +import { assert, assertEquals } from "@std/assert"; import { markdownToHtml, markdownToPlaintext, mjmlToHtml } from "./mod.ts"; Deno.test("it parses markdown to html", async () => { diff --git a/src/html_process/dom.rs b/src/html_process/dom.rs index f31e0a2..5ee1938 100644 --- a/src/html_process/dom.rs +++ b/src/html_process/dom.rs @@ -14,7 +14,7 @@ use html5ever::{ Serialize, Serializer, TraversalScope::{self, ChildrenOnly, IncludeNode}, }, - tendril::*, + tendril::StrTendril, Attribute, ExpandedName, QualName, }; use std::{ @@ -30,7 +30,11 @@ pub enum NodeData { Document, Doctype { name: StrTendril, + + #[allow(dead_code)] public_id: StrTendril, + + #[allow(dead_code)] system_id: StrTendril, }, Text { @@ -92,7 +96,7 @@ impl fmt::Debug for Node { fmt.debug_struct("Node") .field("data", &self.data) .field("children", &self.children) - .finish() + .finish_non_exhaustive() } } @@ -110,15 +114,14 @@ fn get_parent_and_index(target: &Handle) -> Option<(Handle, usize)> { if let Some(weak) = target.parent.take() { let parent = weak.upgrade().expect("dangling weak pointer"); target.parent.set(Some(weak)); - let i = match parent + let Some((i, _)) = parent .children .borrow() .iter() .enumerate() .find(|&(_, child)| Rc::ptr_eq(child, target)) - { - Some((i, _)) => i, - None => panic!("have parent but couldn't find in parent's children!"), + else { + panic!("have parent but couldn't find in parent's children!") }; Some((parent, i)) } else { @@ -143,6 +146,7 @@ fn remove_from_parent(target: &Handle) { } } +#[allow(clippy::module_name_repetitions)] pub struct RcDom { pub document: Handle, pub errors: Vec>, @@ -334,7 +338,7 @@ impl TreeSink for RcDom { assert!(Rc::ptr_eq( node, &previous_parent.unwrap().upgrade().expect("dangling weak") - )) + )); } new_children.extend(mem::take(&mut *children)); } diff --git a/src/html_process/mod.rs b/src/html_process/mod.rs index 6cb7fe6..4617575 100644 --- a/src/html_process/mod.rs +++ b/src/html_process/mod.rs @@ -34,7 +34,7 @@ use html5ever::{ interface::tree_builder::{AppendNode, NodeOrText, TreeSink}, local_name, namespace_url, ns, serialize::{serialize, SerializeOpts}, - tendril::*, + tendril::{format_tendril, StrTendril, TendrilSink}, Attribute, QualName, }; use std::{ @@ -83,7 +83,7 @@ impl<'a> Builder<'a> { self } - fn process_child(&self, _child: &mut Handle) -> bool { + fn process_child(_child: &mut Handle) -> bool { true } @@ -108,17 +108,17 @@ impl<'a> Builder<'a> { while let Some(mut node) = stack.pop() { let parent = node.parent.replace(None).expect("a node in the DOM will have a parent, except the root, which is not processed") .upgrade().expect("a node's parent will be pointed to by its parent (or the root pointer), and will not be dropped"); - let pass_process = self.process_child(&mut node); + let pass_process = Builder::<'a>::process_child(&mut node); if pass_process { self.adjust_node_attributes(&mut node, &link_rel, &link_target); - self.adjust_node_children(&mut node, &mut dom); + Builder::<'a>::adjust_node_children(&mut node, &mut dom); if self.search_term.is_some() { if let Some(value) = self.replacement_node(&mut node, &mut dom, &mut already_matched) { // node should be a TextNode and so have no children to check so OK to // continue here - for new_child_node in value.iter() { + for new_child_node in &value { dom.append(&parent, NodeOrText::AppendNode(new_child_node.clone())); } removed.push(node); @@ -180,7 +180,7 @@ impl<'a> Builder<'a> { attrs.push(Attribute { name: QualName::new(None, ns!(), local_name!("rel")), value: link_rel.clone(), - }) + }); } } } @@ -209,11 +209,14 @@ impl<'a> Builder<'a> { .build(search_pattern); let mut matches = vec![]; let search_content = contents.borrow(); - for search_term_match in ac.find_iter(&search_content[..]) { + for search_term_match in ac + .expect("Search term should build valid Aho-Corasick instance") + .find_iter(&search_content[..]) + { matches.push((search_term_match.start(), search_term_match.end())); } let mut index: usize = 0; - for (start, end) in matches.iter() { + for (start, end) in &matches { replacement_nodes.push(Node::new(NodeData::Text { contents: RefCell::new(search_content[index..*start].into()), })); @@ -249,14 +252,13 @@ impl<'a> Builder<'a> { })); if replacement_nodes.is_empty() { return None; - } else { - return Some(replacement_nodes); } + return Some(replacement_nodes); } None } - fn adjust_node_children(&self, child: &mut Handle, dom: &mut RcDom) { + fn adjust_node_children(child: &mut Handle, dom: &mut RcDom) { if let NodeData::Element { ref name, ref attrs, diff --git a/src/html_process/tests.rs b/src/html_process/tests.rs index e158d9c..c2d4cd9 100644 --- a/src/html_process/tests.rs +++ b/src/html_process/tests.rs @@ -48,13 +48,13 @@ fn test_process_html() { fn test_relative_url() { assert!(relative_url("/about.html")); assert!(relative_url("#some-id")); - assert_eq!(relative_url("https://example.com"), false); + assert!(!relative_url("https://example.com")); } #[test] fn search_html_highlight_requested_term() { let result = process_html( - r#"

Heading

Nobody likes maple in their apple flavoured Snapple. APPLE

Paragraph with no matches

Paragraph which mentions apples again

"#, + r"

Heading

Nobody likes maple in their apple flavoured Snapple. APPLE

Paragraph with no matches

Paragraph which mentions apples again

", None, Some("apple"), ) @@ -66,7 +66,7 @@ fn search_html_highlight_requested_term() { #[test] fn search_html_highlight_requested_nested_term() { let result = process_html( - r#"

Heading

Nobody likes maple in their apple flavoured Snapple. APPLE

Paragraph with no matches

Paragraph which mentions apples again

"#, + r"

Heading

Nobody likes maple in their apple flavoured Snapple. APPLE

Paragraph with no matches

Paragraph which mentions apples again

", None, Some("apple"), ) @@ -78,7 +78,7 @@ fn search_html_highlight_requested_nested_term() { #[test] fn search_html_matches_on_multiple_terms() { let result = process_html( - r#"

Heading

Nobody likes maple in their apple flavoured Snapple. APPLE

Paragraph with no matches

Paragraph which mentions apples again

"#, + r"

Heading

Nobody likes maple in their apple flavoured Snapple. APPLE

Paragraph with no matches

Paragraph which mentions apples again

", None, Some("apple flavour"), ) diff --git a/src/lib.rs b/src/lib.rs index 6f1a270..bbacf68 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![warn(clippy::all, clippy::pedantic)] + mod html_process; mod markdown; mod url_utility; @@ -67,7 +69,11 @@ fn markdown_to_processed_html(markdown: &str, options: &ParseInputOptions) -> Pa } } +/// # Panics +/// +/// Will panic if unable to parse options #[wasm_bindgen] +#[must_use] pub fn markdown_to_html(markdown: &str, options: JsValue) -> JsValue { let input_options: Option = serde_wasm_bindgen::from_value(options).unwrap(); let parse_options = match input_options { @@ -82,7 +88,11 @@ pub fn markdown_to_html(markdown: &str, options: JsValue) -> JsValue { serde_wasm_bindgen::to_value(&results).unwrap() } +/// # Panics +/// +/// Will panic if unable to parse options #[wasm_bindgen] +#[must_use] pub fn markdown_to_plaintext(markdown: &str, options: JsValue) -> String { let input_options: Option = serde_wasm_bindgen::from_value(options).unwrap(); let mut markdown_options = ParseMarkdownOptions::default(); @@ -99,19 +109,20 @@ pub fn markdown_to_plaintext(markdown: &str, options: JsValue) -> String { if let Some(value) = enable_smart_punctuation { markdown_options.enable_smart_punctuation(value); } - parse_markdown_to_plaintext(markdown, markdown_options) + parse_markdown_to_plaintext(markdown, &markdown_options) } else { - parse_markdown_to_plaintext(markdown, markdown_options) + parse_markdown_to_plaintext(markdown, &markdown_options) } } #[wasm_bindgen] +#[must_use] pub fn mjml_to_html(mjml: &str) -> String { let root = match mrml::parse(mjml) { Ok(value) => value, Err(error) => { console_log!("Error parsing mjml: {:?}", error); - return String::from(""); + return String::new(); } }; let opts = mrml::prelude::render::Options::default(); @@ -119,7 +130,7 @@ pub fn mjml_to_html(mjml: &str) -> String { Ok(value) => value, Err(error) => { console_log!("Error rendering parsed mjml to html: {:?}", error); - String::from("") + String::new() } } } diff --git a/src/markdown/mod.rs b/src/markdown/mod.rs index 4d0bda0..35e9e1f 100644 --- a/src/markdown/mod.rs +++ b/src/markdown/mod.rs @@ -5,7 +5,6 @@ use crate::url_utility::relative_url; use deunicode::deunicode; use nom::{ - self, branch::alt, bytes::complete::{is_not, tag}, character::complete::multispace0, @@ -23,8 +22,9 @@ use std::io::{self, Cursor}; use textwrap::wrap; /// Reading time in minutes from number of words, assumes 180 wpm reading speed from a device +#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] fn reading_time_from_words(words: u32) -> u32 { - let result = (words as f64 / 180.0).round(); + let result = (f64::from(words) / 180.0).round(); if result > 0.0 { result as u32 } else { @@ -113,32 +113,29 @@ pub fn parse_markdown_to_html( let mut parsing_heading = false; let mut word_count: u32 = 0; - let heading_parser = Parser::new_ext(markdown, options).map(|event| { - match &event { - Event::Start(Tag::Heading(_level, _identifier, _classes)) => { - parsing_heading = true; - } - Event::Text(value) => { - word_count += words(value); - if parsing_heading { - current_id_fragments.push_str(value); - } - } - Event::Code(value) => { - if parsing_heading { - current_id_fragments.push_str(value); - } + let heading_parser = Parser::new_ext(markdown, options).inspect(|event| match &event { + Event::Start(Tag::Heading(_level, _identifier, _classes)) => { + parsing_heading = true; + } + Event::Text(value) => { + word_count += words(value); + if parsing_heading { + current_id_fragments.push_str(value); } - Event::End(Tag::Heading(_level, _identifier, _classes)) => { - let heading = ¤t_id_fragments; - let id = slugified_title(¤t_id_fragments); - headings.push(Heading::new(heading, &id)); - current_id_fragments = String::new(); - parsing_heading = false; + } + Event::Code(value) => { + if parsing_heading { + current_id_fragments.push_str(value); } - _ => {} } - event + Event::End(Tag::Heading(_level, _identifier, _classes)) => { + let heading = ¤t_id_fragments; + let id = slugified_title(¤t_id_fragments); + headings.push(Heading::new(heading, &id)); + current_id_fragments = String::new(); + parsing_heading = false; + } + _ => {} }); html::write_html(Cursor::new(&mut bytes), heading_parser)?; let reading_time = reading_time_from_words(word_count); @@ -153,7 +150,7 @@ pub fn parse_markdown_to_html( let heading_identifier = heading_iterator.next(); Event::Start(Tag::Heading( *level, - heading_identifier.map(|x| x.id()), + heading_identifier.map(Heading::id), Vec::new(), )) } @@ -161,7 +158,7 @@ pub fn parse_markdown_to_html( }); match html::write_html(Cursor::new(&mut bytes), parser) { - Ok(_) => Ok(( + Ok(()) => Ok(( String::from_utf8_lossy(&bytes).to_string(), headings, statistics, @@ -221,7 +218,7 @@ fn html_tag(html: &str) -> Result<(HTMLElementEvent, &str), Box Err(format!("{:?}", error).into()), + Err(error) => Err(format!("{error:?}").into()), } } @@ -275,7 +272,7 @@ where #[inline] fn write(&mut self) -> io::Result<()> { let lines = wrap(&self.current_line, self.line_length); - for line in lines.iter() { + for line in &lines { self.writer.write_str(line)?; self.writer.write_str("\n")?; } @@ -296,11 +293,7 @@ where End(tag) => { self.end_tag(tag)?; } - Text(text) => { - self.current_line.push_str(&text); - self.end_newline = text.ends_with('\n'); - } - Code(text) => { + Text(text) | Code(text) => { self.current_line.push_str(&text); self.end_newline = text.ends_with('\n'); } @@ -336,10 +329,10 @@ where fn start_tag(&mut self, tag: Tag) -> io::Result<()> { match tag { Tag::Paragraph => { - if !self.end_newline { - self.write() - } else { + if self.end_newline { Ok(()) + } else { + self.write() } } Tag::Heading(_level, _id, _classes) => { @@ -427,19 +420,19 @@ impl<'a> ParseMarkdownOptions<'a> { } } -pub fn parse_markdown_to_plaintext(markdown: &str, options: ParseMarkdownOptions) -> String { +pub fn parse_markdown_to_plaintext(markdown: &str, options: &ParseMarkdownOptions) -> String { let ParseMarkdownOptions { canonical_root_url, enable_smart_punctuation, } = options; let mut parser_options = Options::empty(); - if enable_smart_punctuation { + if *enable_smart_punctuation { parser_options.insert(Options::ENABLE_SMART_PUNCTUATION); } let parser = Parser::new_ext(markdown, parser_options); let mut plaintext_buf = String::new(); - push_plaintext(&mut plaintext_buf, parser, canonical_root_url); + push_plaintext(&mut plaintext_buf, parser, *canonical_root_url); plaintext_buf } diff --git a/src/markdown/tests.rs b/src/markdown/tests.rs index ae29b52..550c0a5 100644 --- a/src/markdown/tests.rs +++ b/src/markdown/tests.rs @@ -68,20 +68,20 @@ hello fn test_parse_markdown_to_plaintext() { let markdown = "## πŸ§‘πŸ½β€πŸ³ Pick of the Month β€” vanilla-extract"; - let result = parse_markdown_to_plaintext(markdown, ParseMarkdownOptions::default()); + let result = parse_markdown_to_plaintext(markdown, &ParseMarkdownOptions::default()); let expected = String::from("πŸ§‘πŸ½\u{200d}🍳 Pick of the Month β€” vanilla-extract\n"); assert_eq!(result, expected); let markdown = "My apple's quite tasty."; - let result = parse_markdown_to_plaintext(markdown, ParseMarkdownOptions::default()); + let result = parse_markdown_to_plaintext(markdown, &ParseMarkdownOptions::default()); let expected = String::from("My apple’s quite tasty.\n"); assert_eq!(result, expected); - let markdown = r#" + let markdown = r" testing, testing one, two, three, four, five, six, seven, eight, nine, ten, eleven -"#; +"; - let result = parse_markdown_to_plaintext(markdown, ParseMarkdownOptions::default()); + let result = parse_markdown_to_plaintext(markdown, &ParseMarkdownOptions::default()); let expected = String::from( "testing, testing one, two, three, four, five, six, seven, eight, nine,\nten, eleven\n", ); @@ -89,7 +89,7 @@ testing, testing one, two, three, four, five, six, seven, eight, nine, ten, ele let markdown = r#"CLICommand Line Interface"#; - let result = parse_markdown_to_plaintext(markdown, ParseMarkdownOptions::default()); + let result = parse_markdown_to_plaintext(markdown, &ParseMarkdownOptions::default()); let expected = String::from("CLI\n"); assert_eq!(result, expected); } @@ -100,7 +100,7 @@ pub fn parse_markdown_to_plaintext_applies_canonical_root_url() { let mut options = ParseMarkdownOptions::default(); options.canonical_root_url(Some("https://example.com")); - let result = parse_markdown_to_plaintext(markdown, options); + let result = parse_markdown_to_plaintext(markdown, &options); let expected = String::from("Contact us (https://example.com/contact) to find out more.\n"); assert_eq!(result, expected); } @@ -111,7 +111,7 @@ pub fn parse_markdown_to_plaintext_outputs_relative_urls_when_canonical_root_url let mut options = ParseMarkdownOptions::default(); options.canonical_root_url(None); - let result = parse_markdown_to_plaintext(markdown, options); + let result = parse_markdown_to_plaintext(markdown, &options); let expected = String::from("Contact us (/contact) to find out more.\n"); assert_eq!(result, expected); } diff --git a/src/url_utility/mod.rs b/src/url_utility/mod.rs index c13dbbb..d93105c 100644 --- a/src/url_utility/mod.rs +++ b/src/url_utility/mod.rs @@ -2,8 +2,7 @@ use url::Url; pub fn relative_url(url: &str) -> bool { match Url::parse(url) { - Ok(_) => false, Err(url::ParseError::RelativeUrlWithoutBase) => true, - Err(_) => false, + Ok(_) | Err(_) => false, } }