From 5c08be973d571f6e1380154ba23e523c1e2229cb Mon Sep 17 00:00:00 2001 From: Tobie Morgan Hitchcock Date: Fri, 14 Jul 2023 17:01:12 +0100 Subject: [PATCH] Revert "Update js functions to new rquickjs version" (#2262) --- Cargo.lock | 389 ++++++------ lib/Cargo.toml | 4 +- lib/src/fnc/script/classes/duration.rs | 81 +-- lib/src/fnc/script/classes/mod.rs | 10 +- lib/src/fnc/script/classes/record.rs | 96 +-- lib/src/fnc/script/classes/uuid.rs | 81 +-- lib/src/fnc/script/fetch/body.rs | 10 +- lib/src/fnc/script/fetch/classes/blob.rs | 245 ++++---- lib/src/fnc/script/fetch/classes/form_data.rs | 217 +++---- lib/src/fnc/script/fetch/classes/headers.rs | 484 +++++++-------- lib/src/fnc/script/fetch/classes/request.rs | 387 ++++++------ .../fnc/script/fetch/classes/response/init.rs | 34 +- .../fnc/script/fetch/classes/response/mod.rs | 555 +++++++++--------- lib/src/fnc/script/fetch/func.rs | 32 +- lib/src/fnc/script/fetch/mod.rs | 25 +- lib/src/fnc/script/fetch_stub/mod.rs | 3 +- lib/src/fnc/script/from.rs | 26 +- lib/src/fnc/script/globals/console.rs | 74 +-- lib/src/fnc/script/into.rs | 40 +- lib/src/fnc/script/main.rs | 15 +- lib/src/fnc/script/modules/mod.rs | 4 +- lib/src/fnc/script/modules/os.rs | 38 +- lib/src/fnc/script/modules/surrealdb/mod.rs | 4 +- lib/src/sql/value/value.rs | 2 +- 24 files changed, 1496 insertions(+), 1360 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 460ead9b..0b73363c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,7 +177,7 @@ dependencies = [ "serde_urlencoded", "smallvec", "socket2", - "time 0.3.23", + "time 0.3.22", "url", ] @@ -240,6 +240,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + [[package]] name = "aho-corasick" version = "1.0.2" @@ -321,7 +330,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -331,7 +340,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -395,9 +404,9 @@ dependencies = [ [[package]] name = "async-channel" -version = "1.9.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" dependencies = [ "concurrent-queue", "event-listener", @@ -449,7 +458,7 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.23", ] [[package]] @@ -471,7 +480,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.23", ] [[package]] @@ -482,13 +491,13 @@ checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" [[package]] name = "async-trait" -version = "0.1.71" +version = "0.1.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" +checksum = "7b2d0f03b3640e3a630367e40c468cb7f309529c708ed1d88597047b0e7c6ef7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.23", ] [[package]] @@ -701,13 +710,13 @@ dependencies = [ "lazycell", "log", "peeking_take_while", - "prettyplease 0.2.10", + "prettyplease 0.2.9", "proc-macro2", "quote", "regex", "rustc-hash", "shlex 1.1.0", - "syn 2.0.25", + "syn 2.0.23", "which", ] @@ -1048,9 +1057,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.11" +version = "4.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1640e5cc7fb47dbb8338fd471b105e7ed6c3cb2aeb00c2e067127ffd3764a05d" +checksum = "384e169cc618c613d5e3ca6404dda77a8685a63e08660dcc64abaf7da7cb0c7a" dependencies = [ "clap_builder", "clap_derive", @@ -1059,9 +1068,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.11" +version = "4.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c59138d527eeaf9b53f35a77fcc1fad9d883116070c63d5de1c7dc7b00c72b" +checksum = "ef137bbe35aab78bdb468ccfba75a5f4d8321ae011d34063770780545176af2d" dependencies = [ "anstream", "anstyle", @@ -1081,7 +1090,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.23", ] [[package]] @@ -1157,7 +1166,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" dependencies = [ "percent-encoding", - "time 0.3.23", + "time 0.3.22", "version_check", ] @@ -1188,9 +1197,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" dependencies = [ "libc", ] @@ -1302,9 +1311,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" dependencies = [ "darling_core", "darling_macro", @@ -1312,37 +1321,37 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.25", + "syn 1.0.109", ] [[package]] name = "darling_macro" -version = "0.20.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" dependencies = [ "darling_core", "quote", - "syn 2.0.25", + "syn 1.0.109", ] [[package]] name = "dashmap" -version = "5.5.0" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6943ae99c34386c84a470c499d3414f66502a41340aa895406e0d2e4a207b91d" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" dependencies = [ "cfg-if", - "hashbrown 0.14.0", + "hashbrown 0.12.3", "lock_api", "once_cell", "parking_lot_core 0.9.8", @@ -1498,9 +1507,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" [[package]] name = "errno" @@ -1510,7 +1519,7 @@ checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1566,8 +1575,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ "cfg-if", - "rustix 0.38.4", - "windows-sys", + "rustix 0.38.2", + "windows-sys 0.48.0", ] [[package]] @@ -1690,7 +1699,7 @@ checksum = "83c8d52fe8b46ab822b4decdcc0d6d85aeedfc98f0d52ba2bd4aec4a97807516" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.23", "try_map", ] @@ -1804,7 +1813,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.23", ] [[package]] @@ -1939,11 +1948,11 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.11" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1391ab1f92ffcc08911957149833e682aa3fe252b9f45f966d2ef972274c97df" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ - "aho-corasick", + "aho-corasick 0.7.20", "bstr", "fnv", "log", @@ -2128,9 +2137,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" [[package]] name = "hex" @@ -2213,14 +2222,13 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" +checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7" dependencies = [ - "futures-util", "http", "hyper", - "rustls 0.21.5", + "rustls 0.21.2", "tokio", "tokio-rustls 0.24.1", ] @@ -2404,9 +2412,9 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi 0.3.1", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2417,13 +2425,13 @@ checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "is-terminal" -version = "0.4.9" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb" dependencies = [ - "hermit-abi 0.3.2", - "rustix 0.38.4", - "windows-sys", + "hermit-abi 0.3.1", + "rustix 0.38.2", + "windows-sys 0.48.0", ] [[package]] @@ -2446,9 +2454,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.8" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" +checksum = "c0aa48fab2893d8a49caa94082ae8488f4e1050d73b367881dcd2198f4199fd8" [[package]] name = "jobserver" @@ -2646,7 +2654,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata 0.1.10", + "regex-automata", ] [[package]] @@ -2737,7 +2745,7 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2900,7 +2908,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi 0.3.1", "libc", ] @@ -2948,7 +2956,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.23", ] [[package]] @@ -3138,15 +3146,15 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.13" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "pbkdf2" -version = "0.12.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +checksum = "f0ca0b5a68607598bf3bad68f32227a8164f6254833f84eafaac409cd6746c31" dependencies = [ "digest", "hmac", @@ -3222,7 +3230,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.23", ] [[package]] @@ -3339,12 +3347,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.10" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92139198957b410250d43fad93e630d956499a625c527eda65175c8680f83387" +checksum = "9825a04601d60621feed79c4e6b56d65db77cdca55cef43b46b0de1096d1c282" dependencies = [ "proc-macro2", - "syn 2.0.25", + "syn 2.0.23", ] [[package]] @@ -3392,9 +3400,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.64" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" dependencies = [ "unicode-ident", ] @@ -3727,7 +3735,7 @@ checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", "ring", - "time 0.3.23", + "time 0.3.22", "yasna", ] @@ -3762,14 +3770,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.1" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ - "aho-corasick", + "aho-corasick 1.0.2", "memchr", - "regex-automata 0.3.3", - "regex-syntax 0.7.4", + "regex-syntax 0.7.2", ] [[package]] @@ -3781,17 +3788,6 @@ dependencies = [ "regex-syntax 0.6.29", ] -[[package]] -name = "regex-automata" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.7.4", -] - [[package]] name = "regex-syntax" version = "0.6.29" @@ -3800,9 +3796,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "relative-path" @@ -3845,7 +3841,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.21.5", + "rustls 0.21.2", "rustls-pemfile", "serde", "serde_json", @@ -3989,9 +3985,9 @@ dependencies = [ [[package]] name = "rquickjs" -version = "0.4.0-beta.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbfcaaf4557ff16c6e6b53387a3c81c2f0298ceaa7082357fa14170dadb060cd" +checksum = "6db7788c2818f4546daabe9ae2d1ee2f4db61ab1998d4b483494c4193cc38dab" dependencies = [ "rquickjs-core", "rquickjs-macro", @@ -3999,9 +3995,9 @@ dependencies = [ [[package]] name = "rquickjs-core" -version = "0.4.0-beta.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75454c59ff94406807a41bf04cee8369307c7c0d15269eb721ae2774f3c96c60" +checksum = "b12cf8646fe0af5bcff2822ccd162990f0679a1f9287c7257f4f4193a9d31ea9" dependencies = [ "async-lock", "relative-path", @@ -4010,9 +4006,9 @@ dependencies = [ [[package]] name = "rquickjs-macro" -version = "0.4.0-beta.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cea01191a7b5d087fb180a6c0de76d5c5a322289b662b990093a03368310096" +checksum = "80564583a91b0ae6b2d6b9b3d0f8ffd69a4b17202cc63a12df78dfa8983885fc" dependencies = [ "darling", "fnv", @@ -4023,14 +4019,14 @@ dependencies = [ "proc-macro2", "quote", "rquickjs-core", - "syn 2.0.25", + "syn 1.0.109", ] [[package]] name = "rquickjs-sys" -version = "0.4.0-beta.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0c47d60e7e2816b4e893874296f28868e8383999d067cbadd0b7948ed629b5" +checksum = "b747058afd4d988d056e4972ec8516a5a86fdfc103c1c1485bfee8966a0743ae" dependencies = [ "bindgen 0.65.1", "cc", @@ -4098,29 +4094,29 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.23" +version = "0.37.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +checksum = "8818fa822adcc98b18fedbb3632a6a33213c070556b5aa7c4c8cc21cff565c4c" dependencies = [ "bitflags 1.3.2", "errno", "io-lifetimes", "libc", "linux-raw-sys 0.3.8", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "rustix" -version = "0.38.4" +version = "0.38.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +checksum = "aabcb0461ebd01d6b79945797c27f8529082226cb630a9865a71870ff63532a4" dependencies = [ "bitflags 2.3.3", "errno", "libc", "linux-raw-sys 0.4.3", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -4137,9 +4133,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.5" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79ea77c539259495ce8ca47f53e66ae0330a8819f67e23ac96ca02f50e7b7d36" +checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f" dependencies = [ "log", "ring", @@ -4158,9 +4154,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.101.1" +version = "0.100.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f36a6828982f422756984e47912a7a51dcbc2a197aa791158f8ca61cd8204e" +checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" dependencies = [ "ring", "untrusted", @@ -4168,9 +4164,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.13" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc31bd9b61a32c31f9650d18add92aa83a49ba979c143eefd27fe7177b05bd5f" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" [[package]] name = "rustyline" @@ -4209,9 +4205,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.14" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "salsa20" @@ -4233,11 +4229,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" dependencies = [ - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -4320,18 +4316,18 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.171" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.11" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a16be4fe5320ade08736447e3198294a5ea9a6d44dde6f35f0a5e06859c427a" +checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" dependencies = [ "serde", ] @@ -4348,20 +4344,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.171" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.23", ] [[package]] name = "serde_json" -version = "1.0.102" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5062a995d481b2308b6064e9af76011f2921c35f97b0468811ed9f6cd91dfed" +checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" dependencies = [ "itoa", "ryu", @@ -4370,9 +4366,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.13" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc4422959dd87a76cb117c191dcbffc20467f06c9100b76721dab370f24d3a" +checksum = "0b1b6471d7496b051e03f1958802a73f88b947866f5146f329e47e36554f4e55" dependencies = [ "itoa", "serde", @@ -4412,7 +4408,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.23", ] [[package]] @@ -4493,7 +4489,7 @@ dependencies = [ "num-bigint", "num-traits", "thiserror", - "time 0.3.23", + "time 0.3.22", ] [[package]] @@ -4507,9 +4503,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "snap" @@ -4608,7 +4604,7 @@ dependencies = [ "assert_fs", "base64 0.21.2", "bytes", - "clap 4.3.11", + "clap 4.3.10", "futures 0.3.28", "glob", "http", @@ -4712,7 +4708,7 @@ dependencies = [ "temp-dir", "test-log", "thiserror", - "time 0.3.23", + "time 0.3.22", "tokio", "tokio-tungstenite", "tokio-util", @@ -4859,9 +4855,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.25" +version = "2.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" +checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" dependencies = [ "proc-macro2", "quote", @@ -4905,8 +4901,8 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.37.23", - "windows-sys", + "rustix 0.37.22", + "windows-sys 0.48.0", ] [[package]] @@ -4924,8 +4920,8 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" dependencies = [ - "rustix 0.37.23", - "windows-sys", + "rustix 0.37.22", + "windows-sys 0.48.0", ] [[package]] @@ -4953,22 +4949,22 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.43" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.43" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.23", ] [[package]] @@ -4994,9 +4990,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.23" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" +checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" dependencies = [ "itoa", "serde", @@ -5012,9 +5008,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.10" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" dependencies = [ "time-core", ] @@ -5061,7 +5057,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -5082,7 +5078,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.23", ] [[package]] @@ -5112,7 +5108,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.5", + "rustls 0.21.2", "tokio", ] @@ -5177,9 +5173,9 @@ checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" -version = "0.19.12" +version = "0.19.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78" +checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" dependencies = [ "indexmap 2.0.0", "toml_datetime", @@ -5284,7 +5280,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.23", ] [[package]] @@ -5428,9 +5424,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.10" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "unicode-normalization" @@ -5617,7 +5613,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.23", "wasm-bindgen-shared", ] @@ -5651,7 +5647,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.23", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5768,6 +5764,21 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -5783,51 +5794,93 @@ version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.0" @@ -5836,9 +5889,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.9" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a2094c43cc94775293eaa0e499fbc30048a6d824ac82c0351a8c0bf9112529" +checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" dependencies = [ "memchr", ] @@ -5892,7 +5945,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" dependencies = [ - "time 0.3.23", + "time 0.3.22", ] [[package]] diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 387ba8e4..06fbc406 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -75,7 +75,7 @@ fuzzy-matcher = "0.3.7" geo = { version = "0.25.1", features = ["use-serde"] } indexmap = { version = "1.9.3", features = ["serde"] } indxdb = { version = "0.3.0", optional = true } -js = { version = "0.4.0-beta.0" , package = "rquickjs", features = ["array-buffer", "bindgen", "classes", "futures", "loader", "macro", "parallel", "properties","rust-alloc"], optional = true } +js = { version = "0.3.1" , package = "rquickjs", features = ["array-buffer", "bindgen", "classes", "futures", "loader", "macro", "parallel", "properties","rust-alloc"], optional = true } jsonwebtoken = "8.3.0" lexicmp = "0.1.0" lru = "0.10.1" @@ -155,4 +155,4 @@ harness = false [[bench]] name = "index_btree" -harness = false +harness = false \ No newline at end of file diff --git a/lib/src/fnc/script/classes/duration.rs b/lib/src/fnc/script/classes/duration.rs index 7b36849b..7631deb3 100644 --- a/lib/src/fnc/script/classes/duration.rs +++ b/lib/src/fnc/script/classes/duration.rs @@ -1,48 +1,51 @@ -use js::class::Trace; +#[js::bind(object, public)] +#[quickjs(bare)] +#[allow(non_snake_case)] +#[allow(unused_variables)] +#[allow(clippy::module_inception)] +pub mod duration { -use crate::sql::duration; + use crate::sql::duration; + use crate::sql::value::Value; + use js::{class::Ref, function::Rest}; -#[derive(Clone, Trace)] -#[js::class] -pub struct Duration { - #[qjs(skip_trace)] - pub(crate) value: Option, -} + #[derive(Clone)] + #[quickjs(cloneable)] + pub struct Duration { + pub(crate) value: Option, + } -#[js::methods] -impl Duration { - #[qjs(constructor)] - pub fn new(value: String) -> Self { - Self { - value: duration::Duration::try_from(value).ok(), + impl Duration { + #[quickjs(constructor)] + pub fn new(value: String, args: Rest) -> Self { + Self { + value: duration::Duration::try_from(value).ok(), + } } - } - - #[qjs(get)] - pub fn value(&self) -> String { - match &self.value { - Some(v) => v.to_raw(), - None => String::from("Invalid Duration"), + #[quickjs(get)] + pub fn value(&self) -> String { + match &self.value { + Some(v) => v.to_raw(), + None => String::from("Invalid Duration"), + } } - } - // Compare two Duration instances - pub fn is(a: &Duration, b: &Duration) -> bool { - a.value.is_some() && b.value.is_some() && a.value == b.value - } - /// Convert the object to a string - #[qjs(rename = "toString")] - pub fn js_to_string(&self) -> String { - match &self.value { - Some(v) => v.to_raw(), - None => String::from("Invalid Duration"), + // Compare two Duration instances + pub fn is(a: Ref, b: Ref, args: Rest<()>) -> bool { + a.value.is_some() && b.value.is_some() && a.value == b.value } - } - /// Convert the object to JSON - #[qjs(rename = "toJSON")] - pub fn to_json(&self) -> String { - match &self.value { - Some(v) => v.to_raw(), - None => String::from("Invalid Duration"), + /// Convert the object to a string + pub fn toString(&self, args: Rest<()>) -> String { + match &self.value { + Some(v) => v.to_raw(), + None => String::from("Invalid Duration"), + } + } + /// Convert the object to JSON + pub fn toJSON(&self, args: Rest<()>) -> String { + match &self.value { + Some(v) => v.to_raw(), + None => String::from("Invalid Duration"), + } } } } diff --git a/lib/src/fnc/script/classes/mod.rs b/lib/src/fnc/script/classes/mod.rs index 6699419e..11041b2d 100644 --- a/lib/src/fnc/script/classes/mod.rs +++ b/lib/src/fnc/script/classes/mod.rs @@ -1,13 +1,13 @@ -use js::{Class, Ctx, Result}; +use js::{Ctx, Result}; pub mod duration; pub mod record; pub mod uuid; -pub fn init(ctx: &Ctx<'_>) -> Result<()> { +pub fn init(ctx: Ctx<'_>) -> Result<()> { let globals = ctx.globals(); - Class::::define(&globals)?; - Class::::define(&globals)?; - Class::::define(&globals)?; + globals.init_def::()?; + globals.init_def::()?; + globals.init_def::()?; Ok(()) } diff --git a/lib/src/fnc/script/classes/record.rs b/lib/src/fnc/script/classes/record.rs index f8c27ce8..0508f8be 100644 --- a/lib/src/fnc/script/classes/record.rs +++ b/lib/src/fnc/script/classes/record.rs @@ -1,52 +1,56 @@ -use crate::sql::thing; -use crate::sql::value::Value; -use js::class::Trace; +#[js::bind(object, public)] +#[quickjs(bare)] +#[allow(non_snake_case)] +#[allow(unused_variables)] +#[allow(clippy::module_inception)] +pub mod record { -#[derive(Clone, Trace)] -#[js::class] -pub struct Record { - #[qjs(skip_trace)] - pub(crate) value: thing::Thing, -} + use crate::sql::thing; + use crate::sql::value::Value; + use js::{class::Ref, function::Rest}; -#[js::methods] -impl Record { - #[qjs(constructor)] - pub fn new(tb: String, id: Value) -> Self { - Self { - value: thing::Thing { - tb, - id: match id { - Value::Array(v) => v.into(), - Value::Object(v) => v.into(), - Value::Number(v) => v.into(), - v => v.as_string().into(), + #[derive(Clone)] + #[quickjs(cloneable)] + pub struct Record { + pub(crate) value: thing::Thing, + } + + impl Record { + #[quickjs(constructor)] + pub fn new(tb: String, id: Value, args: Rest<()>) -> Self { + Self { + value: thing::Thing { + tb, + id: match id { + Value::Array(v) => v.into(), + Value::Object(v) => v.into(), + Value::Number(v) => v.into(), + v => v.as_string().into(), + }, }, - }, + } + } + + #[quickjs(get)] + pub fn tb(&self) -> String { + self.value.tb.clone() + } + + #[quickjs(get)] + pub fn id(&self) -> String { + self.value.id.to_raw() + } + // Compare two Record instances + pub fn is<'js>(a: Ref<'js, Record>, b: Ref<'js, Record>, args: Rest<()>) -> bool { + a.value == b.value + } + /// Convert the object to a string + pub fn toString(&self, args: Rest<()>) -> String { + self.value.to_raw() + } + /// Convert the object to JSON + pub fn toJSON(&self, args: Rest<()>) -> String { + self.value.to_raw() } } - - #[qjs(get)] - pub fn tb(&self) -> String { - self.value.tb.clone() - } - - #[qjs(get)] - pub fn id(&self) -> String { - self.value.id.to_raw() - } - // Compare two Record instances - pub fn is(a: &Record, b: &Record) -> bool { - a.value == b.value - } - /// Convert the object to a string - #[qjs(rename = "toString")] - pub fn js_to_string(&self) -> String { - self.value.to_raw() - } - /// Convert the object to JSON - #[qjs(rename = "toJSON")] - pub fn to_json(&self) -> String { - self.value.to_raw() - } } diff --git a/lib/src/fnc/script/classes/uuid.rs b/lib/src/fnc/script/classes/uuid.rs index e89e412e..4f759ec4 100644 --- a/lib/src/fnc/script/classes/uuid.rs +++ b/lib/src/fnc/script/classes/uuid.rs @@ -1,46 +1,51 @@ -use crate::sql::uuid; -use js::class::Trace; +#[js::bind(object, public)] +#[quickjs(bare)] +#[allow(non_snake_case)] +#[allow(unused_variables)] +#[allow(clippy::module_inception)] +pub mod uuid { -#[derive(Clone, Trace)] -#[js::class] -pub struct Uuid { - #[qjs(skip_trace)] - pub(crate) value: Option, -} + use crate::sql::uuid; + use crate::sql::value::Value; + use js::{class::Ref, function::Rest}; -#[js::methods] -impl Uuid { - #[qjs(constructor)] - pub fn new(value: String) -> Self { - Self { - value: uuid::Uuid::try_from(value).ok(), + #[derive(Clone)] + #[quickjs(cloneable)] + pub struct Uuid { + pub(crate) value: Option, + } + + impl Uuid { + #[quickjs(constructor)] + pub fn new(value: String, args: Rest) -> Self { + Self { + value: uuid::Uuid::try_from(value).ok(), + } } - } - #[qjs(get)] - pub fn value(&self) -> String { - match &self.value { - Some(v) => v.to_raw(), - None => String::from("Invalid Uuid"), + #[quickjs(get)] + pub fn value(&self) -> String { + match &self.value { + Some(v) => v.to_raw(), + None => String::from("Invalid Uuid"), + } } - } - // Compare two Uuid instances - pub fn is(a: &Uuid, b: &Uuid) -> bool { - a.value.is_some() && b.value.is_some() && a.value == b.value - } - /// Convert the object to a string - #[qjs(rename = "toString")] - pub fn js_to_string(&self) -> String { - match &self.value { - Some(v) => v.to_raw(), - None => String::from("Invalid Uuid"), + // Compare two Uuid instances + pub fn is<'js>(a: Ref<'js, Uuid>, b: Ref<'js, Uuid>, _args: Rest<()>) -> bool { + a.value.is_some() && b.value.is_some() && a.value == b.value } - } - /// Convert the object to JSON - #[qjs(rename = "toJSON")] - pub fn to_json(&self) -> String { - match &self.value { - Some(v) => v.to_raw(), - None => String::from("Invalid Uuid"), + /// Convert the object to a string + pub fn toString(&self, _args: Rest<()>) -> String { + match &self.value { + Some(v) => v.to_raw(), + None => String::from("Invalid Uuid"), + } + } + /// Convert the object to JSON + pub fn toJSON(&self, _args: Rest<()>) -> String { + match &self.value { + Some(v) => v.to_raw(), + None => String::from("Invalid Uuid"), + } } } } diff --git a/lib/src/fnc/script/fetch/body.rs b/lib/src/fnc/script/fetch/body.rs index 17cb19b7..6e7fa863 100644 --- a/lib/src/fnc/script/fetch/body.rs +++ b/lib/src/fnc/script/fetch/body.rs @@ -1,4 +1,4 @@ -use crate::fnc::script::fetch::{stream::ReadableStream, RequestError}; +use crate::fnc::script::fetch::{classes::BlobClass, stream::ReadableStream, RequestError}; use bytes::{Bytes, BytesMut}; use futures::{future, Stream, TryStreamExt}; use js::{ArrayBuffer, Class, Ctx, Error, Exception, FromJs, Result, Type, TypedArray, Value}; @@ -7,8 +7,6 @@ use std::{ result::Result as StdResult, }; -use super::classes::Blob; - pub type StreamItem = StdResult; #[derive(Clone)] @@ -129,7 +127,7 @@ impl Body { } impl<'js> FromJs<'js> for Body { - fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { + fn from_js(ctx: Ctx<'js>, value: Value<'js>) -> Result { let object = match value.type_of() { Type::String => { let string = value.as_string().unwrap().to_string()?; @@ -144,7 +142,7 @@ impl<'js> FromJs<'js> for Body { }) } }; - if let Some(x) = Class::::from_object(object.clone()) { + if let Ok(x) = Class::::from_object(object.clone()) { let borrow = x.borrow(); return Ok(Body::buffer(BodyKind::Blob(borrow.mime.clone()), borrow.data.clone())); } @@ -196,7 +194,7 @@ impl<'js> FromJs<'js> for Body { .ok_or_else(|| Exception::throw_type(ctx, "Buffer is already detached"))?; return Ok(Body::buffer(BodyKind::Buffer, Bytes::copy_from_slice(bytes))); } - if let Some(x) = ArrayBuffer::from_object(object.clone()) { + if let Ok(x) = ArrayBuffer::from_object(object.clone()) { let bytes = x .as_bytes() .ok_or_else(|| Exception::throw_type(ctx, "Buffer is already detached"))?; diff --git a/lib/src/fnc/script/fetch/classes/blob.rs b/lib/src/fnc/script/fetch/classes/blob.rs index 95e18bb0..a616b4de 100644 --- a/lib/src/fnc/script/fetch/classes/blob.rs +++ b/lib/src/fnc/script/fetch/classes/blob.rs @@ -1,11 +1,9 @@ //! Blob class implementation -use bytes::{Bytes, BytesMut}; -use js::{ - class::Trace, - prelude::{Coerced, Opt}, - ArrayBuffer, Class, Ctx, Exception, FromJs, Object, Result, Value, -}; +use bytes::BytesMut; +use js::{bind, prelude::Coerced, ArrayBuffer, Class, Ctx, Exception, FromJs, Result, Value}; + +pub use blob::Blob as BlobClass; #[derive(Clone, Copy)] pub enum EndingType { @@ -14,7 +12,7 @@ pub enum EndingType { } fn append_blob_part<'js>( - ctx: &Ctx<'js>, + ctx: Ctx<'js>, value: Value<'js>, ending: EndingType, data: &mut BytesMut, @@ -25,11 +23,11 @@ fn append_blob_part<'js>( const LINE_ENDING: &[u8] = b"\n"; if let Some(object) = value.as_object() { - if let Some(x) = Class::::from_object(object.clone()) { + if let Ok(x) = Class::::from_object(object.clone()) { data.extend_from_slice(&x.borrow().data); return Ok(()); } - if let Some(x) = ArrayBuffer::from_object(object.clone()) { + if let Ok(x) = ArrayBuffer::from_object(object.clone()) { data.extend_from_slice(x.as_bytes().ok_or_else(|| { Exception::throw_type(ctx, "Tried to construct blob with detached buffer") })?); @@ -76,121 +74,144 @@ fn normalize_type(mut ty: String) -> String { } } -#[derive(Clone, Trace)] -#[js::class] -pub struct Blob { - pub(crate) mime: String, - // TODO: make bytes? - #[qjs(skip_trace)] - pub(crate) data: Bytes, -} +#[bind(object, public)] +#[quickjs(bare)] +#[allow(non_snake_case)] +#[allow(unused_variables)] +#[allow(clippy::module_inception)] +mod blob { + use super::*; -#[js::methods] -impl Blob { - // ------------------------------ - // Constructor - // ------------------------------ + use bytes::{Bytes, BytesMut}; + use js::{ + function::{Opt, Rest}, + ArrayBuffer, Ctx, Exception, Object, Result, Value, + }; - #[qjs(constructor)] - pub fn new<'js>( - ctx: Ctx<'js>, - parts: Opt>, - options: Opt>, - ) -> Result { - let mut r#type = String::new(); - let mut endings = EndingType::Transparent; + #[derive(Clone)] + #[quickjs(cloneable)] + pub struct Blob { + pub(crate) mime: String, + // TODO: make bytes? + pub(crate) data: Bytes, + } - if let Some(obj) = options.into_inner() { - if let Some(x) = obj.get::<_, Option>>("type")? { - r#type = normalize_type(x.to_string()); - } - if let Some(Coerced(x)) = obj.get::<_, Option>>("endings")? { - if x == "native" { - endings = EndingType::Native; - } else if x != "transparent" { - return Err(Exception::throw_type( - &ctx, - ",expected endings to be either 'transparent' or 'native'", - )); + impl Blob { + // ------------------------------ + // Constructor + // ------------------------------ + + #[quickjs(constructor)] + pub fn new<'js>( + ctx: Ctx<'js>, + parts: Opt>, + options: Opt>, + _rest: Rest<()>, + ) -> Result { + let mut r#type = String::new(); + let mut endings = EndingType::Transparent; + + if let Some(obj) = options.into_inner() { + if let Some(x) = obj.get::<_, Option>>("type")? { + r#type = normalize_type(x.to_string()); + } + if let Some(Coerced(x)) = obj.get::<_, Option>>("endings")? { + if x == "native" { + endings = EndingType::Native; + } else if x != "transparent" { + return Err(Exception::throw_type( + ctx, + ",expected endings to be either 'transparent' or 'native'", + )); + } } } + + let data = if let Some(parts) = parts.into_inner() { + let array = parts + .into_array() + .ok_or_else(|| Exception::throw_type(ctx, "Blob parts are not a sequence"))?; + + let mut buffer = BytesMut::new(); + + for elem in array.iter::() { + let elem = elem?; + append_blob_part(ctx, elem, endings, &mut buffer)?; + } + buffer.freeze() + } else { + Bytes::new() + }; + Ok(Self { + mime: r#type, + data, + }) } - let data = if let Some(parts) = parts.into_inner() { - let array = parts - .into_array() - .ok_or_else(|| Exception::throw_type(&ctx, "Blob parts are not a sequence"))?; + // ------------------------------ + // Instance properties + // ------------------------------ - let mut buffer = BytesMut::new(); + #[quickjs(get)] + pub fn size(&self) -> usize { + self.data.len() + } - for elem in array.iter::() { - let elem = elem?; - append_blob_part(&ctx, elem, endings, &mut buffer)?; + #[quickjs(get)] + #[quickjs(rename = "type")] + pub fn r#type(&self) -> String { + self.mime.clone() + } + + pub fn slice( + &self, + start: Opt, + end: Opt, + content_type: Opt, + _rest: Rest<()>, + ) -> Blob { + // see https://w3c.github.io/FileAPI/#slice-blob + let start = start.into_inner().unwrap_or_default(); + let start = if start < 0 { + (self.data.len() as isize + start).max(0) as usize + } else { + start as usize + }; + let end = end.into_inner().unwrap_or_default(); + let end = if end < 0 { + (self.data.len() as isize + end).max(0) as usize + } else { + end as usize + }; + let data = self.data.slice(start..end); + let content_type = content_type.into_inner().map(normalize_type).unwrap_or_default(); + Blob { + mime: content_type, + data, } - buffer.freeze() - } else { - Bytes::new() - }; - Ok(Self { - mime: r#type, - data, - }) - } - - // ------------------------------ - // Instance properties - // ------------------------------ - - #[qjs(get)] - pub fn size(&self) -> usize { - self.data.len() - } - - #[qjs(get, rename = "type")] - pub fn r#type(&self) -> String { - self.mime.clone() - } - - pub fn slice(&self, start: Opt, end: Opt, content_type: Opt) -> Blob { - // see https://w3c.github.io/FileAPI/#slice-blob - let start = start.into_inner().unwrap_or_default(); - let start = if start < 0 { - (self.data.len() as isize + start).max(0) as usize - } else { - start as usize - }; - let end = end.into_inner().unwrap_or_default(); - let end = if end < 0 { - (self.data.len() as isize + end).max(0) as usize - } else { - end as usize - }; - let data = self.data.slice(start..end); - let content_type = content_type.into_inner().map(normalize_type).unwrap_or_default(); - Blob { - mime: content_type, - data, } - } - pub async fn text(&self) -> Result { - let text = String::from_utf8(self.data.to_vec())?; - Ok(text) - } + pub async fn text(&self, _rest: Rest<()>) -> Result { + let text = String::from_utf8(self.data.to_vec())?; + Ok(text) + } - #[qjs(rename = "arrayBuffer")] - pub async fn array_buffer<'js>(&self, ctx: Ctx<'js>) -> Result> { - ArrayBuffer::new(ctx, self.data.to_vec()) - } + pub async fn arrayBuffer<'js>( + &self, + ctx: Ctx<'js>, + _rest: Rest<()>, + ) -> Result> { + ArrayBuffer::new(ctx, self.data.to_vec()) + } - // ------------------------------ - // Instance methods - // ------------------------------ + // ------------------------------ + // Instance methods + // ------------------------------ - // Convert the object to a string - #[qjs(rename = "toString")] - pub fn js_to_string(&self) -> String { - String::from("[object Blob]") + // Convert the object to a string + pub fn toString(&self, _rest: Rest<()>) -> String { + String::from("[object Blob]") + } } } @@ -221,17 +242,17 @@ mod test { blob = new Blob(["\n\r\n \n\r"],{endings: "transparent"}); assert.eq(blob.size,6) - assert.eq(await blob.text(),"\n\r\n \n\r"); + assert.eq(await blob.text(),"\n\r\n \n\r"); blob = new Blob(["\n\r\n \n\r"],{endings: "native"}); // \n \r\n and the \n from \n\r are converted. // the part of the string which isn't converted is the space and the \r assert.eq(await blob.text(),`${NATIVE_LINE_ENDING}${NATIVE_LINE_ENDING} ${NATIVE_LINE_ENDING}\r`); assert.eq(blob.size,NATIVE_LINE_ENDING.length*3 + 2) - assert.mustThrow(() => new Blob("text")); + assert.mustThrow(() => new Blob("text")); assert.mustThrow(() => new Blob(["text"], {endings: "invalid value"})); })() - "#).catch(&ctx).unwrap().await.catch(&ctx).unwrap(); + "#).catch(ctx).unwrap().await.catch(ctx).unwrap(); }) .await } diff --git a/lib/src/fnc/script/fetch/classes/form_data.rs b/lib/src/fnc/script/fetch/classes/form_data.rs index a963bc98..f77cd8f7 100644 --- a/lib/src/fnc/script/fetch/classes/form_data.rs +++ b/lib/src/fnc/script/fetch/classes/form_data.rs @@ -1,36 +1,34 @@ //! FormData class implementation use js::{ - class::{Class, Trace}, - function::{Opt, Rest}, - prelude::Coerced, - Ctx, Exception, FromJs, Result, String, Value, + bind, function::Opt, prelude::Coerced, Class, Ctx, Exception, FromJs, Persistent, Result, + String, Value, }; -use reqwest::multipart::{Form, Part}; -use std::{collections::HashMap, string::String as StdString}; +use std::string::String as StdString; -use crate::fnc::script::fetch::classes::Blob; +use crate::fnc::script::fetch::classes::BlobClass; #[derive(Clone)] -pub enum FormDataValue<'js> { - String(String<'js>), +pub enum FormDataValue { + String(Persistent>), Blob { - data: Class<'js, Blob>, - filename: Option>, + data: Persistent>, + filename: Option>>, }, } -impl<'js> FormDataValue<'js> { - fn from_arguments( - ctx: &Ctx<'js>, +impl FormDataValue { + fn from_arguments<'js>( + ctx: Ctx<'js>, value: Value<'js>, filename: Opt>>, error: &'static str, - ) -> Result { + ) -> Result { if let Some(blob) = - value.as_object().and_then(|value| Class::::from_object(value.clone())) + value.as_object().and_then(|value| Class::::from_object(value.clone()).ok()) { - let filename = filename.into_inner().map(|x| x.0); + let blob = Persistent::save(ctx, blob); + let filename = filename.into_inner().map(|x| Persistent::save(ctx, x.0)); Ok(FormDataValue::Blob { data: blob, @@ -40,109 +38,128 @@ impl<'js> FormDataValue<'js> { return Err(Exception::throw_type(ctx, error)); } else { let value = Coerced::::from_js(ctx, value)?; - Ok(FormDataValue::String(value.0)) + let value = Persistent::save(ctx, value.0); + Ok(FormDataValue::String(value)) } } } -#[js::class] -#[derive(Clone, Trace)] -pub struct FormData<'js> { - #[qjs(skip_trace)] - pub(crate) values: HashMap>>, -} +pub use form_data::FormData as FormDataClass; +#[bind(object, public)] +#[quickjs(bare)] +#[allow(non_snake_case)] +#[allow(unused_variables)] +#[allow(clippy::module_inception)] +pub mod form_data { + use super::*; + use std::{cell::RefCell, collections::HashMap}; -#[js::methods] -impl<'js> FormData<'js> { - // ------------------------------ - // Constructor - // ------------------------------ + use js::{ + function::Opt, + prelude::{Coerced, Rest}, + Ctx, Result, String, Value, + }; + use reqwest::multipart::{Form, Part}; - // FormData spec states that FormDa takes two html elements as arguments - // which does not make sense implementing fetch outside a browser. - // So we ignore those arguments. - #[qjs(constructor)] - pub fn new(ctx: Ctx<'js>, args: Rest<()>) -> Result { - if args.len() > 0 { - return Err(Exception::throw_internal( - &ctx, - "Cant call FormData with arguments as the dom elements required are not available", - )); + #[derive(Clone)] + #[quickjs(cloneable)] + pub struct FormData { + pub(crate) values: RefCell>>, + } + + impl FormData { + // ------------------------------ + // Constructor + // ------------------------------ + + // FormData spec states that FormDa takes two html elements as arguments + // which does not make sense implementing fetch outside a browser. + // So we ignore those arguments. + #[quickjs(constructor)] + pub fn new(ctx: Ctx<'_>, args: Rest<()>) -> Result { + if args.len() > 0 { + return Err(Exception::throw_internal(ctx,"Cant call FormData with arguments as the dom elements required are not available")); + } + Ok(FormData { + values: RefCell::new(HashMap::new()), + }) } - Ok(FormData { - values: HashMap::new(), - }) - } - pub fn append( - &mut self, - ctx: Ctx<'js>, - name: Coerced, - value: Value<'js>, - filename: Opt>>, - ) -> Result<()> { - let value = FormDataValue::from_arguments( - &ctx, - value, - filename, - "Can't call `append` on `FormData` with a filename when value isn't of type `Blob`", - )?; + pub fn append<'js>( + &self, + ctx: Ctx<'js>, + name: Coerced, + value: Value<'js>, + filename: Opt>>, + ) -> Result<()> { + let value = FormDataValue::from_arguments( + ctx, + value, + filename, + "Can't call `append` on `FormData` with a filename when value isn't of type `Blob`", + )?; - self.values.entry(name.0).or_insert_with(Vec::new).push(value); + self.values.borrow_mut().entry(name.0).or_insert_with(Vec::new).push(value); - Ok(()) - } + Ok(()) + } - pub fn set( - &mut self, - ctx: Ctx<'js>, - name: Coerced, - value: Value<'js>, - filename: Opt>>, - ) -> Result<()> { - let value = FormDataValue::from_arguments( - &ctx, - value, - filename, - "Can't call `set` on `FormData` with a filename when value isn't of type `Blob`", - )?; + pub fn set<'js>( + &self, + ctx: Ctx<'js>, + name: Coerced, + value: Value<'js>, + filename: Opt>>, + ) -> Result<()> { + let value = FormDataValue::from_arguments( + ctx, + value, + filename, + "Can't call `set` on `FormData` with a filename when value isn't of type `Blob`", + )?; - self.values.insert(name.0, vec![value]); + self.values.borrow_mut().insert(name.0, vec![value]); - Ok(()) - } + Ok(()) + } - pub fn has(&self, name: Coerced) -> bool { - self.values.contains_key(&name.0) - } + pub fn has(&self, ctx: Ctx<'_>, name: Coerced) -> bool { + self.values.borrow().contains_key(&name.0) + } - pub fn delete(&mut self, name: Coerced) { - self.values.remove(&name.0); - } + pub fn delete(&self, ctx: Ctx<'_>, name: Coerced) { + self.values.borrow_mut().remove(&name.0); + } - #[qjs(skip)] - pub fn to_form(&self) -> Result
{ - let mut res = Form::new(); - for (k, v) in self.values.iter() { - for v in v { - match v { - FormDataValue::String(x) => { - res = res.text(k.clone(), x.to_string()?); - } - FormDataValue::Blob { - data, - filename, - } => { - let mut part = Part::bytes(data.borrow().data.to_vec()); - if let Some(filename) = filename { - let filename = filename.to_string()?; - part = part.file_name(filename); + #[quickjs(skip)] + pub fn to_form(&self, ctx: Ctx<'_>) -> Result { + let lock = self.values.borrow(); + let mut res = Form::new(); + for (k, v) in lock.iter() { + for v in v { + match v { + FormDataValue::String(x) => { + let x = x.clone().restore(ctx).unwrap(); + res = res.text(k.clone(), x.to_string()?); + } + FormDataValue::Blob { + data, + filename, + } => { + let mut part = Part::bytes( + data.clone().restore(ctx).unwrap().borrow().data.to_vec(), + ); + if let Some(filename) = filename { + let filename = + filename.clone().restore(ctx).unwrap().to_string()?; + part = part.file_name(filename); + } + res = res.part(k.clone(), part); } - res = res.part(k.clone(), part); } } } + Ok(res) } - Ok(res) } } diff --git a/lib/src/fnc/script/fetch/classes/headers.rs b/lib/src/fnc/script/fetch/classes/headers.rs index ecb015d0..01e06053 100644 --- a/lib/src/fnc/script/fetch/classes/headers.rs +++ b/lib/src/fnc/script/fetch/classes/headers.rs @@ -1,258 +1,272 @@ //! Headers class implementation -use std::str::FromStr; +use js::bind; -use js::{ - class::Trace, - prelude::{Coerced, List}, - Array, Ctx, Exception, Result, Value, -}; -use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; +pub use headers::Headers as HeadersClass; -#[derive(Clone, Trace)] -#[js::class] -pub struct Headers { - #[qjs(skip_trace)] - pub(crate) inner: HeaderMap, -} +#[bind(object, public)] +#[quickjs(bare)] +#[allow(non_snake_case)] +#[allow(unused_variables)] +#[allow(clippy::module_inception)] +mod headers { + use std::{cell::RefCell, str::FromStr}; -#[js::methods] -impl Headers { - // ------------------------------ - // Constructor - // ------------------------------ + use js::{function::Rest, prelude::Coerced, Array, Ctx, Exception, Result, Value}; + use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; - #[qjs(constructor)] - pub fn new<'js>(ctx: Ctx<'js>, init: Value<'js>) -> Result { - Headers::new_inner(&ctx, init) + #[derive(Clone)] + #[quickjs(cloneable)] + #[allow(dead_code)] + pub struct Headers { + pub(crate) inner: RefCell, } - // ------------------------------ - // Instance methods - // ------------------------------ + impl Headers { + // ------------------------------ + // Constructor + // ------------------------------ - // Convert the object to a string - #[qjs(rename = "toString")] - pub fn js_to_string(&self) -> String { - String::from("[object Header]") + #[quickjs(constructor)] + pub fn new<'js>(ctx: Ctx<'js>, init: Value<'js>, args: Rest<()>) -> Result { + Headers::new_inner(ctx, init) + } + + // ------------------------------ + // Instance methods + // ------------------------------ + + // Convert the object to a string + pub fn toString(&self, args: Rest<()>) -> String { + String::from("[object Header]") + } + + // Adds or appends a new value to a header + pub fn append(&self, ctx: Ctx<'_>, key: String, val: String, args: Rest<()>) -> Result<()> { + self.append_inner(ctx, &key, &val) + } + + // Deletes a header from the header set + pub fn delete(&self, ctx: Ctx<'_>, key: String, args: Rest<()>) -> Result<()> { + // Process and check the header name is valid + let key = HeaderName::from_str(&key) + .map_err(|e| Exception::throw_type(ctx, &format!("{e}")))?; + // Remove the header entry from the map + self.inner.borrow_mut().remove(&key); + // Everything ok + Ok(()) + } + + // Returns all header entries in the header set + pub fn entries(&self, args: Rest<()>) -> Vec<(String, String)> { + let lock = self.inner.borrow(); + let mut res = Vec::<(String, String)>::with_capacity(lock.len()); + + for (k, v) in lock.iter() { + let k = k.as_str(); + if Some(k) == res.last().map(|x| x.0.as_str()) { + let ent = res.last_mut().unwrap(); + ent.1.push_str(", "); + // Header value came from a string, so it should also be able to be cast back + // to a string + ent.1.push_str(v.to_str().unwrap()); + } else { + res.push((k.to_owned(), v.to_str().unwrap().to_owned())); + } + } + + res + } + + // Returns all values of a header in the header set + pub fn get(&self, ctx: Ctx<'_>, key: String, args: Rest<()>) -> Result> { + // Process and check the header name is valid + let key = HeaderName::from_str(&key) + .map_err(|e| Exception::throw_type(ctx, &format!("{e}")))?; + // Convert the header values to strings + let lock = self.inner.borrow(); + let all = lock.get_all(&key); + + // Header value came from a string, so it should also be able to be cast back + // to a string + let mut res = String::new(); + for (idx, v) in all.iter().enumerate() { + if idx != 0 { + res.push_str(", "); + } + res.push_str(v.to_str().unwrap()); + } + + if res.is_empty() { + return Ok(None); + } + Ok(Some(res)) + } + + // Returns all values for the `Set-Cookie` header. + #[quickjs(rename = "getSetCookie")] + pub fn get_set_cookie(&self, args: Rest<()>) -> Vec { + // This should always be a correct cookie; + let key = HeaderName::from_str("set-cookie").unwrap(); + self.inner + .borrow() + .get_all(key) + .iter() + .map(|x| x.to_str().unwrap().to_owned()) + .collect() + } + + // Checks to see if the header set contains a header + pub fn has(&self, ctx: Ctx<'_>, key: String, args: Rest<()>) -> Result { + // Process and check the header name is valid + let key = HeaderName::from_str(&key) + .map_err(|e| Exception::throw_type(ctx, &format!("{e}")))?; + // Check if the header entry exists + Ok(self.inner.borrow().contains_key(&key)) + } + + // Returns all header keys contained in the header set + pub fn keys(&self, args: Rest<()>) -> Vec { + // TODO: Incorrect, should return an iterator but iterators are not supported yet by quickjs + self.inner.borrow().keys().map(|v| v.as_str().to_owned()).collect::>() + } + + // Sets a new value or adds a header to the header set + pub fn set(&self, ctx: Ctx<'_>, key: String, val: String, args: Rest<()>) -> Result<()> { + // Process and check the header name is valid + let key = HeaderName::from_str(&key) + .map_err(|e| Exception::throw_type(ctx, &format!("Invalid header name: {e}")))?; + // Process and check the header name is valid + let val = HeaderValue::from_str(&val) + .map_err(|e| Exception::throw_type(ctx, &format!("Invalid header value: {e}")))?; + // Insert and overwrite the header entry + self.inner.borrow_mut().insert(key, val); + // Everything ok + Ok(()) + } + + // Returns all header values contained in the header set + pub fn values(&self, args: Rest<()>) -> Vec { + let lock = self.inner.borrow(); + let mut res = Vec::::with_capacity(lock.len()); + + let mut pref = None; + for (k, v) in lock.iter() { + if Some(k) == pref { + let ent = res.last_mut().unwrap(); + ent.push_str(", "); + ent.push_str(v.to_str().unwrap()) + } else { + pref = Some(k); + res.push(v.to_str().unwrap().to_owned()); + } + } + + res + } } - // Adds or appends a new value to a header - pub fn append(&mut self, ctx: Ctx<'_>, key: String, val: String) -> Result<()> { - self.append_inner(&ctx, &key, &val) - } + #[quickjs(skip)] + impl Headers { + pub fn from_map(map: HeaderMap) -> Self { + Self { + inner: RefCell::new(map), + } + } - // Deletes a header from the header set - pub fn delete(&mut self, ctx: Ctx<'_>, key: String) -> Result<()> { - // Process and check the header name is valid - let key = - HeaderName::from_str(&key).map_err(|e| Exception::throw_type(&ctx, &format!("{e}")))?; - // Remove the header entry from the map - self.inner.remove(&key); - // Everything ok - Ok(()) - } + pub fn new_empty() -> Self { + Self::from_map(HeaderMap::new()) + } - // Returns all header entries in the header set - pub fn entries(&self) -> Vec> { - let mut res = Vec::>::with_capacity(self.inner.len()); + pub fn new_inner<'js>(ctx: Ctx<'js>, val: Value<'js>) -> Result { + static INVALID_ERROR: &str = "Headers constructor: init was neither sequence> or record"; + let res = Self::new_empty(); - for (k, v) in self.inner.iter() { - let k = k.as_str(); - if Some(k) == res.last().map(|x| x.0 .0.as_str()) { - let ent = res.last_mut().unwrap(); - ent.0 .1.push_str(", "); - // Header value came from a string, so it should also be able to be cast back - // to a string - ent.0 .1.push_str(v.to_str().unwrap()); + // TODO Set and Map, + if let Some(array) = val.as_array() { + // a sequence>; + for v in array.iter::() { + let v = match v { + Ok(x) => x, + Err(e) => { + if e.is_from_js() { + return Err(Exception::throw_type(ctx, INVALID_ERROR)); + } + return Err(e); + } + }; + let key = match v.get::>(0) { + Ok(x) => x, + Err(e) => { + if e.is_from_js() { + return Err(Exception::throw_type(ctx, INVALID_ERROR)); + } + return Err(e); + } + }; + let value = match v.get::>(1) { + Ok(x) => x, + Err(e) => { + if e.is_from_js() { + return Err(Exception::throw_type(ctx, INVALID_ERROR)); + } + return Err(e); + } + }; + res.append_inner(ctx, &key, &value)?; + } + } else if let Some(obj) = val.as_object() { + // a record; + for prop in obj.props::>() { + let (key, value) = match prop { + Ok(x) => x, + Err(e) => { + if e.is_from_js() { + return Err(Exception::throw_type(ctx, INVALID_ERROR)); + } + return Err(e); + } + }; + res.append_inner(ctx, &key, &value.0)?; + } } else { - res.push(List((k.to_owned(), v.to_str().unwrap().to_owned()))); + return Err(Exception::throw_type(ctx, INVALID_ERROR)); } + + Ok(res) } - res - } + fn append_inner(&self, ctx: Ctx<'_>, key: &str, val: &str) -> Result<()> { + // Unsure what to do exactly here. + // Spec dictates normalizing string before adding it as a header value, i.e. removing + // any leading and trailing whitespace: + // [`https://fetch.spec.whatwg.org/#concept-header-value-normalize`] + // But non of the platforms I tested, normalize, instead they throw an error + // with `Invalid header value`. I'll chose to just do what the platforms do. - // Returns all values of a header in the header set - pub fn get(&self, ctx: Ctx<'_>, key: String) -> Result> { - // Process and check the header name is valid - let key = - HeaderName::from_str(&key).map_err(|e| Exception::throw_type(&ctx, &format!("{e}")))?; - // Convert the header values to strings - let all = self.inner.get_all(&key); + let key = match HeaderName::from_bytes(key.as_bytes()) { + Ok(x) => x, + Err(e) => { + return Err(Exception::throw_type( + ctx, + &format!("invalid header name `{key}`: {e}"), + )) + } + }; + let val = match HeaderValue::from_bytes(val.as_bytes()) { + Ok(x) => x, + Err(e) => { + return Err(Exception::throw_type( + ctx, + &format!("invalid header value `{val}`: {e}"), + )) + } + }; - // Header value came from a string, so it should also be able to be cast back - // to a string - let mut res = String::new(); - for (idx, v) in all.iter().enumerate() { - if idx != 0 { - res.push_str(", "); - } - res.push_str(v.to_str().unwrap()); + self.inner.borrow_mut().append(key, val); + + Ok(()) } - - if res.is_empty() { - return Ok(None); - } - Ok(Some(res)) - } - - // Returns all values for the `Set-Cookie` header. - #[qjs(rename = "getSetCookie")] - pub fn get_set_cookie(&self) -> Vec { - // This should always be a correct cookie; - let key = HeaderName::from_str("set-cookie").unwrap(); - self.inner.get_all(key).iter().map(|x| x.to_str().unwrap().to_owned()).collect() - } - - // Checks to see if the header set contains a header - pub fn has(&self, ctx: Ctx<'_>, key: String) -> Result { - // Process and check the header name is valid - let key = - HeaderName::from_str(&key).map_err(|e| Exception::throw_type(&ctx, &format!("{e}")))?; - // Check if the header entry exists - Ok(self.inner.contains_key(&key)) - } - - // Returns all header keys contained in the header set - pub fn keys(&self) -> Vec { - // TODO: Incorrect, should return an iterator but iterators are not supported yet by quickjs - self.inner.keys().map(|v| v.as_str().to_owned()).collect::>() - } - - // Sets a new value or adds a header to the header set - pub fn set(&mut self, ctx: Ctx<'_>, key: String, val: String) -> Result<()> { - // Process and check the header name is valid - let key = HeaderName::from_str(&key) - .map_err(|e| Exception::throw_type(&ctx, &format!("Invalid header name: {e}")))?; - // Process and check the header name is valid - let val = HeaderValue::from_str(&val) - .map_err(|e| Exception::throw_type(&ctx, &format!("Invalid header value: {e}")))?; - // Insert and overwrite the header entry - self.inner.insert(key, val); - // Everything ok - Ok(()) - } - - // Returns all header values contained in the header set - pub fn values(&self) -> Vec { - let mut res = Vec::::with_capacity(self.inner.len()); - - let mut pref = None; - for (k, v) in self.inner.iter() { - if Some(k) == pref { - let ent = res.last_mut().unwrap(); - ent.push_str(", "); - ent.push_str(v.to_str().unwrap()) - } else { - pref = Some(k); - res.push(v.to_str().unwrap().to_owned()); - } - } - - res - } -} - -impl Headers { - pub fn from_map(map: HeaderMap) -> Self { - Self { - inner: map, - } - } - - pub fn new_empty() -> Self { - Self::from_map(HeaderMap::new()) - } - - pub fn new_inner<'js>(ctx: &Ctx<'js>, val: Value<'js>) -> Result { - static INVALID_ERROR: &str = "Headers constructor: init was neither sequence> or record"; - let mut res = Self::new_empty(); - - // TODO Set and Map, - if let Some(array) = val.as_array() { - // a sequence>; - for v in array.iter::() { - let v = match v { - Ok(x) => x, - Err(e) => { - if e.is_from_js() { - return Err(Exception::throw_type(ctx, INVALID_ERROR)); - } - return Err(e); - } - }; - let key = match v.get::>(0) { - Ok(x) => x, - Err(e) => { - if e.is_from_js() { - return Err(Exception::throw_type(ctx, INVALID_ERROR)); - } - return Err(e); - } - }; - let value = match v.get::>(1) { - Ok(x) => x, - Err(e) => { - if e.is_from_js() { - return Err(Exception::throw_type(ctx, INVALID_ERROR)); - } - return Err(e); - } - }; - res.append_inner(ctx, &key, &value)?; - } - } else if let Some(obj) = val.as_object() { - // a record; - for prop in obj.props::>() { - let (key, value) = match prop { - Ok(x) => x, - Err(e) => { - if e.is_from_js() { - return Err(Exception::throw_type(ctx, INVALID_ERROR)); - } - return Err(e); - } - }; - res.append_inner(ctx, &key, &value.0)?; - } - } else { - return Err(Exception::throw_type(ctx, INVALID_ERROR)); - } - - Ok(res) - } - - fn append_inner(&mut self, ctx: &Ctx<'_>, key: &str, val: &str) -> Result<()> { - // Unsure what to do exactly here. - // Spec dictates normalizing string before adding it as a header value, i.e. removing - // any leading and trailing whitespace: - // [`https://fetch.spec.whatwg.org/#concept-header-value-normalize`] - // But non of the platforms I tested, normalize, instead they throw an error - // with `Invalid header value`. I'll chose to just do what the platforms do. - - let key = match HeaderName::from_bytes(key.as_bytes()) { - Ok(x) => x, - Err(e) => { - return Err(Exception::throw_type( - ctx, - &format!("invalid header name `{key}`: {e}"), - )) - } - }; - let val = match HeaderValue::from_bytes(val.as_bytes()) { - Ok(x) => x, - Err(e) => { - return Err(Exception::throw_type( - ctx, - &format!("invalid header value `{val}`: {e}"), - )) - } - }; - - self.inner.append(key, val); - - Ok(()) } } @@ -313,7 +327,7 @@ mod test { }); assert.seq(headers.get("f"), "g"); assert.seq(headers.get("h"), "j"); - "#).catch(&ctx).unwrap(); + "#).catch(ctx).unwrap(); }) .await } diff --git a/lib/src/fnc/script/fetch/classes/request.rs b/lib/src/fnc/script/fetch/classes/request.rs index aae64746..f57c982e 100644 --- a/lib/src/fnc/script/fetch/classes/request.rs +++ b/lib/src/fnc/script/fetch/classes/request.rs @@ -1,9 +1,18 @@ //! Request class implementation - -use js::{class::Trace, prelude::Coerced, Class, Ctx, Exception, FromJs, Object, Result, Value}; +//! +use js::{ + bind, + class::{HasRefs, RefsMarker}, + prelude::Coerced, + Class, Ctx, Exception, FromJs, Object, Persistent, Result, Value, +}; use reqwest::Method; -use crate::fnc::script::fetch::{body::Body, RequestError}; +use crate::fnc::script::fetch::{ + body::Body, + classes::{BlobClass, HeadersClass}, + RequestError, +}; #[derive(Clone, Copy, Eq, PartialEq)] pub enum RequestMode { @@ -14,7 +23,7 @@ pub enum RequestMode { } impl<'js> FromJs<'js> for RequestMode { - fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { + fn from_js(ctx: Ctx<'js>, value: Value<'js>) -> Result { let res = if let Some(Coerced(x)) = >>::from_js(ctx, value)? { match x.as_str() { "navigate" => RequestMode::Navigate, @@ -50,7 +59,7 @@ pub enum RequestCredentials { } impl<'js> FromJs<'js> for RequestCredentials { - fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { + fn from_js(ctx: Ctx<'js>, value: Value<'js>) -> Result { let res = if let Some(Coerced(x)) = >>::from_js(ctx, value)? { match x.as_str() { "omit" => RequestCredentials::Omit, @@ -87,7 +96,7 @@ pub enum RequestCache { } impl<'js> FromJs<'js> for RequestCache { - fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { + fn from_js(ctx: Ctx<'js>, value: Value<'js>) -> Result { let res = if let Some(Coerced(x)) = >>::from_js(ctx, value)? { match x.as_str() { "default" => RequestCache::Default, @@ -127,7 +136,7 @@ pub enum RequestRedirect { } impl<'js> FromJs<'js> for RequestRedirect { - fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { + fn from_js(ctx: Ctx<'js>, value: Value<'js>) -> Result { let res = if let Some(Coerced(x)) = >>::from_js(ctx, value)? { match x.as_str() { "follow" => RequestRedirect::Follow, @@ -167,7 +176,7 @@ pub enum ReferrerPolicy { } impl<'js> FromJs<'js> for ReferrerPolicy { - fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { + fn from_js(ctx: Ctx<'js>, value: Value<'js>) -> Result { let res = if let Some(Coerced(x)) = >>::from_js(ctx, value)? { match x.as_str() { "" => ReferrerPolicy::Empty, @@ -204,9 +213,9 @@ impl<'js> FromJs<'js> for ReferrerPolicy { } } -pub struct RequestInit<'js> { +pub struct RequestInit { pub method: Method, - pub headers: Class<'js, Headers>, + pub headers: Persistent>, pub body: Option, pub referrer: String, pub referrer_policy: ReferrerPolicy, @@ -218,15 +227,15 @@ pub struct RequestInit<'js> { pub keep_alive: bool, } -impl<'js> Trace<'js> for RequestInit<'js> { - fn trace<'a>(&self, tracer: js::class::Tracer<'a, 'js>) { - self.headers.trace(tracer); +impl HasRefs for RequestInit { + fn mark_refs(&self, marker: &RefsMarker) { + self.headers.mark_refs(marker); } } -impl<'js> RequestInit<'js> { - pub fn default(ctx: Ctx<'js>) -> Result { - let headers = Class::instance(ctx, Headers::new_empty())?; +impl RequestInit { + pub fn default(ctx: Ctx<'_>) -> Result { + let headers = Persistent::save(ctx, Class::instance(ctx, HeadersClass::new_empty())?); Ok(RequestInit { method: Method::GET, headers, @@ -242,9 +251,9 @@ impl<'js> RequestInit<'js> { }) } - pub fn clone_js(&self, ctx: Ctx<'js>) -> Result { - let headers = self.headers.clone(); - let headers = Class::instance(ctx.clone(), headers.borrow().clone())?; + pub fn clone_js(&self, ctx: Ctx<'_>) -> Result { + let headers = self.headers.clone().restore(ctx).unwrap(); + let headers = Persistent::save(ctx, Class::instance(ctx, headers.borrow().clone())?); let body = self.body.as_ref().map(|x| x.clone_js(ctx)); @@ -265,7 +274,7 @@ impl<'js> RequestInit<'js> { } // Normalize method string according to spec. -fn normalize_method(ctx: &Ctx<'_>, m: String) -> Result { +fn normalize_method(ctx: Ctx<'_>, m: String) -> Result { if m.as_bytes().eq_ignore_ascii_case(b"CONNECT") || m.as_bytes().eq_ignore_ascii_case(b"TRACE") || m.as_bytes().eq_ignore_ascii_case(b"TRACK") @@ -300,8 +309,8 @@ fn normalize_method(ctx: &Ctx<'_>, m: String) -> Result { } } -impl<'js> FromJs<'js> for RequestInit<'js> { - fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { +impl<'js> FromJs<'js> for RequestInit { + fn from_js(ctx: Ctx<'js>, value: Value<'js>) -> Result { let object = Object::from_js(ctx, value)?; let referrer = object @@ -337,14 +346,15 @@ impl<'js> FromJs<'js> for RequestInit<'js> { } let headers = if let Some(hdrs) = object.get::<_, Option>("headers")? { - if let Some(cls) = Class::::from_object(hdrs.clone()) { + if let Ok(cls) = Class::::from_object(hdrs.clone()) { cls } else { - Class::instance(ctx.clone(), Headers::new_inner(ctx, hdrs.into_value())?)? + Class::instance(ctx, HeadersClass::new_inner(ctx, hdrs.into_value())?)? } } else { - Class::instance(ctx.clone(), Headers::new_empty())? + Class::instance(ctx, HeadersClass::new_empty())? }; + let headers = Persistent::save(ctx, headers); let body = object.get::<_, Option>("body")?; @@ -366,173 +376,192 @@ impl<'js> FromJs<'js> for RequestInit<'js> { pub use request::Request as RequestClass; -pub use super::*; +#[bind(object, public)] +#[quickjs(bare)] +#[allow(non_snake_case)] +#[allow(unused_variables)] +#[allow(clippy::module_inception)] +mod request { -use bytes::Bytes; -use js::function::Opt; -// TODO: change implementation based on features. -use reqwest::{header::HeaderName, Url}; + pub use super::*; -#[allow(dead_code)] -#[js::class] -#[derive(Trace)] -pub struct Request<'js> { - #[qjs(skip_trace)] - pub(crate) url: Url, - pub(crate) init: RequestInit<'js>, -} + use bytes::Bytes; + use js::{ + function::{Opt, Rest}, + Class, Ctx, Exception, HasRefs, Result, Value, + }; + // TODO: change implementation based on features. + use reqwest::{header::HeaderName, Url}; -#[js::methods] -impl<'js> Request<'js> { - // ------------------------------ - // Constructor - // ------------------------------ - - #[qjs(constructor)] - pub fn new(ctx: Ctx<'js>, input: Value<'js>, init: Opt>) -> Result { - if let Some(url) = input.as_string() { - // url string - let url_str = url.to_string()?; - let url = Url::parse(&url_str) - .map_err(|e| Exception::throw_type(&ctx, &format!("failed to parse url: {e}")))?; - if !url.username().is_empty() || !url.password().map(str::is_empty).unwrap_or(true) { - // url cannot contain non empty username and passwords - return Err(Exception::throw_type(&ctx, "Url contained credentials.")); - } - let init = init.into_inner().map_or_else(|| RequestInit::default(ctx.clone()), Ok)?; - // HEAD and GET methods can't have a body - if init.body.is_some() && init.method == Method::GET || init.method == Method::HEAD { - return Err(Exception::throw_type( - &ctx, - &format!("Request with method `{}` cannot have a body", init.method), - )); - } - - Ok(Self { - url, - init, - }) - } else if let Some(request) = input.into_object().and_then(Class::::from_object) { - // existing request object, just return it - request.try_borrow()?.clone_js(ctx.clone()) - } else { - Err(Exception::throw_type( - &ctx, - "request `init` paramater must either be a request object or a string", - )) - } + #[allow(dead_code)] + #[derive(HasRefs)] + #[quickjs(has_refs)] + pub struct Request { + pub(crate) url: Url, + #[quickjs(has_refs)] + pub(crate) init: RequestInit, } - /// Clone the response, teeing any possible underlying streams. - #[qjs(rename = "clone")] - pub fn clone_js(&self, ctx: Ctx<'js>) -> Result { - Ok(Self { - url: self.url.clone(), - init: self.init.clone_js(ctx)?, - }) - } + impl Request { + // ------------------------------ + // Constructor + // ------------------------------ - // ------------------------------ - // Instance properties - // ------------------------------ - #[qjs(get, rename = "body_used")] - pub fn body_used(&self) -> bool { - self.init.body.as_ref().map(Body::used).unwrap_or(true) - } - - #[qjs(get)] - pub fn method(&self) -> String { - self.init.method.to_string() - } - - #[qjs(get)] - pub fn url(&self) -> String { - self.url.to_string() - } - - #[qjs(get)] - pub fn headers(&self) -> Class<'js, Headers> { - self.init.headers.clone() - } - - #[qjs(get)] - pub fn referrer(&self) -> String { - self.init.referrer.clone() - } - // TODO - - // ------------------------------ - // Instance methods - // ------------------------------ - - // Convert the object to a string - #[qjs(rename = "toString")] - pub fn js_to_string(&self) -> String { - String::from("[object Request]") - } - - /// Takes the buffer from the body leaving it used. - #[qjs(skip)] - async fn take_buffer(&self, ctx: &Ctx<'js>) -> Result { - let Some(body) = self.init.body.as_ref() else { - return Ok(Bytes::new()); - }; - match body.to_buffer().await { - Ok(Some(x)) => Ok(x), - Ok(None) => Err(Exception::throw_type(ctx, "Body unusable")), - Err(e) => match e { - RequestError::Reqwest(e) => { - Err(Exception::throw_type(ctx, &format!("stream failed: {e}"))) + #[quickjs(constructor)] + pub fn new<'js>( + ctx: Ctx<'js>, + input: Value<'js>, + init: Opt, + args: Rest<()>, + ) -> Result { + if let Some(url) = input.as_string() { + // url string + let url_str = url.to_string()?; + let url = Url::parse(&url_str).map_err(|e| { + Exception::throw_type(ctx, &format!("failed to parse url: {e}")) + })?; + if !url.username().is_empty() || !url.password().map(str::is_empty).unwrap_or(true) + { + // url cannot contain non empty username and passwords + return Err(Exception::throw_type(ctx, "Url contained credentials.")); } - }, + let init = init.into_inner().map_or_else(|| RequestInit::default(ctx), Ok)?; + // HEAD and GET methods can't have a body + if init.body.is_some() && init.method == Method::GET || init.method == Method::HEAD + { + return Err(Exception::throw_type( + ctx, + &format!("Request with method `{}` cannot have a body", init.method), + )); + } + + Ok(Self { + url, + init, + }) + } else if let Some(request) = input + .into_object() + .and_then(|obj| Class::::from_object(obj).ok().map(|x| x.borrow())) + { + // existing request object, just return it + request.clone_js(ctx, Default::default()) + } else { + Err(Exception::throw_type( + ctx, + "request `init` paramater must either be a request object or a string", + )) + } } - } - // Returns a promise with the request body as a Blob - pub async fn blob(&self, ctx: Ctx<'js>) -> Result { - let headers = self.init.headers.clone(); - let mime = { - let headers = headers.borrow(); - let headers = &headers.inner; - let key = HeaderName::from_static("content-type"); - let types = headers.get_all(key); - // TODO: This is not according to spec. - types - .iter() - .next() - .map(|x| x.to_str().unwrap_or("text/html")) - .unwrap_or("text/html") - .to_owned() - }; + /// Clone the response, teeing any possible underlying streams. + #[quickjs(rename = "clone")] + pub fn clone_js(&self, ctx: Ctx<'_>, _rest: Rest<()>) -> Result { + Ok(Self { + url: self.url.clone(), + init: self.init.clone_js(ctx)?, + }) + } - let data = self.take_buffer(&ctx).await?; - Ok(Blob { - mime, - data, - }) - } + // ------------------------------ + // Instance properties + // ------------------------------ + #[quickjs(get)] + pub fn bodyUsed(&self) -> bool { + self.init.body.as_ref().map(Body::used).unwrap_or(true) + } - // Returns a promise with the request body as FormData - #[qjs(rename = "formData")] - pub async fn form_data(&self, ctx: Ctx<'js>) -> Result> { - Err(Exception::throw_internal(&ctx, "Not yet implemented")) - } + #[quickjs(get)] + pub fn method(&self) -> String { + self.init.method.to_string() + } - // Returns a promise with the request body as JSON - pub async fn json(&self, ctx: Ctx<'js>) -> Result> { - let text = self.text(ctx.clone()).await?; - ctx.json_parse(text) - } + #[quickjs(get)] + pub fn url(&self) -> String { + self.url.to_string() + } - // Returns a promise with the request body as text - pub async fn text(&self, ctx: Ctx<'js>) -> Result { - let data = self.take_buffer(&ctx).await?; + #[quickjs(get)] + pub fn headers<'js>(&self, ctx: Ctx<'js>) -> Class<'js, HeadersClass> { + self.init.headers.clone().restore(ctx).unwrap() + } - // Skip UTF-BOM - if data.starts_with(&[0xEF, 0xBB, 0xBF]) { - Ok(String::from_utf8_lossy(&data[3..]).into_owned()) - } else { - Ok(String::from_utf8_lossy(&data).into_owned()) + #[quickjs(get)] + pub fn referrer(&self, ctx: Ctx<'_>) -> String { + self.init.referrer.clone() + } + // TODO + + // ------------------------------ + // Instance methods + // ------------------------------ + + // Convert the object to a string + pub fn toString(&self) -> String { + String::from("[object Request]") + } + + /// Takes the buffer from the body leaving it used. + #[quickjs(skip)] + async fn take_buffer<'js>(&self, ctx: Ctx<'js>) -> Result { + let Some(body) = self.init.body.as_ref() else { + return Ok(Bytes::new()) + }; + match body.to_buffer().await { + Ok(Some(x)) => Ok(x), + Ok(None) => Err(Exception::throw_type(ctx, "Body unusable")), + Err(e) => match e { + RequestError::Reqwest(e) => { + Err(Exception::throw_type(ctx, &format!("stream failed: {e}"))) + } + }, + } + } + + // Returns a promise with the request body as a Blob + pub async fn blob(&self, ctx: Ctx<'_>, args: Rest<()>) -> Result { + let headers = self.init.headers.clone().restore(ctx).unwrap(); + let mime = { + let headers = headers.borrow(); + let headers = headers.inner.borrow(); + let key = HeaderName::from_static("content-type"); + let types = headers.get_all(key); + // TODO: This is not according to spec. + types + .iter() + .next() + .map(|x| x.to_str().unwrap_or("text/html")) + .unwrap_or("text/html") + .to_owned() + }; + + let data = self.take_buffer(ctx).await?; + Ok(BlobClass { + mime, + data, + }) + } + + // Returns a promise with the request body as FormData + pub async fn formData<'js>(&self, ctx: Ctx<'js>, args: Rest<()>) -> Result> { + Err(Exception::throw_internal(ctx, "Not yet implemented")) + } + + // Returns a promise with the request body as JSON + pub async fn json<'js>(&self, ctx: Ctx<'js>, args: Rest<()>) -> Result> { + let text = self.text(ctx, args).await?; + ctx.json_parse(text) + } + + // Returns a promise with the request body as text + pub async fn text<'js>(&self, ctx: Ctx<'js>, args: Rest<()>) -> Result { + let data = self.take_buffer(ctx).await?; + + // Skip UTF-BOM + if data.starts_with(&[0xEF, 0xBB, 0xBF]) { + Ok(String::from_utf8_lossy(&data[3..]).into_owned()) + } else { + Ok(String::from_utf8_lossy(&data).into_owned()) + } } } } @@ -615,7 +644,7 @@ mod test { assert.seq(await req_2.text(),"some text"); })() - "#).catch(&ctx).unwrap().await.catch(&ctx).unwrap(); + "#).catch(ctx).unwrap().await.catch(ctx).unwrap(); }) .await; } diff --git a/lib/src/fnc/script/fetch/classes/response/init.rs b/lib/src/fnc/script/fetch/classes/response/init.rs index 04c25394..53cbcb78 100644 --- a/lib/src/fnc/script/fetch/classes/response/init.rs +++ b/lib/src/fnc/script/fetch/classes/response/init.rs @@ -1,33 +1,34 @@ use std::string::String as StdString; use js::{ - class::{Trace, Tracer}, + class::{HasRefs, RefsMarker}, prelude::*, - Class, Ctx, Exception, FromJs, Object, Result, Value, + Class, Ctx, Exception, FromJs, Object, Persistent, Result, Value, }; -use crate::fnc::script::fetch::{classes::Headers, util}; +use crate::fnc::script::fetch::{classes::HeadersClass, util}; /// Struct containing data from the init argument from the Response constructor. #[derive(Clone)] -pub struct ResponseInit<'js> { +pub struct ResponseInit { // u16 instead of reqwest::StatusCode since javascript allows non valid status codes in some // circumstances. pub status: u16, pub status_text: StdString, - pub headers: Class<'js, Headers>, + pub headers: Persistent>, } -impl<'js> Trace<'js> for ResponseInit<'js> { - fn trace<'a>(&self, tracer: Tracer<'a, 'js>) { - self.headers.trace(tracer); +impl HasRefs for ResponseInit { + fn mark_refs(&self, marker: &RefsMarker) { + self.headers.mark_refs(marker); } } -impl<'js> ResponseInit<'js> { +impl ResponseInit { /// Returns a ResponseInit object with all values as the default value. - pub fn default(ctx: Ctx<'js>) -> Result { - let headers = Class::instance(ctx, Headers::new_empty())?; + pub fn default(ctx: Ctx<'_>) -> Result { + let headers = Class::instance(ctx, HeadersClass::new_empty())?; + let headers = Persistent::save(ctx, headers); Ok(ResponseInit { status: 200, status_text: StdString::new(), @@ -36,8 +37,8 @@ impl<'js> ResponseInit<'js> { } } -impl<'js> FromJs<'js> for ResponseInit<'js> { - fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { +impl<'js> FromJs<'js> for ResponseInit { + fn from_js(ctx: Ctx<'js>, value: Value<'js>) -> Result { let object = Object::from_js(ctx, value)?; // Extract status. @@ -65,11 +66,12 @@ impl<'js> FromJs<'js> for ResponseInit<'js> { // Extract headers. let headers = if let Some(headers) = object.get::<_, Option>("headers")? { - let headers = Headers::new_inner(ctx, headers)?; - Class::instance(ctx.clone(), headers)? + let headers = HeadersClass::new_inner(ctx, headers)?; + Class::instance(ctx, headers)? } else { - Class::instance(ctx.clone(), Headers::new_empty())? + Class::instance(ctx, HeadersClass::new_empty())? }; + let headers = Persistent::save(ctx, headers); Ok(ResponseInit { status, diff --git a/lib/src/fnc/script/fetch/classes/response/mod.rs b/lib/src/fnc/script/fetch/classes/response/mod.rs index 4791900c..87a0223b 100644 --- a/lib/src/fnc/script/fetch/classes/response/mod.rs +++ b/lib/src/fnc/script/fetch/classes/response/mod.rs @@ -1,10 +1,11 @@ //! Response class implementation +use js::bind; + mod init; -use bytes::Bytes; pub use init::ResponseInit; -use js::{class::Trace, prelude::Opt, ArrayBuffer, Class, Ctx, Exception, Result, Value}; +pub use response::Response as ResponseClass; #[allow(dead_code)] #[derive(Clone, Copy)] @@ -17,284 +18,304 @@ pub enum ResponseType { OpaqueRedirect, } -use reqwest::Url; +#[bind(object, public)] +#[quickjs(bare)] +#[allow(non_snake_case)] +#[allow(unused_variables)] +#[allow(clippy::module_inception)] +pub mod response { -use crate::fnc::script::fetch::{ - body::{Body, BodyKind}, - util, RequestError, -}; + use crate::fnc::script::fetch::{ + body::{Body, BodyKind}, + classes::{BlobClass, HeadersClass}, + util, RequestError, + }; -use super::{Blob, Headers}; + use super::{ResponseInit, ResponseType}; + use bytes::Bytes; + use js::{ + function::{Opt, Rest}, + ArrayBuffer, Class, Ctx, Exception, HasRefs, Persistent, Result, Value, + }; + use reqwest::Url; -#[allow(dead_code)] -#[derive(Trace)] -#[js::class] -pub struct Response<'js> { - #[qjs(skip_trace)] - pub(crate) body: Body, - pub(crate) init: ResponseInit<'js>, - #[qjs(skip_trace)] - pub(crate) url: Option, - #[qjs(skip_trace)] - pub(crate) r#type: ResponseType, - pub(crate) was_redirected: bool, -} - -#[js::methods] -impl<'js> Response<'js> { - // ------------------------------ - // Constructor - // ------------------------------ - - #[qjs(constructor)] - pub fn new( - ctx: Ctx<'js>, - body: Opt>, - init: Opt>, - ) -> Result { - let init = match init.into_inner() { - Some(x) => x, - None => ResponseInit::default(ctx.clone())?, - }; - let body = body.into_inner().and_then(|x| x); - if body.is_some() && util::is_null_body_status(init.status) { - // Null body statuses are not allowed to have a body. - return Err(Exception::throw_type( - &ctx, - &format!("Response with status `{}` is not allowed to have a body", init.status), - )); - } - let body = body.unwrap_or_default(); - - Ok(Response { - body, - init, - url: None, - r#type: ResponseType::Default, - was_redirected: false, - }) + #[derive(HasRefs)] + #[allow(dead_code)] + #[quickjs(has_refs)] + pub struct Response { + #[quickjs(has_refs)] + pub(crate) body: Body, + #[quickjs(has_refs)] + pub(crate) init: ResponseInit, + pub(crate) url: Option, + pub(crate) r#type: ResponseType, + pub(crate) was_redirected: bool, } - // ------------------------------ - // Instance properties - // ------------------------------ + impl Response { + // ------------------------------ + // Constructor + // ------------------------------ - #[qjs(get, rename = "bodyUsed")] - pub fn body_used(&self) -> bool { - self.body.used() - } - - #[qjs(get)] - pub fn status(&self) -> u16 { - self.init.status - } - - #[qjs(get)] - pub fn ok(&self) -> bool { - util::is_ok_status(self.init.status) - } - - #[qjs(get)] - pub fn redirected(&self) -> bool { - self.was_redirected - } - - #[qjs(get, rename = "statusText")] - pub fn status_text(&self) -> String { - self.init.status_text.clone() - } - - #[qjs(get, rename = "type")] - pub fn r#type(&self) -> &'static str { - match self.r#type { - ResponseType::Basic => "basic", - ResponseType::Cors => "cors", - ResponseType::Default => "default", - ResponseType::Error => "error", - ResponseType::Opaque => "opaque", - ResponseType::OpaqueRedirect => "opaqueredirect", - } - } - - #[qjs(get)] - pub fn headers(&self) -> Class<'js, Headers> { - self.init.headers.clone() - } - - #[qjs(get)] - pub fn url(&self) -> Option { - self.url.as_ref().map(|x| { - if x.fragment().is_some() { - let mut res = x.clone(); - res.set_fragment(None); - res.to_string() - } else { - x.to_string() + #[quickjs(constructor)] + pub fn new( + ctx: Ctx<'_>, + body: Opt>, + init: Opt, + args: Rest<()>, + ) -> Result { + let init = match init.into_inner() { + Some(x) => x, + None => ResponseInit::default(ctx)?, + }; + let body = body.into_inner().and_then(|x| x); + if body.is_some() && util::is_null_body_status(init.status) { + // Null body statuses are not allowed to have a body. + return Err(Exception::throw_type( + ctx, + &format!( + "Response with status `{}` is not allowed to have a body", + init.status + ), + )); } - }) - } + let body = body.unwrap_or_default(); - // ------------------------------ - // Instance methods - // ------------------------------ - - // Convert the object to a string - #[qjs(rename = "toString")] - pub fn js_to_string(&self) -> String { - String::from("[object Response]") - } - - // Creates a copy of the request object - #[qjs(rename = "clone")] - pub fn clone_js(&self, ctx: Ctx<'js>) -> Self { - Response { - body: self.body.clone_js(ctx), - init: self.init.clone(), - url: self.url.clone(), - r#type: self.r#type, - was_redirected: self.was_redirected, + Ok(Response { + body, + init, + url: None, + r#type: ResponseType::Default, + was_redirected: false, + }) } - } - #[qjs(skip)] - async fn take_buffer(&self, ctx: &Ctx<'js>) -> Result { - match self.body.to_buffer().await { - Ok(Some(x)) => Ok(x), - Ok(None) => Err(Exception::throw_type(ctx, "Body unusable")), - Err(e) => match e { - RequestError::Reqwest(e) => { - Err(Exception::throw_type(ctx, &format!("stream failed: {e}"))) + // ------------------------------ + // Instance properties + // ------------------------------ + + #[quickjs(get)] + pub fn bodyUsed(&self) -> bool { + self.body.used() + } + + #[quickjs(get)] + pub fn status(&self) -> u16 { + self.init.status + } + + #[quickjs(get)] + pub fn ok(&self) -> bool { + util::is_ok_status(self.init.status) + } + + #[quickjs(get)] + pub fn redirected(&self) -> bool { + self.was_redirected + } + + #[quickjs(get)] + pub fn statusText(&self) -> String { + self.init.status_text.clone() + } + + #[quickjs(get)] + pub fn r#type(&self) -> &'static str { + match self.r#type { + ResponseType::Basic => "basic", + ResponseType::Cors => "cors", + ResponseType::Default => "default", + ResponseType::Error => "error", + ResponseType::Opaque => "opaque", + ResponseType::OpaqueRedirect => "opaqueredirect", + } + } + + #[quickjs(get)] + pub fn headers<'js>(&self, ctx: Ctx<'js>) -> Class<'js, HeadersClass> { + self.init.headers.clone().restore(ctx).unwrap() + } + + #[quickjs(get)] + pub fn url(&self) -> Option { + self.url.as_ref().map(|x| { + if x.fragment().is_some() { + let mut res = x.clone(); + res.set_fragment(None); + res.to_string() + } else { + x.to_string() } - }, - } - } - - // Returns a promise with the response body as a Blob - pub async fn blob(&self, ctx: Ctx<'js>) -> Result { - let headers = self.init.headers.clone(); - let mime = { - let headers = headers.borrow(); - let headers = &headers.inner; - let types = headers.get_all(reqwest::header::CONTENT_TYPE); - // TODO: This is not according to spec. - types - .iter() - .next() - .map(|x| x.to_str().unwrap_or("text/html")) - .unwrap_or("text/html") - .to_owned() - }; - - let data = self.take_buffer(&ctx).await?; - Ok(Blob { - mime, - data, - }) - } - - // Returns a promise with the response body as FormData - #[qjs(rename = "formData")] - pub async fn form_data(&self, ctx: Ctx<'js>) -> Result> { - Err(Exception::throw_internal(&ctx, "Not yet implemented")) - } - - // Returns a promise with the response body as JSON - pub async fn json(&self, ctx: Ctx<'js>) -> Result> { - let text = self.text(ctx.clone()).await?; - ctx.json_parse(text) - } - - // Returns a promise with the response body as text - pub async fn text(&self, ctx: Ctx<'js>) -> Result { - let data = self.take_buffer(&ctx).await?; - - // Skip UTF-BOM - if data.starts_with(&[0xEF, 0xBB, 0xBF]) { - Ok(String::from_utf8_lossy(&data[3..]).into_owned()) - } else { - Ok(String::from_utf8_lossy(&data).into_owned()) - } - } - - // Returns a promise with the response body as text - #[qjs(rename = "arrayBuffer")] - pub async fn array_buffer(&self, ctx: Ctx<'js>) -> Result> { - let data = self.take_buffer(&ctx).await?; - ArrayBuffer::new(ctx, data) - } - - // ------------------------------ - // Static methods - // ------------------------------ - - #[qjs(r#static, rename = "json")] - pub fn static_json( - ctx: Ctx<'js>, - data: Value<'js>, - init: Opt>, - ) -> Result { - let json = ctx.json_stringify(data)?; - let json = - json.ok_or_else(|| Exception::throw_type(&ctx, "Value is not JSON serializable"))?; - let json = json.to_string()?; - - let init = if let Some(init) = init.into_inner() { - init - } else { - ResponseInit::default(ctx)? - }; - - Ok(Response { - url: None, - body: Body::buffer(BodyKind::Buffer, json), - init, - r#type: ResponseType::Default, - was_redirected: false, - }) - } - - // Returns a new response representing a network error - #[qjs(r#static)] - pub fn error(ctx: Ctx<'js>) -> Result { - let headers = Class::instance(ctx, Headers::new_empty())?; - Ok(Response { - url: None, - body: Body::new(), - init: ResponseInit { - status: 0, - status_text: String::new(), - headers, - }, - r#type: ResponseType::Error, - was_redirected: false, - }) - } - - // Creates a new response with a different URL - #[qjs(r#static)] - pub fn redirect(ctx: Ctx<'_>, url: String, status: Opt) -> Result { - let url = url - .parse::() - .map_err(|e| Exception::throw_type(&ctx, &format!("Invalid url: {e}")))?; - - let status = status.into_inner().unwrap_or(302) as u16; - if !util::is_redirect_status(status) { - return Err(Exception::throw_range(&ctx, "Status code is not a redirect status")); + }) } - let headers = Class::instance(ctx, Headers::new_empty())?; + // ------------------------------ + // Instance methods + // ------------------------------ - Ok(Response { - url: Some(url), - body: Body::new(), - init: ResponseInit { - status, - status_text: String::new(), - headers, - }, - r#type: ResponseType::Default, - was_redirected: false, - }) + // Convert the object to a string + pub fn toString(&self, args: Rest<()>) -> String { + String::from("[object Response]") + } + + // Creates a copy of the request object + #[quickjs(rename = "clone")] + pub fn clone_js(&self, ctx: Ctx<'_>, args: Rest<()>) -> Response { + Response { + body: self.body.clone_js(ctx), + init: self.init.clone(), + url: self.url.clone(), + r#type: self.r#type, + was_redirected: self.was_redirected, + } + } + + #[quickjs(skip)] + async fn take_buffer<'js>(&self, ctx: Ctx<'js>) -> Result { + match self.body.to_buffer().await { + Ok(Some(x)) => Ok(x), + Ok(None) => Err(Exception::throw_type(ctx, "Body unusable")), + Err(e) => match e { + RequestError::Reqwest(e) => { + Err(Exception::throw_type(ctx, &format!("stream failed: {e}"))) + } + }, + } + } + + // Returns a promise with the response body as a Blob + pub async fn blob<'js>(&self, ctx: Ctx<'js>, args: Rest<()>) -> Result { + let headers = self.init.headers.clone().restore(ctx).unwrap(); + let mime = { + let headers = headers.borrow(); + let headers = headers.inner.borrow(); + let types = headers.get_all(reqwest::header::CONTENT_TYPE); + // TODO: This is not according to spec. + types + .iter() + .next() + .map(|x| x.to_str().unwrap_or("text/html")) + .unwrap_or("text/html") + .to_owned() + }; + + let data = self.take_buffer(ctx).await?; + Ok(BlobClass { + mime, + data, + }) + } + + // Returns a promise with the response body as FormData + pub async fn formData<'js>(&self, ctx: Ctx<'js>, args: Rest<()>) -> Result> { + Err(Exception::throw_internal(ctx, "Not yet implemented")) + } + + // Returns a promise with the response body as JSON + pub async fn json<'js>(&self, ctx: Ctx<'js>, args: Rest<()>) -> Result> { + let text = self.text(ctx, args).await?; + ctx.json_parse(text) + } + + // Returns a promise with the response body as text + pub async fn text<'js>(&self, ctx: Ctx<'js>, args: Rest<()>) -> Result { + let data = self.take_buffer(ctx).await?; + + // Skip UTF-BOM + if data.starts_with(&[0xEF, 0xBB, 0xBF]) { + Ok(String::from_utf8_lossy(&data[3..]).into_owned()) + } else { + Ok(String::from_utf8_lossy(&data).into_owned()) + } + } + + // Returns a promise with the response body as text + pub async fn arrayBuffer<'js>( + &self, + ctx: Ctx<'js>, + args: Rest<()>, + ) -> Result> { + let data = self.take_buffer(ctx).await?; + ArrayBuffer::new(ctx, data) + } + + // ------------------------------ + // Static methods + // ------------------------------ + + #[quickjs(rename = "json")] + pub fn static_json<'js>( + ctx: Ctx<'js>, + data: Value<'js>, + init: Opt, + args: Rest<()>, + ) -> Result { + let json = ctx.json_stringify(data)?; + let json = + json.ok_or_else(|| Exception::throw_type(ctx, "Value is not JSON serializable"))?; + let json = json.to_string()?; + + let init = if let Some(init) = init.into_inner() { + init + } else { + ResponseInit::default(ctx)? + }; + + Ok(Response { + url: None, + body: Body::buffer(BodyKind::Buffer, json), + init, + r#type: ResponseType::Default, + was_redirected: false, + }) + } + + // Returns a new response representing a network error + pub fn error(ctx: Ctx<'_>, args: Rest<()>) -> Result { + let headers = Persistent::save(ctx, Class::instance(ctx, HeadersClass::new_empty())?); + Ok(Response { + url: None, + body: Body::new(), + init: ResponseInit { + status: 0, + status_text: String::new(), + headers, + }, + r#type: ResponseType::Error, + was_redirected: false, + }) + } + + // Creates a new response with a different URL + pub fn redirect( + ctx: Ctx<'_>, + url: String, + status: Opt, + args: Rest<()>, + ) -> Result { + let url = url + .parse::() + .map_err(|e| Exception::throw_type(ctx, &format!("Invalid url: {e}")))?; + + let status = status.into_inner().unwrap_or(302) as u16; + if !util::is_redirect_status(status) { + return Err(Exception::throw_range(ctx, "Status code is not a redirect status")); + } + + let headers = Persistent::save(ctx, Class::instance(ctx, HeadersClass::new_empty())?); + + Ok(Response { + url: Some(url), + body: Body::new(), + init: ResponseInit { + status, + status_text: String::new(), + headers, + }, + r#type: ResponseType::Default, + was_redirected: false, + }) + } } } @@ -367,7 +388,7 @@ mod test { })() - "#).catch(&ctx).unwrap().await.catch(&ctx).unwrap(); + "#).catch(ctx).unwrap().await.catch(ctx).unwrap(); }) .await; } diff --git a/lib/src/fnc/script/fetch/func.rs b/lib/src/fnc/script/fetch/func.rs index 40dc9fac..cc2f6241 100644 --- a/lib/src/fnc/script/fetch/func.rs +++ b/lib/src/fnc/script/fetch/func.rs @@ -2,28 +2,29 @@ use crate::fnc::script::fetch::{ body::{Body, BodyData, BodyKind}, - classes::{self, Request, RequestInit, Response, ResponseInit, ResponseType}, + classes::{ + self, HeadersClass, RequestClass, RequestInit, ResponseClass, ResponseInit, ResponseType, + }, RequestError, }; use futures::TryStreamExt; -use js::{function::Opt, Class, Ctx, Exception, Result, Value}; +use js::{bind, function::Opt, prelude::*, Class, Ctx, Exception, Persistent, Result, Value}; use reqwest::{ header::{HeaderValue, CONTENT_TYPE}, redirect, Body as ReqBody, }; use std::sync::Arc; -use super::classes::Headers; - -#[js::function] +#[bind(object, public)] #[allow(unused_variables)] pub async fn fetch<'js>( ctx: Ctx<'js>, input: Value<'js>, - init: Opt>, -) -> Result> { + init: Opt, + args: Rest<()>, +) -> Result { // Create a request from the input. - let js_req = Request::new(ctx.clone(), input, init)?; + let js_req = RequestClass::new(ctx, input, init, args)?; let url = js_req.url; @@ -31,9 +32,9 @@ pub async fn fetch<'js>( // SurrealDB Implementation keeps all javascript parts inside the context::with scope so this // unwrap should never panic. - let headers = js_req.init.headers; + let headers = js_req.init.headers.restore(ctx).unwrap(); let headers = headers.borrow(); - let mut headers = headers.inner.clone(); + let mut headers = headers.inner.borrow().clone(); let redirect = js_req.init.request_redirect; @@ -54,7 +55,7 @@ pub async fn fetch<'js>( }); let client = reqwest::Client::builder().redirect(policy).build().map_err(|e| { - Exception::throw_internal(&ctx, &format!("Could not initialize http client: {e}")) + Exception::throw_internal(ctx, &format!("Could not initialize http client: {e}")) })?; // Set the body for the request. @@ -69,7 +70,7 @@ pub async fn fetch<'js>( let body = ReqBody::from(x); req_builder = req_builder.body(body); } - BodyData::Used => return Err(Exception::throw_type(&ctx, "Body unusable")), + BodyData::Used => return Err(Exception::throw_type(ctx, "Body unusable")), }; match body.kind { BodyKind::Buffer => {} @@ -93,11 +94,12 @@ pub async fn fetch<'js>( .headers(headers) .send() .await - .map_err(|e| Exception::throw_type(&ctx, &e.to_string()))?; + .map_err(|e| Exception::throw_type(ctx, &e.to_string()))?; // Extract the headers - let headers = Headers::from_map(response.headers().clone()); + let headers = HeadersClass::from_map(response.headers().clone()); let headers = Class::instance(ctx, headers)?; + let headers = Persistent::save(ctx, headers); let init = ResponseInit { headers, status: response.status().as_u16(), @@ -109,7 +111,7 @@ pub async fn fetch<'js>( BodyKind::Buffer, response.bytes_stream().map_err(Arc::new).map_err(RequestError::Reqwest), ); - let response = Response { + let response = ResponseClass { body, init, url: Some(url), diff --git a/lib/src/fnc/script/fetch/mod.rs b/lib/src/fnc/script/fetch/mod.rs index 40f831e9..5636df74 100644 --- a/lib/src/fnc/script/fetch/mod.rs +++ b/lib/src/fnc/script/fetch/mod.rs @@ -1,6 +1,6 @@ use std::{error::Error, fmt, sync::Arc}; -use js::{Class, Ctx, Result}; +use js::{Ctx, Result}; mod body; mod classes; @@ -9,7 +9,7 @@ mod stream; mod util; use classes::{Blob, FormData, Headers, Request, Response}; -use func::js_fetch; +use func::Fetch; // Anoyingly errors aren't clone, // But with how we implement streams RequestError must be clone. @@ -30,14 +30,15 @@ impl fmt::Display for RequestError { impl Error for RequestError {} /// Register the fetch types in the context. -pub fn register(ctx: &Ctx<'_>) -> Result<()> { +pub fn register(ctx: Ctx<'_>) -> Result<()> { let globals = ctx.globals(); - globals.set("fetch", js_fetch)?; - Class::::define(&globals)?; - Class::::define(&globals)?; - Class::::define(&globals)?; - Class::::define(&globals)?; - Class::::define(&globals)?; + globals.init_def::()?; + + globals.init_def::()?; + globals.init_def::()?; + globals.init_def::()?; + globals.init_def::()?; + globals.init_def::()?; Ok(()) } @@ -54,9 +55,9 @@ mod test { let ctx = js::AsyncContext::full(&rt).await.unwrap(); js::async_with!(ctx => |$ctx|{ - crate::fnc::script::fetch::register(&$ctx).unwrap(); + crate::fnc::script::fetch::register($ctx).unwrap(); - $ctx.eval::<(),_>(r" + $ctx.eval::<(),_>(r#" globalThis.assert = (...arg) => { arg.forEach(x => { if (!x) { @@ -90,7 +91,7 @@ mod test { } throw new Error(`Code which should throw, didnt: \n${cb}`) } - ").unwrap(); + "#).unwrap(); $($t)* }).await; diff --git a/lib/src/fnc/script/fetch_stub/mod.rs b/lib/src/fnc/script/fetch_stub/mod.rs index 60fd45e1..9f050826 100644 --- a/lib/src/fnc/script/fetch_stub/mod.rs +++ b/lib/src/fnc/script/fetch_stub/mod.rs @@ -1,5 +1,4 @@ -//! stub implementations for the fetch API when `http` is not enabled. - +/// The stub implementations for the fetch API when `http` is not enabled. use js::{bind, prelude::*, Ctx, Exception, Result}; #[cfg(test)] diff --git a/lib/src/fnc/script/from.rs b/lib/src/fnc/script/from.rs index 10fc6a00..55a5363c 100644 --- a/lib/src/fnc/script/from.rs +++ b/lib/src/fnc/script/from.rs @@ -5,7 +5,6 @@ use crate::sql::object::Object; use crate::sql::value::Value; use crate::sql::Id; use chrono::{TimeZone, Utc}; -use js::prelude::This; use js::Ctx; use js::Error; use js::Exception; @@ -21,7 +20,7 @@ fn check_nul(s: &str) -> Result<(), Error> { } impl<'js> FromJs<'js> for Value { - fn from_js(ctx: &Ctx<'js>, val: js::Value<'js>) -> Result { + fn from_js(ctx: Ctx<'js>, val: js::Value<'js>) -> Result { match val { val if val.type_name() == "null" => Ok(Value::Null), val if val.type_name() == "undefined" => Ok(Value::None), @@ -50,15 +49,14 @@ impl<'js> FromJs<'js> for Value { // Check to see if this object is an error if v.is_error() { let e: String = v.get("message")?; - let (Ok(e) | Err(e)) = - Exception::from_message(ctx.clone(), &e).map(|x| x.throw()); + let (Ok(e) | Err(e)) = Exception::from_message(ctx, &e).map(|x| x.throw()); return Err(e); } // Check to see if this object is a record - if (v).instance_of::() { - let v = v.into_class::().unwrap(); + if (v).instance_of::() { + let v = v.into_instance::().unwrap(); let borrow = v.borrow(); - let v: &classes::record::Record = &borrow; + let v: &classes::record::record::Record = &borrow; check_nul(&v.value.tb)?; if let Id::String(s) = &v.value.id { check_nul(s)?; @@ -66,20 +64,20 @@ impl<'js> FromJs<'js> for Value { return Ok(v.value.clone().into()); } // Check to see if this object is a duration - if (v).instance_of::() { - let v = v.into_class::().unwrap(); + if (v).instance_of::() { + let v = v.into_instance::().unwrap(); let borrow = v.borrow(); - let v: &classes::duration::Duration = &borrow; + let v: &classes::duration::duration::Duration = &borrow; return match &v.value { Some(v) => Ok(v.clone().into()), None => Ok(Value::None), }; } // Check to see if this object is a uuid - if (v).instance_of::() { - let v = v.into_class::().unwrap(); + if (v).instance_of::() { + let v = v.into_instance::().unwrap(); let borrow = v.borrow(); - let v: &classes::uuid::Uuid = &borrow; + let v: &classes::uuid::uuid::Uuid = &borrow; return match &v.value { Some(v) => Ok(v.clone().into()), None => Ok(Value::None), @@ -89,7 +87,7 @@ impl<'js> FromJs<'js> for Value { let date: js::Object = ctx.globals().get("Date")?; if (v).is_instance_of(&date) { let f: js::Function = v.get("getTime")?; - let m: i64 = f.call((This(v),))?; + let m: i64 = f.call((js::prelude::This(v),))?; let d = Utc.timestamp_millis_opt(m).unwrap(); return Ok(Datetime::from(d).into()); } diff --git a/lib/src/fnc/script/globals/console.rs b/lib/src/fnc/script/globals/console.rs index b681ea78..7ec7fda5 100644 --- a/lib/src/fnc/script/globals/console.rs +++ b/lib/src/fnc/script/globals/console.rs @@ -1,44 +1,32 @@ -// Specify the imports -use crate::sql::value::Value; -use js::{prelude::Rest, Ctx, Object, Result}; -/// Log the input values as INFO -#[js::function] -pub fn log(args: Rest) { - info!("{}", args.iter().map(|v| v.to_raw_string()).collect::>().join(" ")); -} -/// Log the input values as INFO -#[js::function] -pub fn info(args: Rest) { - info!("{}", args.iter().map(|v| v.to_raw_string()).collect::>().join(" ")); -} -/// Log the input values as WARN -#[js::function] -pub fn warn(args: Rest) { - warn!("{}", args.iter().map(|v| v.to_raw_string()).collect::>().join(" ")); -} -/// Log the input values as ERROR -#[js::function] -pub fn error(args: Rest) { - error!("{}", args.iter().map(|v| v.to_raw_string()).collect::>().join(" ")); -} -/// Log the input values as DEBUG -#[js::function] -pub fn debug(args: Rest) { - debug!("{}", args.iter().map(|v| v.to_raw_string()).collect::>().join(" ")); -} -/// Log the input values as TRACE -#[js::function] -pub fn trace(args: Rest) { - trace!("{}", args.iter().map(|v| v.to_raw_string()).collect::>().join(" ")); -} - -pub fn console<'js>(ctx: &Ctx<'js>) -> Result> { - let console = Object::new(ctx.clone())?; - console.set("log", js_log)?; - console.set("info", js_info)?; - console.set("warn", js_warn)?; - console.set("error", js_error)?; - console.set("debug", js_debug)?; - console.set("trace", js_trace)?; - Ok(console) +#[js::bind(object, public)] +#[quickjs(rename = "console")] +#[allow(clippy::module_inception)] +pub mod console { + // Specify the imports + use crate::sql::value::Value; + use js::prelude::Rest; + /// Log the input values as INFO + pub fn log(args: Rest) { + info!("{}", args.iter().map(|v| v.to_raw_string()).collect::>().join(" ")); + } + /// Log the input values as INFO + pub fn info(args: Rest) { + info!("{}", args.iter().map(|v| v.to_raw_string()).collect::>().join(" ")); + } + /// Log the input values as WARN + pub fn warn(args: Rest) { + warn!("{}", args.iter().map(|v| v.to_raw_string()).collect::>().join(" ")); + } + /// Log the input values as ERROR + pub fn error(args: Rest) { + error!("{}", args.iter().map(|v| v.to_raw_string()).collect::>().join(" ")); + } + /// Log the input values as DEBUG + pub fn debug(args: Rest) { + debug!("{}", args.iter().map(|v| v.to_raw_string()).collect::>().join(" ")); + } + /// Log the input values as TRACE + pub fn trace(args: Rest) { + trace!("{}", args.iter().map(|v| v.to_raw_string()).collect::>().join(" ")); + } } diff --git a/lib/src/fnc/script/into.rs b/lib/src/fnc/script/into.rs index 495df24f..1b999c0b 100644 --- a/lib/src/fnc/script/into.rs +++ b/lib/src/fnc/script/into.rs @@ -12,58 +12,58 @@ use js::Object; use js::Undefined; impl<'js> IntoJs<'js> for Value { - fn into_js(self, ctx: &Ctx<'js>) -> Result, Error> { + fn into_js(self, ctx: Ctx<'js>) -> Result, Error> { (&self).into_js(ctx) } } impl<'js> IntoJs<'js> for &Value { - fn into_js(self, ctx: &Ctx<'js>) -> Result, Error> { + fn into_js(self, ctx: Ctx<'js>) -> Result, Error> { match self { Value::Null => Null.into_js(ctx), Value::None => Undefined.into_js(ctx), - Value::Bool(boolean) => Ok(js::Value::new_bool(ctx.clone(), *boolean)), - Value::Strand(v) => js::String::from_str(ctx.clone(), v)?.into_js(ctx), - Value::Number(Number::Int(v)) => Ok(js::Value::new_int(ctx.clone(), *v as i32)), - Value::Number(Number::Float(v)) => Ok(js::Value::new_float(ctx.clone(), *v)), + Value::Bool(boolean) => Ok(js::Value::new_bool(ctx, *boolean)), + Value::Strand(v) => js::String::from_str(ctx, v)?.into_js(ctx), + Value::Number(Number::Int(v)) => Ok(js::Value::new_int(ctx, *v as i32)), + Value::Number(Number::Float(v)) => Ok(js::Value::new_float(ctx, *v)), &Value::Number(Number::Decimal(v)) => match decimal_is_integer(&v) { - true => Ok(js::Value::new_int(ctx.clone(), v.try_into().unwrap_or_default())), - false => Ok(js::Value::new_float(ctx.clone(), v.try_into().unwrap_or_default())), + true => Ok(js::Value::new_int(ctx, v.try_into().unwrap_or_default())), + false => Ok(js::Value::new_float(ctx, v.try_into().unwrap_or_default())), }, Value::Datetime(v) => { - let date: js::function::Constructor = ctx.globals().get("Date")?; + let date: js::Function = ctx.globals().get("Date")?; date.construct((v.0.timestamp_millis(),)) } - Value::Thing(v) => Ok(Class::::instance( - ctx.clone(), - classes::record::Record { + Value::Thing(v) => Ok(Class::::instance( + ctx, + classes::record::record::Record { value: v.to_owned(), }, )? .into_value()), - Value::Duration(v) => Ok(Class::::instance( - ctx.clone(), - classes::duration::Duration { + Value::Duration(v) => Ok(Class::::instance( + ctx, + classes::duration::duration::Duration { value: Some(v.to_owned()), }, )? .into_value()), - Value::Uuid(v) => Ok(Class::::instance( - ctx.clone(), - classes::uuid::Uuid { + Value::Uuid(v) => Ok(Class::::instance( + ctx, + classes::uuid::uuid::Uuid { value: Some(v.to_owned()), }, )? .into_value()), Value::Array(v) => { - let x = Array::new(ctx.clone())?; + let x = Array::new(ctx)?; for (i, v) in v.iter().enumerate() { x.set(i, v)?; } x.into_js(ctx) } Value::Object(v) => { - let x = Object::new(ctx.clone())?; + let x = Object::new(ctx)?; for (k, v) in v.iter() { x.set(k, v)?; } diff --git a/lib/src/fnc/script/main.rs b/lib/src/fnc/script/main.rs index 08ec697f..6f837d94 100644 --- a/lib/src/fnc/script/main.rs +++ b/lib/src/fnc/script/main.rs @@ -50,24 +50,23 @@ pub async fn run( // Attempt to execute the script async_with!(ctx => |ctx|{ - let res = async{ + let res = async move { // register all classes to the runtime. // Get the context global object let global = ctx.globals(); // Register the surrealdb module as a global object global.set( "surrealdb", - Module::evaluate_def::(ctx.clone(), "surrealdb")? + Module::evaluate_def::(ctx, "surrealdb")? .get::<_, js::Value>("default")?, )?; - fetch::register(&ctx)?; - let console = globals::console::console(&ctx)?; + fetch::register(ctx)?; // Register the console function to the globals - global.set("console",console)?; + global.init_def::()?; // Register the special SurrealDB types as classes - classes::init(&ctx)?; + classes::init(ctx)?; // Attempt to compile the script - let res = ctx.clone().compile("script", src)?; + let res = ctx.compile("script", src)?; // Attempt to fetch the main export let fnc = res.get::<_, Function>("default")?; // Extract the doc if any @@ -77,7 +76,7 @@ pub async fn run( promise.await }.await; - res.catch(&ctx).map_err(Error::from) + res.catch(ctx).map_err(Error::from) }) .await } diff --git a/lib/src/fnc/script/modules/mod.rs b/lib/src/fnc/script/modules/mod.rs index 879241f7..4e37c88a 100644 --- a/lib/src/fnc/script/modules/mod.rs +++ b/lib/src/fnc/script/modules/mod.rs @@ -54,8 +54,8 @@ macro_rules! impl_module_def { Ok(()) } - fn evaluate<'js>(ctx: &js::Ctx<'js>, exports: &mut js::module::Exports<'js>) -> js::Result<()> { - let default = js::Object::new(ctx.clone())?; + fn evaluate<'js>(ctx: js::Ctx<'js>, exports: &mut js::module::Exports<'js>) -> js::Result<()> { + let default = js::Object::new(ctx)?; $( exports.export($name, crate::fnc::script::modules::impl_module_def!(ctx, $path, $name, $action, $($wrapper)?))?; default.set($name, crate::fnc::script::modules::impl_module_def!(ctx, $path, $name, $action, $($wrapper)?))?; diff --git a/lib/src/fnc/script/modules/os.rs b/lib/src/fnc/script/modules/os.rs index 1e6b4b9b..49162f66 100644 --- a/lib/src/fnc/script/modules/os.rs +++ b/lib/src/fnc/script/modules/os.rs @@ -1,31 +1,13 @@ -use js::{ - module::{Declarations, Exports, ModuleDef}, - Result, -}; - -/// Get the target system architecture -#[js::function] -pub fn arch() -> &'static str { - crate::env::arch() -} -/// Get the target operating system -#[js::function] -pub fn platform() -> &'static str { - crate::env::os() -} - -pub struct Package; - -impl ModuleDef for Package { - fn declare(declare: &mut Declarations) -> Result<()> { - declare.declare("arch")?; - declare.declare("platform")?; - Ok(()) +#[js::bind(module, public)] +#[quickjs(bare)] +#[allow(non_upper_case_globals)] +pub mod package { + /// Get the target system architecture + pub fn arch() -> &'static str { + crate::env::arch() } - - fn evaluate<'js>(_ctx: &js::Ctx<'js>, exports: &mut Exports<'js>) -> Result<()> { - exports.export("arch", js_arch)?; - exports.export("platform", js_platform)?; - Ok(()) + /// Get the target operating system + pub fn platform() -> &'static str { + crate::env::os() } } diff --git a/lib/src/fnc/script/modules/surrealdb/mod.rs b/lib/src/fnc/script/modules/surrealdb/mod.rs index 26fb2796..7e38b6b2 100644 --- a/lib/src/fnc/script/modules/surrealdb/mod.rs +++ b/lib/src/fnc/script/modules/surrealdb/mod.rs @@ -12,9 +12,9 @@ impl_module_def!( "version" => (env!("CARGO_PKG_VERSION")) ); -fn pkg<'js, D>(ctx: &Ctx<'js>, name: &str) -> Result> +fn pkg<'js, D>(ctx: Ctx<'js>, name: &str) -> Result> where D: ModuleDef, { - Module::evaluate_def::(ctx.clone(), name)?.get::<_, js::Value>("default") + Module::evaluate_def::(ctx, name)?.get::<_, js::Value>("default") } diff --git a/lib/src/sql/value/value.rs b/lib/src/sql/value/value.rs index bc84f588..7da8b193 100644 --- a/lib/src/sql/value/value.rs +++ b/lib/src/sql/value/value.rs @@ -2938,7 +2938,7 @@ mod tests { assert_eq!(24, std::mem::size_of::()); assert_eq!(56, std::mem::size_of::()); assert_eq!(40, std::mem::size_of::()); - assert_eq!(32, std::mem::size_of::()); + assert_eq!(16, std::mem::size_of::()); assert_eq!(8, std::mem::size_of::>()); assert_eq!(8, std::mem::size_of::>()); assert_eq!(8, std::mem::size_of::>());