From 4f4339848e1b16b8a37b2184a6a976b51670fe13 Mon Sep 17 00:00:00 2001 From: Mees Delzenne Date: Fri, 14 Jul 2023 15:35:32 +0200 Subject: [PATCH] Update js functions to new rquickjs version (#2252) --- 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 | 94 ++- lib/src/fnc/script/classes/uuid.rs | 81 ++- lib/src/fnc/script/fetch/body.rs | 10 +- lib/src/fnc/script/fetch/classes/blob.rs | 251 ++++---- 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, 1362 insertions(+), 1498 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b73363c..460ead9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,7 +177,7 @@ dependencies = [ "serde_urlencoded", "smallvec", "socket2", - "time 0.3.22", + "time 0.3.23", "url", ] @@ -240,15 +240,6 @@ 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" @@ -330,7 +321,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -340,7 +331,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -404,9 +395,9 @@ dependencies = [ [[package]] name = "async-channel" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", "event-listener", @@ -458,7 +449,7 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -480,7 +471,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -491,13 +482,13 @@ checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" [[package]] name = "async-trait" -version = "0.1.69" +version = "0.1.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2d0f03b3640e3a630367e40c468cb7f309529c708ed1d88597047b0e7c6ef7" +checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -710,13 +701,13 @@ dependencies = [ "lazycell", "log", "peeking_take_while", - "prettyplease 0.2.9", + "prettyplease 0.2.10", "proc-macro2", "quote", "regex", "rustc-hash", "shlex 1.1.0", - "syn 2.0.23", + "syn 2.0.25", "which", ] @@ -1057,9 +1048,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.10" +version = "4.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384e169cc618c613d5e3ca6404dda77a8685a63e08660dcc64abaf7da7cb0c7a" +checksum = "1640e5cc7fb47dbb8338fd471b105e7ed6c3cb2aeb00c2e067127ffd3764a05d" dependencies = [ "clap_builder", "clap_derive", @@ -1068,9 +1059,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.10" +version = "4.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef137bbe35aab78bdb468ccfba75a5f4d8321ae011d34063770780545176af2d" +checksum = "98c59138d527eeaf9b53f35a77fcc1fad9d883116070c63d5de1c7dc7b00c72b" dependencies = [ "anstream", "anstyle", @@ -1090,7 +1081,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -1166,7 +1157,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" dependencies = [ "percent-encoding", - "time 0.3.22", + "time 0.3.23", "version_check", ] @@ -1197,9 +1188,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -1311,9 +1302,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.14.4" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ "darling_core", "darling_macro", @@ -1321,37 +1312,37 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.14.4" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 1.0.109", + "syn 2.0.25", ] [[package]] name = "darling_macro" -version = "0.14.4" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 1.0.109", + "syn 2.0.25", ] [[package]] name = "dashmap" -version = "5.4.0" +version = "5.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +checksum = "6943ae99c34386c84a470c499d3414f66502a41340aa895406e0d2e4a207b91d" dependencies = [ "cfg-if", - "hashbrown 0.12.3", + "hashbrown 0.14.0", "lock_api", "once_cell", "parking_lot_core 0.9.8", @@ -1507,9 +1498,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" @@ -1519,7 +1510,7 @@ checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1575,8 +1566,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ "cfg-if", - "rustix 0.38.2", - "windows-sys 0.48.0", + "rustix 0.38.4", + "windows-sys", ] [[package]] @@ -1699,7 +1690,7 @@ checksum = "83c8d52fe8b46ab822b4decdcc0d6d85aeedfc98f0d52ba2bd4aec4a97807516" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", "try_map", ] @@ -1813,7 +1804,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -1948,11 +1939,11 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" +checksum = "1391ab1f92ffcc08911957149833e682aa3fe252b9f45f966d2ef972274c97df" dependencies = [ - "aho-corasick 0.7.20", + "aho-corasick", "bstr", "fnv", "log", @@ -2137,9 +2128,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" @@ -2222,13 +2213,14 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7" +checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ + "futures-util", "http", "hyper", - "rustls 0.21.2", + "rustls 0.21.5", "tokio", "tokio-rustls 0.24.1", ] @@ -2412,9 +2404,9 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi 0.3.2", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -2425,13 +2417,13 @@ checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "is-terminal" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.3.1", - "rustix 0.38.2", - "windows-sys 0.48.0", + "hermit-abi 0.3.2", + "rustix 0.38.4", + "windows-sys", ] [[package]] @@ -2454,9 +2446,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0aa48fab2893d8a49caa94082ae8488f4e1050d73b367881dcd2198f4199fd8" +checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" [[package]] name = "jobserver" @@ -2654,7 +2646,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", ] [[package]] @@ -2745,7 +2737,7 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -2908,7 +2900,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi 0.3.2", "libc", ] @@ -2956,7 +2948,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -3146,15 +3138,15 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" [[package]] name = "pbkdf2" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0ca0b5a68607598bf3bad68f32227a8164f6254833f84eafaac409cd6746c31" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ "digest", "hmac", @@ -3230,7 +3222,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -3347,12 +3339,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9825a04601d60621feed79c4e6b56d65db77cdca55cef43b46b0de1096d1c282" +checksum = "92139198957b410250d43fad93e630d956499a625c527eda65175c8680f83387" dependencies = [ "proc-macro2", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -3400,9 +3392,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" dependencies = [ "unicode-ident", ] @@ -3735,7 +3727,7 @@ checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", "ring", - "time 0.3.22", + "time 0.3.23", "yasna", ] @@ -3770,13 +3762,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.4" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ - "aho-corasick 1.0.2", + "aho-corasick", "memchr", - "regex-syntax 0.7.2", + "regex-automata 0.3.3", + "regex-syntax 0.7.4", ] [[package]] @@ -3788,6 +3781,17 @@ 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" @@ -3796,9 +3800,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "relative-path" @@ -3841,7 +3845,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.21.2", + "rustls 0.21.5", "rustls-pemfile", "serde", "serde_json", @@ -3985,9 +3989,9 @@ dependencies = [ [[package]] name = "rquickjs" -version = "0.3.1" +version = "0.4.0-beta.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db7788c2818f4546daabe9ae2d1ee2f4db61ab1998d4b483494c4193cc38dab" +checksum = "cbfcaaf4557ff16c6e6b53387a3c81c2f0298ceaa7082357fa14170dadb060cd" dependencies = [ "rquickjs-core", "rquickjs-macro", @@ -3995,9 +3999,9 @@ dependencies = [ [[package]] name = "rquickjs-core" -version = "0.3.1" +version = "0.4.0-beta.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b12cf8646fe0af5bcff2822ccd162990f0679a1f9287c7257f4f4193a9d31ea9" +checksum = "75454c59ff94406807a41bf04cee8369307c7c0d15269eb721ae2774f3c96c60" dependencies = [ "async-lock", "relative-path", @@ -4006,9 +4010,9 @@ dependencies = [ [[package]] name = "rquickjs-macro" -version = "0.3.1" +version = "0.4.0-beta.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80564583a91b0ae6b2d6b9b3d0f8ffd69a4b17202cc63a12df78dfa8983885fc" +checksum = "7cea01191a7b5d087fb180a6c0de76d5c5a322289b662b990093a03368310096" dependencies = [ "darling", "fnv", @@ -4019,14 +4023,14 @@ dependencies = [ "proc-macro2", "quote", "rquickjs-core", - "syn 1.0.109", + "syn 2.0.25", ] [[package]] name = "rquickjs-sys" -version = "0.3.1" +version = "0.4.0-beta.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b747058afd4d988d056e4972ec8516a5a86fdfc103c1c1485bfee8966a0743ae" +checksum = "5b0c47d60e7e2816b4e893874296f28868e8383999d067cbadd0b7948ed629b5" dependencies = [ "bindgen 0.65.1", "cc", @@ -4094,29 +4098,29 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.22" +version = "0.37.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8818fa822adcc98b18fedbb3632a6a33213c070556b5aa7c4c8cc21cff565c4c" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ "bitflags 1.3.2", "errno", "io-lifetimes", "libc", "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] name = "rustix" -version = "0.38.2" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aabcb0461ebd01d6b79945797c27f8529082226cb630a9865a71870ff63532a4" +checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" dependencies = [ "bitflags 2.3.3", "errno", "libc", "linux-raw-sys 0.4.3", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -4133,9 +4137,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f" +checksum = "79ea77c539259495ce8ca47f53e66ae0330a8819f67e23ac96ca02f50e7b7d36" dependencies = [ "log", "ring", @@ -4154,9 +4158,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.100.1" +version = "0.101.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" +checksum = "15f36a6828982f422756984e47912a7a51dcbc2a197aa791158f8ca61cd8204e" dependencies = [ "ring", "untrusted", @@ -4164,9 +4168,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "dc31bd9b61a32c31f9650d18add92aa83a49ba979c143eefd27fe7177b05bd5f" [[package]] name = "rustyline" @@ -4205,9 +4209,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" [[package]] name = "salsa20" @@ -4229,11 +4233,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys 0.42.0", + "windows-sys", ] [[package]] @@ -4316,18 +4320,18 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.9" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" +checksum = "5a16be4fe5320ade08736447e3198294a5ea9a6d44dde6f35f0a5e06859c427a" dependencies = [ "serde", ] @@ -4344,20 +4348,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] name = "serde_json" -version = "1.0.99" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" +checksum = "b5062a995d481b2308b6064e9af76011f2921c35f97b0468811ed9f6cd91dfed" dependencies = [ "itoa", "ryu", @@ -4366,9 +4370,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b1b6471d7496b051e03f1958802a73f88b947866f5146f329e47e36554f4e55" +checksum = "8acc4422959dd87a76cb117c191dcbffc20467f06c9100b76721dab370f24d3a" dependencies = [ "itoa", "serde", @@ -4408,7 +4412,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -4489,7 +4493,7 @@ dependencies = [ "num-bigint", "num-traits", "thiserror", - "time 0.3.22", + "time 0.3.23", ] [[package]] @@ -4503,9 +4507,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "snap" @@ -4604,7 +4608,7 @@ dependencies = [ "assert_fs", "base64 0.21.2", "bytes", - "clap 4.3.10", + "clap 4.3.11", "futures 0.3.28", "glob", "http", @@ -4708,7 +4712,7 @@ dependencies = [ "temp-dir", "test-log", "thiserror", - "time 0.3.22", + "time 0.3.23", "tokio", "tokio-tungstenite", "tokio-util", @@ -4855,9 +4859,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.23" +version = "2.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" +checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" dependencies = [ "proc-macro2", "quote", @@ -4901,8 +4905,8 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.37.22", - "windows-sys 0.48.0", + "rustix 0.37.23", + "windows-sys", ] [[package]] @@ -4920,8 +4924,8 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" dependencies = [ - "rustix 0.37.22", - "windows-sys 0.48.0", + "rustix 0.37.23", + "windows-sys", ] [[package]] @@ -4949,22 +4953,22 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -4990,9 +4994,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" dependencies = [ "itoa", "serde", @@ -5008,9 +5012,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" dependencies = [ "time-core", ] @@ -5057,7 +5061,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -5078,7 +5082,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -5108,7 +5112,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.2", + "rustls 0.21.5", "tokio", ] @@ -5173,9 +5177,9 @@ checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" -version = "0.19.11" +version = "0.19.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" +checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78" dependencies = [ "indexmap 2.0.0", "toml_datetime", @@ -5280,7 +5284,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -5424,9 +5428,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" [[package]] name = "unicode-normalization" @@ -5613,7 +5617,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", "wasm-bindgen-shared", ] @@ -5647,7 +5651,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5764,21 +5768,6 @@ 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" @@ -5794,93 +5783,51 @@ version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ - "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", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[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" @@ -5889,9 +5836,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +checksum = "81a2094c43cc94775293eaa0e499fbc30048a6d824ac82c0351a8c0bf9112529" dependencies = [ "memchr", ] @@ -5945,7 +5892,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" dependencies = [ - "time 0.3.22", + "time 0.3.23", ] [[package]] diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 06fbc406..387ba8e4 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.3.1" , package = "rquickjs", features = ["array-buffer", "bindgen", "classes", "futures", "loader", "macro", "parallel", "properties","rust-alloc"], 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 } jsonwebtoken = "8.3.0" lexicmp = "0.1.0" lru = "0.10.1" @@ -155,4 +155,4 @@ harness = false [[bench]] name = "index_btree" -harness = false \ No newline at end of file +harness = false diff --git a/lib/src/fnc/script/classes/duration.rs b/lib/src/fnc/script/classes/duration.rs index 7631deb3..7b36849b 100644 --- a/lib/src/fnc/script/classes/duration.rs +++ b/lib/src/fnc/script/classes/duration.rs @@ -1,51 +1,48 @@ -#[js::bind(object, public)] -#[quickjs(bare)] -#[allow(non_snake_case)] -#[allow(unused_variables)] -#[allow(clippy::module_inception)] -pub mod duration { +use js::class::Trace; - use crate::sql::duration; - use crate::sql::value::Value; - use js::{class::Ref, function::Rest}; +use crate::sql::duration; - #[derive(Clone)] - #[quickjs(cloneable)] - pub struct Duration { - pub(crate) value: Option, +#[derive(Clone, Trace)] +#[js::class] +pub struct Duration { + #[qjs(skip_trace)] + 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 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"), - } + } + /// 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"), } } } diff --git a/lib/src/fnc/script/classes/mod.rs b/lib/src/fnc/script/classes/mod.rs index 11041b2d..6699419e 100644 --- a/lib/src/fnc/script/classes/mod.rs +++ b/lib/src/fnc/script/classes/mod.rs @@ -1,13 +1,13 @@ -use js::{Ctx, Result}; +use js::{Class, 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(); - globals.init_def::()?; - globals.init_def::()?; - globals.init_def::()?; + Class::::define(&globals)?; + Class::::define(&globals)?; + Class::::define(&globals)?; Ok(()) } diff --git a/lib/src/fnc/script/classes/record.rs b/lib/src/fnc/script/classes/record.rs index 0508f8be..f8c27ce8 100644 --- a/lib/src/fnc/script/classes/record.rs +++ b/lib/src/fnc/script/classes/record.rs @@ -1,56 +1,52 @@ -#[js::bind(object, public)] -#[quickjs(bare)] -#[allow(non_snake_case)] -#[allow(unused_variables)] -#[allow(clippy::module_inception)] -pub mod record { +use crate::sql::thing; +use crate::sql::value::Value; +use js::class::Trace; - use crate::sql::thing; - use crate::sql::value::Value; - use js::{class::Ref, function::Rest}; +#[derive(Clone, Trace)] +#[js::class] +pub struct Record { + #[qjs(skip_trace)] + pub(crate) value: thing::Thing, +} - #[derive(Clone)] - #[quickjs(cloneable)] - pub struct Record { - pub(crate) value: thing::Thing, +#[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(), + }, + }, + } } - 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(), - }, - }, - } - } + #[qjs(get)] + pub fn tb(&self) -> String { + self.value.tb.clone() + } - #[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 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 4f759ec4..e89e412e 100644 --- a/lib/src/fnc/script/classes/uuid.rs +++ b/lib/src/fnc/script/classes/uuid.rs @@ -1,51 +1,46 @@ -#[js::bind(object, public)] -#[quickjs(bare)] -#[allow(non_snake_case)] -#[allow(unused_variables)] -#[allow(clippy::module_inception)] -pub mod uuid { +use crate::sql::uuid; +use js::class::Trace; - use crate::sql::uuid; - use crate::sql::value::Value; - use js::{class::Ref, function::Rest}; +#[derive(Clone, Trace)] +#[js::class] +pub struct Uuid { + #[qjs(skip_trace)] + pub(crate) value: Option, +} - #[derive(Clone)] - #[quickjs(cloneable)] - pub struct Uuid { - pub(crate) value: Option, +#[js::methods] +impl Uuid { + #[qjs(constructor)] + pub fn new(value: String) -> Self { + Self { + value: uuid::Uuid::try_from(value).ok(), + } } - - 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 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"), - } + } + /// 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"), } } } diff --git a/lib/src/fnc/script/fetch/body.rs b/lib/src/fnc/script/fetch/body.rs index 6e7fa863..17cb19b7 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::{classes::BlobClass, stream::ReadableStream, RequestError}; +use crate::fnc::script::fetch::{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,6 +7,8 @@ use std::{ result::Result as StdResult, }; +use super::classes::Blob; + pub type StreamItem = StdResult; #[derive(Clone)] @@ -127,7 +129,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()?; @@ -142,7 +144,7 @@ impl<'js> FromJs<'js> for Body { }) } }; - if let Ok(x) = Class::::from_object(object.clone()) { + if let Some(x) = Class::::from_object(object.clone()) { let borrow = x.borrow(); return Ok(Body::buffer(BodyKind::Blob(borrow.mime.clone()), borrow.data.clone())); } @@ -194,7 +196,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 Ok(x) = ArrayBuffer::from_object(object.clone()) { + if let Some(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 a616b4de..95e18bb0 100644 --- a/lib/src/fnc/script/fetch/classes/blob.rs +++ b/lib/src/fnc/script/fetch/classes/blob.rs @@ -1,9 +1,11 @@ //! Blob class implementation -use bytes::BytesMut; -use js::{bind, prelude::Coerced, ArrayBuffer, Class, Ctx, Exception, FromJs, Result, Value}; - -pub use blob::Blob as BlobClass; +use bytes::{Bytes, BytesMut}; +use js::{ + class::Trace, + prelude::{Coerced, Opt}, + ArrayBuffer, Class, Ctx, Exception, FromJs, Object, Result, Value, +}; #[derive(Clone, Copy)] pub enum EndingType { @@ -12,7 +14,7 @@ pub enum EndingType { } fn append_blob_part<'js>( - ctx: Ctx<'js>, + ctx: &Ctx<'js>, value: Value<'js>, ending: EndingType, data: &mut BytesMut, @@ -23,11 +25,11 @@ fn append_blob_part<'js>( const LINE_ENDING: &[u8] = b"\n"; if let Some(object) = value.as_object() { - if let Ok(x) = Class::::from_object(object.clone()) { + if let Some(x) = Class::::from_object(object.clone()) { data.extend_from_slice(&x.borrow().data); return Ok(()); } - if let Ok(x) = ArrayBuffer::from_object(object.clone()) { + if let Some(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") })?); @@ -74,144 +76,121 @@ fn normalize_type(mut ty: String) -> String { } } -#[bind(object, public)] -#[quickjs(bare)] -#[allow(non_snake_case)] -#[allow(unused_variables)] -#[allow(clippy::module_inception)] -mod blob { - use super::*; +#[derive(Clone, Trace)] +#[js::class] +pub struct Blob { + pub(crate) mime: String, + // TODO: make bytes? + #[qjs(skip_trace)] + pub(crate) data: Bytes, +} - use bytes::{Bytes, BytesMut}; - use js::{ - function::{Opt, Rest}, - ArrayBuffer, Ctx, Exception, Object, Result, Value, - }; +#[js::methods] +impl Blob { + // ------------------------------ + // Constructor + // ------------------------------ - #[derive(Clone)] - #[quickjs(cloneable)] - pub struct Blob { - pub(crate) mime: String, - // TODO: make bytes? - pub(crate) data: Bytes, + #[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; + + 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, + }) } - impl Blob { - // ------------------------------ - // Constructor - // ------------------------------ + // ------------------------------ + // Instance properties + // ------------------------------ - #[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; + #[qjs(get)] + pub fn size(&self) -> usize { + self.data.len() + } - 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'", - )); - } - } - } + #[qjs(get, rename = "type")] + pub fn r#type(&self) -> String { + self.mime.clone() + } - 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, - }) + 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, } + } - // ------------------------------ - // Instance properties - // ------------------------------ + pub async fn text(&self) -> Result { + let text = String::from_utf8(self.data.to_vec())?; + Ok(text) + } - #[quickjs(get)] - pub fn size(&self) -> usize { - self.data.len() - } + #[qjs(rename = "arrayBuffer")] + pub async fn array_buffer<'js>(&self, ctx: Ctx<'js>) -> Result> { + ArrayBuffer::new(ctx, self.data.to_vec()) + } - #[quickjs(get)] - #[quickjs(rename = "type")] - pub fn r#type(&self) -> String { - self.mime.clone() - } + // ------------------------------ + // Instance methods + // ------------------------------ - 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, - } - } - - pub async fn text(&self, _rest: Rest<()>) -> Result { - let text = String::from_utf8(self.data.to_vec())?; - Ok(text) - } - - pub async fn arrayBuffer<'js>( - &self, - ctx: Ctx<'js>, - _rest: Rest<()>, - ) -> Result> { - ArrayBuffer::new(ctx, self.data.to_vec()) - } - - // ------------------------------ - // Instance methods - // ------------------------------ - - // Convert the object to a string - pub fn toString(&self, _rest: Rest<()>) -> String { - String::from("[object Blob]") - } + // Convert the object to a string + #[qjs(rename = "toString")] + pub fn js_to_string(&self) -> String { + String::from("[object Blob]") } } @@ -242,17 +221,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 f77cd8f7..a963bc98 100644 --- a/lib/src/fnc/script/fetch/classes/form_data.rs +++ b/lib/src/fnc/script/fetch/classes/form_data.rs @@ -1,34 +1,36 @@ //! FormData class implementation use js::{ - bind, function::Opt, prelude::Coerced, Class, Ctx, Exception, FromJs, Persistent, Result, - String, Value, + class::{Class, Trace}, + function::{Opt, Rest}, + prelude::Coerced, + Ctx, Exception, FromJs, Result, String, Value, }; -use std::string::String as StdString; +use reqwest::multipart::{Form, Part}; +use std::{collections::HashMap, string::String as StdString}; -use crate::fnc::script::fetch::classes::BlobClass; +use crate::fnc::script::fetch::classes::Blob; #[derive(Clone)] -pub enum FormDataValue { - String(Persistent>), +pub enum FormDataValue<'js> { + String(String<'js>), Blob { - data: Persistent>, - filename: Option>>, + data: Class<'js, Blob>, + filename: Option>, }, } -impl FormDataValue { - fn from_arguments<'js>( - ctx: Ctx<'js>, +impl<'js> FormDataValue<'js> { + fn from_arguments( + 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()).ok()) + value.as_object().and_then(|value| Class::::from_object(value.clone())) { - let blob = Persistent::save(ctx, blob); - let filename = filename.into_inner().map(|x| Persistent::save(ctx, x.0)); + let filename = filename.into_inner().map(|x| x.0); Ok(FormDataValue::Blob { data: blob, @@ -38,128 +40,109 @@ impl FormDataValue { return Err(Exception::throw_type(ctx, error)); } else { let value = Coerced::::from_js(ctx, value)?; - let value = Persistent::save(ctx, value.0); - Ok(FormDataValue::String(value)) + Ok(FormDataValue::String(value.0)) } } } -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::class] +#[derive(Clone, Trace)] +pub struct FormData<'js> { + #[qjs(skip_trace)] + pub(crate) values: HashMap>>, +} - use js::{ - function::Opt, - prelude::{Coerced, Rest}, - Ctx, Result, String, Value, - }; - use reqwest::multipart::{Form, Part}; +#[js::methods] +impl<'js> FormData<'js> { + // ------------------------------ + // Constructor + // ------------------------------ - #[derive(Clone)] - #[quickjs(cloneable)] - pub struct FormData { - pub(crate) values: RefCell>>, + // 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", + )); + } + Ok(FormData { + values: HashMap::new(), + }) } - impl FormData { - // ------------------------------ - // Constructor - // ------------------------------ + 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`", + )?; - // 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()), - }) - } + self.values.entry(name.0).or_insert_with(Vec::new).push(value); - 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`", - )?; + Ok(()) + } - self.values.borrow_mut().entry(name.0).or_insert_with(Vec::new).push(value); + 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`", + )?; - Ok(()) - } + self.values.insert(name.0, vec![value]); - 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`", - )?; + Ok(()) + } - self.values.borrow_mut().insert(name.0, vec![value]); + pub fn has(&self, name: Coerced) -> bool { + self.values.contains_key(&name.0) + } - Ok(()) - } + pub fn delete(&mut self, name: Coerced) { + self.values.remove(&name.0); + } - pub fn has(&self, ctx: Ctx<'_>, name: Coerced) -> bool { - self.values.borrow().contains_key(&name.0) - } - - pub fn delete(&self, ctx: Ctx<'_>, name: Coerced) { - self.values.borrow_mut().remove(&name.0); - } - - #[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); + #[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); } + 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 01e06053..ecb015d0 100644 --- a/lib/src/fnc/script/fetch/classes/headers.rs +++ b/lib/src/fnc/script/fetch/classes/headers.rs @@ -1,272 +1,258 @@ //! Headers class implementation -use js::bind; +use std::str::FromStr; -pub use headers::Headers as HeadersClass; +use js::{ + class::Trace, + prelude::{Coerced, List}, + Array, Ctx, Exception, Result, Value, +}; +use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; -#[bind(object, public)] -#[quickjs(bare)] -#[allow(non_snake_case)] -#[allow(unused_variables)] -#[allow(clippy::module_inception)] -mod headers { - use std::{cell::RefCell, str::FromStr}; +#[derive(Clone, Trace)] +#[js::class] +pub struct Headers { + #[qjs(skip_trace)] + pub(crate) inner: HeaderMap, +} - use js::{function::Rest, prelude::Coerced, Array, Ctx, Exception, Result, Value}; - use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; +#[js::methods] +impl Headers { + // ------------------------------ + // Constructor + // ------------------------------ - #[derive(Clone)] - #[quickjs(cloneable)] - #[allow(dead_code)] - pub struct Headers { - pub(crate) inner: RefCell, + #[qjs(constructor)] + pub fn new<'js>(ctx: Ctx<'js>, init: Value<'js>) -> Result { + Headers::new_inner(&ctx, init) } - impl Headers { - // ------------------------------ - // Constructor - // ------------------------------ + // ------------------------------ + // Instance methods + // ------------------------------ - #[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 - } + // Convert the object to a string + #[qjs(rename = "toString")] + pub fn js_to_string(&self) -> String { + String::from("[object Header]") } - #[quickjs(skip)] - impl Headers { - pub fn from_map(map: HeaderMap) -> Self { - Self { - inner: RefCell::new(map), - } - } + // 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) + } - pub fn new_empty() -> Self { - Self::from_map(HeaderMap::new()) - } + // 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_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(); + // Returns all header entries in the header set + pub fn entries(&self) -> Vec> { + let mut res = Vec::>::with_capacity(self.inner.len()); - // 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)?; - } + 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()); } else { - return Err(Exception::throw_type(ctx, INVALID_ERROR)); + res.push(List((k.to_owned(), v.to_str().unwrap().to_owned()))); } - - Ok(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. + res + } - 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}"), - )) - } - }; + // 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); - self.inner.borrow_mut().append(key, val); - - Ok(()) + // 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. + #[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(()) } } @@ -327,7 +313,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 f57c982e..aae64746 100644 --- a/lib/src/fnc/script/fetch/classes/request.rs +++ b/lib/src/fnc/script/fetch/classes/request.rs @@ -1,18 +1,9 @@ //! Request class implementation -//! -use js::{ - bind, - class::{HasRefs, RefsMarker}, - prelude::Coerced, - Class, Ctx, Exception, FromJs, Object, Persistent, Result, Value, -}; + +use js::{class::Trace, prelude::Coerced, Class, Ctx, Exception, FromJs, Object, Result, Value}; use reqwest::Method; -use crate::fnc::script::fetch::{ - body::Body, - classes::{BlobClass, HeadersClass}, - RequestError, -}; +use crate::fnc::script::fetch::{body::Body, RequestError}; #[derive(Clone, Copy, Eq, PartialEq)] pub enum RequestMode { @@ -23,7 +14,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, @@ -59,7 +50,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, @@ -96,7 +87,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, @@ -136,7 +127,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, @@ -176,7 +167,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, @@ -213,9 +204,9 @@ impl<'js> FromJs<'js> for ReferrerPolicy { } } -pub struct RequestInit { +pub struct RequestInit<'js> { pub method: Method, - pub headers: Persistent>, + pub headers: Class<'js, Headers>, pub body: Option, pub referrer: String, pub referrer_policy: ReferrerPolicy, @@ -227,15 +218,15 @@ pub struct RequestInit { pub keep_alive: bool, } -impl HasRefs for RequestInit { - fn mark_refs(&self, marker: &RefsMarker) { - self.headers.mark_refs(marker); +impl<'js> Trace<'js> for RequestInit<'js> { + fn trace<'a>(&self, tracer: js::class::Tracer<'a, 'js>) { + self.headers.trace(tracer); } } -impl RequestInit { - pub fn default(ctx: Ctx<'_>) -> Result { - let headers = Persistent::save(ctx, Class::instance(ctx, HeadersClass::new_empty())?); +impl<'js> RequestInit<'js> { + pub fn default(ctx: Ctx<'js>) -> Result { + let headers = Class::instance(ctx, Headers::new_empty())?; Ok(RequestInit { method: Method::GET, headers, @@ -251,9 +242,9 @@ impl RequestInit { }) } - 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())?); + pub fn clone_js(&self, ctx: Ctx<'js>) -> Result { + let headers = self.headers.clone(); + let headers = Class::instance(ctx.clone(), headers.borrow().clone())?; let body = self.body.as_ref().map(|x| x.clone_js(ctx)); @@ -274,7 +265,7 @@ impl RequestInit { } // 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") @@ -309,8 +300,8 @@ fn normalize_method(ctx: Ctx<'_>, m: String) -> Result { } } -impl<'js> FromJs<'js> for RequestInit { - fn from_js(ctx: Ctx<'js>, value: Value<'js>) -> Result { +impl<'js> FromJs<'js> for RequestInit<'js> { + fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { let object = Object::from_js(ctx, value)?; let referrer = object @@ -346,15 +337,14 @@ impl<'js> FromJs<'js> for RequestInit { } let headers = if let Some(hdrs) = object.get::<_, Option>("headers")? { - if let Ok(cls) = Class::::from_object(hdrs.clone()) { + if let Some(cls) = Class::::from_object(hdrs.clone()) { cls } else { - Class::instance(ctx, HeadersClass::new_inner(ctx, hdrs.into_value())?)? + Class::instance(ctx.clone(), Headers::new_inner(ctx, hdrs.into_value())?)? } } else { - Class::instance(ctx, HeadersClass::new_empty())? + Class::instance(ctx.clone(), Headers::new_empty())? }; - let headers = Persistent::save(ctx, headers); let body = object.get::<_, Option>("body")?; @@ -376,192 +366,173 @@ impl<'js> FromJs<'js> for RequestInit { pub use request::Request as RequestClass; -#[bind(object, public)] -#[quickjs(bare)] -#[allow(non_snake_case)] -#[allow(unused_variables)] -#[allow(clippy::module_inception)] -mod request { +pub use super::*; - pub use super::*; +use bytes::Bytes; +use js::function::Opt; +// TODO: change implementation based on features. +use reqwest::{header::HeaderName, Url}; - 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}; +#[allow(dead_code)] +#[js::class] +#[derive(Trace)] +pub struct Request<'js> { + #[qjs(skip_trace)] + pub(crate) url: Url, + pub(crate) init: RequestInit<'js>, +} - #[allow(dead_code)] - #[derive(HasRefs)] - #[quickjs(has_refs)] - pub struct Request { - pub(crate) url: Url, - #[quickjs(has_refs)] - pub(crate) init: RequestInit, +#[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", + )) + } } - impl Request { - // ------------------------------ - // Constructor - // ------------------------------ + /// 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)?, + }) + } - #[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.")); + // ------------------------------ + // 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}"))) } - 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", - )) - } + }, } + } - /// 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)?, - }) - } + // 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() + }; - // ------------------------------ - // Instance properties - // ------------------------------ - #[quickjs(get)] - pub fn bodyUsed(&self) -> bool { - self.init.body.as_ref().map(Body::used).unwrap_or(true) - } + let data = self.take_buffer(&ctx).await?; + Ok(Blob { + mime, + data, + }) + } - #[quickjs(get)] - pub fn method(&self) -> String { - self.init.method.to_string() - } + // 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 url(&self) -> String { - self.url.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 headers<'js>(&self, ctx: Ctx<'js>) -> Class<'js, HeadersClass> { - self.init.headers.clone().restore(ctx).unwrap() - } + // 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 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()) - } + // 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()) } } } @@ -644,7 +615,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 53cbcb78..04c25394 100644 --- a/lib/src/fnc/script/fetch/classes/response/init.rs +++ b/lib/src/fnc/script/fetch/classes/response/init.rs @@ -1,34 +1,33 @@ use std::string::String as StdString; use js::{ - class::{HasRefs, RefsMarker}, + class::{Trace, Tracer}, prelude::*, - Class, Ctx, Exception, FromJs, Object, Persistent, Result, Value, + Class, Ctx, Exception, FromJs, Object, Result, Value, }; -use crate::fnc::script::fetch::{classes::HeadersClass, util}; +use crate::fnc::script::fetch::{classes::Headers, util}; /// Struct containing data from the init argument from the Response constructor. #[derive(Clone)] -pub struct ResponseInit { +pub struct ResponseInit<'js> { // u16 instead of reqwest::StatusCode since javascript allows non valid status codes in some // circumstances. pub status: u16, pub status_text: StdString, - pub headers: Persistent>, + pub headers: Class<'js, Headers>, } -impl HasRefs for ResponseInit { - fn mark_refs(&self, marker: &RefsMarker) { - self.headers.mark_refs(marker); +impl<'js> Trace<'js> for ResponseInit<'js> { + fn trace<'a>(&self, tracer: Tracer<'a, 'js>) { + self.headers.trace(tracer); } } -impl ResponseInit { +impl<'js> ResponseInit<'js> { /// Returns a ResponseInit object with all values as the default value. - pub fn default(ctx: Ctx<'_>) -> Result { - let headers = Class::instance(ctx, HeadersClass::new_empty())?; - let headers = Persistent::save(ctx, headers); + pub fn default(ctx: Ctx<'js>) -> Result { + let headers = Class::instance(ctx, Headers::new_empty())?; Ok(ResponseInit { status: 200, status_text: StdString::new(), @@ -37,8 +36,8 @@ impl ResponseInit { } } -impl<'js> FromJs<'js> for ResponseInit { - fn from_js(ctx: Ctx<'js>, value: Value<'js>) -> Result { +impl<'js> FromJs<'js> for ResponseInit<'js> { + fn from_js(ctx: &Ctx<'js>, value: Value<'js>) -> Result { let object = Object::from_js(ctx, value)?; // Extract status. @@ -66,12 +65,11 @@ impl<'js> FromJs<'js> for ResponseInit { // Extract headers. let headers = if let Some(headers) = object.get::<_, Option>("headers")? { - let headers = HeadersClass::new_inner(ctx, headers)?; - Class::instance(ctx, headers)? + let headers = Headers::new_inner(ctx, headers)?; + Class::instance(ctx.clone(), headers)? } else { - Class::instance(ctx, HeadersClass::new_empty())? + Class::instance(ctx.clone(), Headers::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 87a0223b..4791900c 100644 --- a/lib/src/fnc/script/fetch/classes/response/mod.rs +++ b/lib/src/fnc/script/fetch/classes/response/mod.rs @@ -1,11 +1,10 @@ //! Response class implementation -use js::bind; - mod init; +use bytes::Bytes; pub use init::ResponseInit; -pub use response::Response as ResponseClass; +use js::{class::Trace, prelude::Opt, ArrayBuffer, Class, Ctx, Exception, Result, Value}; #[allow(dead_code)] #[derive(Clone, Copy)] @@ -18,304 +17,284 @@ pub enum ResponseType { OpaqueRedirect, } -#[bind(object, public)] -#[quickjs(bare)] -#[allow(non_snake_case)] -#[allow(unused_variables)] -#[allow(clippy::module_inception)] -pub mod response { +use reqwest::Url; - use crate::fnc::script::fetch::{ - body::{Body, BodyKind}, - classes::{BlobClass, HeadersClass}, - util, RequestError, - }; +use crate::fnc::script::fetch::{ + body::{Body, BodyKind}, + util, RequestError, +}; - use super::{ResponseInit, ResponseType}; - use bytes::Bytes; - use js::{ - function::{Opt, Rest}, - ArrayBuffer, Class, Ctx, Exception, HasRefs, Persistent, Result, Value, - }; - use reqwest::Url; +use super::{Blob, Headers}; - #[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, +#[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, + }) } - impl Response { - // ------------------------------ - // Constructor - // ------------------------------ + // ------------------------------ + // Instance properties + // ------------------------------ - #[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 - ), - )); + #[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() } - let body = body.unwrap_or_default(); + }) + } - Ok(Response { - body, - init, - url: None, - r#type: ResponseType::Default, - was_redirected: false, - }) + // ------------------------------ + // 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, } + } - // ------------------------------ - // 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() + #[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}"))) } - }) + }, + } + } + + // 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")); } - // ------------------------------ - // Instance methods - // ------------------------------ + let headers = Class::instance(ctx, Headers::new_empty())?; - // 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, - }) - } + Ok(Response { + url: Some(url), + body: Body::new(), + init: ResponseInit { + status, + status_text: String::new(), + headers, + }, + r#type: ResponseType::Default, + was_redirected: false, + }) } } @@ -388,7 +367,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 cc2f6241..40dc9fac 100644 --- a/lib/src/fnc/script/fetch/func.rs +++ b/lib/src/fnc/script/fetch/func.rs @@ -2,29 +2,28 @@ use crate::fnc::script::fetch::{ body::{Body, BodyData, BodyKind}, - classes::{ - self, HeadersClass, RequestClass, RequestInit, ResponseClass, ResponseInit, ResponseType, - }, + classes::{self, Request, RequestInit, Response, ResponseInit, ResponseType}, RequestError, }; use futures::TryStreamExt; -use js::{bind, function::Opt, prelude::*, Class, Ctx, Exception, Persistent, Result, Value}; +use js::{function::Opt, Class, Ctx, Exception, Result, Value}; use reqwest::{ header::{HeaderValue, CONTENT_TYPE}, redirect, Body as ReqBody, }; use std::sync::Arc; -#[bind(object, public)] +use super::classes::Headers; + +#[js::function] #[allow(unused_variables)] pub async fn fetch<'js>( ctx: Ctx<'js>, input: Value<'js>, - init: Opt, - args: Rest<()>, -) -> Result { + init: Opt>, +) -> Result> { // Create a request from the input. - let js_req = RequestClass::new(ctx, input, init, args)?; + let js_req = Request::new(ctx.clone(), input, init)?; let url = js_req.url; @@ -32,9 +31,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.restore(ctx).unwrap(); + let headers = js_req.init.headers; let headers = headers.borrow(); - let mut headers = headers.inner.borrow().clone(); + let mut headers = headers.inner.clone(); let redirect = js_req.init.request_redirect; @@ -55,7 +54,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. @@ -70,7 +69,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 => {} @@ -94,12 +93,11 @@ 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 = HeadersClass::from_map(response.headers().clone()); + let headers = Headers::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(), @@ -111,7 +109,7 @@ pub async fn fetch<'js>( BodyKind::Buffer, response.bytes_stream().map_err(Arc::new).map_err(RequestError::Reqwest), ); - let response = ResponseClass { + let response = Response { body, init, url: Some(url), diff --git a/lib/src/fnc/script/fetch/mod.rs b/lib/src/fnc/script/fetch/mod.rs index 5636df74..40f831e9 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::{Ctx, Result}; +use js::{Class, Ctx, Result}; mod body; mod classes; @@ -9,7 +9,7 @@ mod stream; mod util; use classes::{Blob, FormData, Headers, Request, Response}; -use func::Fetch; +use func::js_fetch; // Anoyingly errors aren't clone, // But with how we implement streams RequestError must be clone. @@ -30,15 +30,14 @@ 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.init_def::()?; - - globals.init_def::()?; - globals.init_def::()?; - globals.init_def::()?; - globals.init_def::()?; - globals.init_def::()?; + globals.set("fetch", js_fetch)?; + Class::::define(&globals)?; + Class::::define(&globals)?; + Class::::define(&globals)?; + Class::::define(&globals)?; + Class::::define(&globals)?; Ok(()) } @@ -55,9 +54,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) { @@ -91,7 +90,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 9f050826..60fd45e1 100644 --- a/lib/src/fnc/script/fetch_stub/mod.rs +++ b/lib/src/fnc/script/fetch_stub/mod.rs @@ -1,4 +1,5 @@ -/// The stub implementations for the fetch API when `http` is not enabled. +//! 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 55a5363c..10fc6a00 100644 --- a/lib/src/fnc/script/from.rs +++ b/lib/src/fnc/script/from.rs @@ -5,6 +5,7 @@ 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; @@ -20,7 +21,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), @@ -49,14 +50,15 @@ 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, &e).map(|x| x.throw()); + let (Ok(e) | Err(e)) = + Exception::from_message(ctx.clone(), &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_instance::().unwrap(); + if (v).instance_of::() { + let v = v.into_class::().unwrap(); let borrow = v.borrow(); - let v: &classes::record::record::Record = &borrow; + let v: &classes::record::Record = &borrow; check_nul(&v.value.tb)?; if let Id::String(s) = &v.value.id { check_nul(s)?; @@ -64,20 +66,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_instance::().unwrap(); + if (v).instance_of::() { + let v = v.into_class::().unwrap(); let borrow = v.borrow(); - let v: &classes::duration::duration::Duration = &borrow; + let v: &classes::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_instance::().unwrap(); + if (v).instance_of::() { + let v = v.into_class::().unwrap(); let borrow = v.borrow(); - let v: &classes::uuid::uuid::Uuid = &borrow; + let v: &classes::uuid::Uuid = &borrow; return match &v.value { Some(v) => Ok(v.clone().into()), None => Ok(Value::None), @@ -87,7 +89,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((js::prelude::This(v),))?; + let m: i64 = f.call((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 7ec7fda5..b681ea78 100644 --- a/lib/src/fnc/script/globals/console.rs +++ b/lib/src/fnc/script/globals/console.rs @@ -1,32 +1,44 @@ -#[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(" ")); - } +// 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) } diff --git a/lib/src/fnc/script/into.rs b/lib/src/fnc/script/into.rs index 1b999c0b..495df24f 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, *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::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::Number(Number::Decimal(v)) => match decimal_is_integer(&v) { - 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())), + 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())), }, Value::Datetime(v) => { - let date: js::Function = ctx.globals().get("Date")?; + let date: js::function::Constructor = ctx.globals().get("Date")?; date.construct((v.0.timestamp_millis(),)) } - Value::Thing(v) => Ok(Class::::instance( - ctx, - classes::record::record::Record { + Value::Thing(v) => Ok(Class::::instance( + ctx.clone(), + classes::record::Record { value: v.to_owned(), }, )? .into_value()), - Value::Duration(v) => Ok(Class::::instance( - ctx, - classes::duration::duration::Duration { + Value::Duration(v) => Ok(Class::::instance( + ctx.clone(), + classes::duration::Duration { value: Some(v.to_owned()), }, )? .into_value()), - Value::Uuid(v) => Ok(Class::::instance( - ctx, - classes::uuid::uuid::Uuid { + Value::Uuid(v) => Ok(Class::::instance( + ctx.clone(), + classes::uuid::Uuid { value: Some(v.to_owned()), }, )? .into_value()), Value::Array(v) => { - let x = Array::new(ctx)?; + let x = Array::new(ctx.clone())?; for (i, v) in v.iter().enumerate() { x.set(i, v)?; } x.into_js(ctx) } Value::Object(v) => { - let x = Object::new(ctx)?; + let x = Object::new(ctx.clone())?; 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 6f837d94..08ec697f 100644 --- a/lib/src/fnc/script/main.rs +++ b/lib/src/fnc/script/main.rs @@ -50,23 +50,24 @@ pub async fn run( // Attempt to execute the script async_with!(ctx => |ctx|{ - let res = async move { + let res = async{ // 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, "surrealdb")? + Module::evaluate_def::(ctx.clone(), "surrealdb")? .get::<_, js::Value>("default")?, )?; - fetch::register(ctx)?; + fetch::register(&ctx)?; + let console = globals::console::console(&ctx)?; // Register the console function to the globals - global.init_def::()?; + global.set("console",console)?; // Register the special SurrealDB types as classes - classes::init(ctx)?; + classes::init(&ctx)?; // Attempt to compile the script - let res = ctx.compile("script", src)?; + let res = ctx.clone().compile("script", src)?; // Attempt to fetch the main export let fnc = res.get::<_, Function>("default")?; // Extract the doc if any @@ -76,7 +77,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 4e37c88a..879241f7 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)?; + fn evaluate<'js>(ctx: &js::Ctx<'js>, exports: &mut js::module::Exports<'js>) -> js::Result<()> { + let default = js::Object::new(ctx.clone())?; $( 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 49162f66..1e6b4b9b 100644 --- a/lib/src/fnc/script/modules/os.rs +++ b/lib/src/fnc/script/modules/os.rs @@ -1,13 +1,31 @@ -#[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() +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(()) } - /// Get the target operating system - pub fn platform() -> &'static str { - crate::env::os() + + fn evaluate<'js>(_ctx: &js::Ctx<'js>, exports: &mut Exports<'js>) -> Result<()> { + exports.export("arch", js_arch)?; + exports.export("platform", js_platform)?; + Ok(()) } } diff --git a/lib/src/fnc/script/modules/surrealdb/mod.rs b/lib/src/fnc/script/modules/surrealdb/mod.rs index 7e38b6b2..26fb2796 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, name)?.get::<_, js::Value>("default") + Module::evaluate_def::(ctx.clone(), name)?.get::<_, js::Value>("default") } diff --git a/lib/src/sql/value/value.rs b/lib/src/sql/value/value.rs index 7da8b193..bc84f588 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!(16, std::mem::size_of::()); + assert_eq!(32, 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::>());