From 43c01796ebc823db831de28c3f5f7347eb3732dd Mon Sep 17 00:00:00 2001 From: LongYinan Date: Sat, 3 Oct 2020 00:05:43 +0800 Subject: [PATCH] feat(napi): implement JsTimeout --- napi/src/js_values/global.rs | 29 ++++++ package.json | 23 ++++- test_module/__test__/get-napi-version.spec.ts | 1 - test_module/__test__/global.spec.ts | 17 ++++ test_module/src/function.rs | 4 +- test_module/src/global.rs | 18 ++++ test_module/src/lib.rs | 2 + test_module/src/napi4/tsfn.rs | 6 +- yarn.lock | 96 ++++++++++++++++++- 9 files changed, 183 insertions(+), 13 deletions(-) create mode 100644 test_module/__test__/global.spec.ts create mode 100644 test_module/src/global.rs diff --git a/napi/src/js_values/global.rs b/napi/src/js_values/global.rs index 0d1f880b..b67c1641 100644 --- a/napi/src/js_values/global.rs +++ b/napi/src/js_values/global.rs @@ -26,4 +26,33 @@ impl JsGlobal { ) .and_then(|ret| ret.try_into()) } + + pub fn clear_interval(&self, timer: JsTimeout) -> Result { + let func: JsFunction = self.get_named_property("clearInterval")?; + func + .call(None, &[timer.into_unknown()]) + .and_then(|ret| ret.try_into()) + } + + pub fn set_timeout(&self, handler: JsFunction, interval: f64) -> Result { + let func: JsFunction = self.get_named_property("setTimeout")?; + func + .call( + None, + &[ + handler.into_unknown(), + Env::from_raw(self.0.env) + .create_double(interval)? + .into_unknown(), + ], + ) + .and_then(|ret| ret.try_into()) + } + + pub fn clear_timeout(&self, timer: JsTimeout) -> Result { + let func: JsFunction = self.get_named_property("clearTimeout")?; + func + .call(None, &[timer.into_unknown()]) + .and_then(|ret| ret.try_into()) + } } diff --git a/package.json b/package.json index bce5b6fe..24da3b22 100644 --- a/package.json +++ b/package.json @@ -58,12 +58,23 @@ "trailingComma": "all", "arrowParens": "always" }, - "files": ["scripts", "LICENSE"], + "files": [ + "scripts", + "LICENSE" + ], "lint-staged": { - "*.js": ["prettier --write"], - "*.@(yml|yaml)": ["prettier --parser yaml --write"], - "*.json": ["prettier --parser json --write"], - "*.md": ["prettier --parser markdown --write"] + "*.js": [ + "prettier --write" + ], + "*.@(yml|yaml)": [ + "prettier --parser yaml --write" + ], + "*.json": [ + "prettier --parser json --write" + ], + "*.md": [ + "prettier --parser markdown --write" + ] }, "husky": { "hooks": { @@ -77,6 +88,7 @@ "@types/inquirer": "^7.3.1", "@types/lodash": "^4.14.161", "@types/node": "^14.11.2", + "@types/sinon": "^9.0.7", "@typescript-eslint/eslint-plugin": "^4.3.0", "@typescript-eslint/parser": "^4.3.0", "ava": "^3.13.0", @@ -91,6 +103,7 @@ "npm-run-all": "^4.1.5", "nyc": "^15.1.0", "prettier": "^2.1.2", + "sinon": "^9.1.0", "source-map-support": "^0.5.19", "ts-node": "^9.0.0", "typescript": "^4.0.3" diff --git a/test_module/__test__/get-napi-version.spec.ts b/test_module/__test__/get-napi-version.spec.ts index 2e51c1a5..62fa68b8 100644 --- a/test_module/__test__/get-napi-version.spec.ts +++ b/test_module/__test__/get-napi-version.spec.ts @@ -5,6 +5,5 @@ const bindings = require('../index.node') test('should get napi version', (t) => { const napiVersion = bindings.getNapiVersion() t.true(typeof napiVersion === 'number') - // @ts-expect-error t.is(`${napiVersion}`, process.versions.napi) }) diff --git a/test_module/__test__/global.spec.ts b/test_module/__test__/global.spec.ts new file mode 100644 index 00000000..b321b2d4 --- /dev/null +++ b/test_module/__test__/global.spec.ts @@ -0,0 +1,17 @@ +import test from 'ava' +import Sinon from 'sinon' + +const bindings = require('../index.node') + +function wait(delay: number) { + return new Promise((resolve) => setTimeout(resolve, delay)) +} + +test('should setTimeout', async (t) => { + const handler = Sinon.spy() + const delay = 100 + bindings.setTimeout(handler, delay) + t.is(handler.callCount, 0) + await wait(delay + 10) + t.is(handler.callCount, 1) +}) diff --git a/test_module/src/function.rs b/test_module/src/function.rs index 4307c609..94cd8c6b 100644 --- a/test_module/src/function.rs +++ b/test_module/src/function.rs @@ -3,8 +3,8 @@ use napi::{CallContext, JsFunction, JsNull, JsObject, Module, Result}; #[js_function(1)] pub fn call_function(ctx: CallContext) -> Result { let js_func = ctx.get::(0)?; - let js_string_hello = ctx.env.create_string("hello".as_ref())?.into_unknown()?; - let js_string_world = ctx.env.create_string("world".as_ref())?.into_unknown()?; + let js_string_hello = ctx.env.create_string("hello".as_ref())?.into_unknown(); + let js_string_world = ctx.env.create_string("world".as_ref())?.into_unknown(); js_func.call(None, &[js_string_hello, js_string_world])?; diff --git a/test_module/src/global.rs b/test_module/src/global.rs new file mode 100644 index 00000000..fb70053a --- /dev/null +++ b/test_module/src/global.rs @@ -0,0 +1,18 @@ +use std::convert::TryInto; + +use napi::{CallContext, JsFunction, JsNumber, JsTimeout, Module, Result}; + +#[js_function(2)] +pub fn set_timeout(ctx: CallContext) -> Result { + let handler: JsFunction = ctx.get(0)?; + let timeout: JsNumber = ctx.get(1)?; + ctx + .env + .get_global()? + .set_timeout(handler, timeout.try_into()?) +} + +pub fn register_js(module: &mut Module) -> Result<()> { + module.create_named_method("setTimeout", set_timeout)?; + Ok(()) +} diff --git a/test_module/src/lib.rs b/test_module/src/lib.rs index 25435cf9..4c0ccabc 100644 --- a/test_module/src/lib.rs +++ b/test_module/src/lib.rs @@ -26,6 +26,7 @@ mod env; mod error; mod external; mod function; +mod global; mod napi_version; mod object; mod serde; @@ -52,6 +53,7 @@ fn init(module: &mut Module) -> Result<()> { class::register_js(module)?; env::register_js(module)?; object::register_js(module)?; + global::register_js(module)?; #[cfg(napi4)] napi4::register_js(module)?; #[cfg(napi4)] diff --git a/test_module/src/napi4/tsfn.rs b/test_module/src/napi4/tsfn.rs index 2281f7ef..214363c9 100644 --- a/test_module/src/napi4/tsfn.rs +++ b/test_module/src/napi4/tsfn.rs @@ -16,7 +16,7 @@ impl ToJs for HandleNumber { fn resolve(&self, env: &mut Env, output: Self::Output) -> Result> { let mut items: Vec = vec![]; for item in output.iter() { - let value = env.create_uint32((*item) as u32)?.into_unknown()?; + let value = env.create_uint32((*item) as u32)?.into_unknown(); items.push(value); } Ok(items) @@ -75,9 +75,7 @@ impl ToJs for HandleBuffer { type Output = Vec; fn resolve(&self, env: &mut Env, output: Self::Output) -> Result> { - let value = env - .create_buffer_with_data(output.to_vec())? - .into_unknown()?; + let value = env.create_buffer_with_data(output.to_vec())?.into_unknown(); Ok(vec![value]) } } diff --git a/yarn.lock b/yarn.lock index 5673d60c..82907dae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -423,6 +423,42 @@ resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== +"@sinonjs/commons@^1", "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.7.2": + version "1.8.1" + resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217" + integrity sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^6.0.0", "@sinonjs/fake-timers@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" + integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@sinonjs/formatio@^5.0.1": + version "5.0.1" + resolved "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz#f13e713cb3313b1ab965901b01b0828ea6b77089" + integrity sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ== + dependencies: + "@sinonjs/commons" "^1" + "@sinonjs/samsam" "^5.0.2" + +"@sinonjs/samsam@^5.0.2", "@sinonjs/samsam@^5.1.0": + version "5.1.0" + resolved "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.1.0.tgz#3afe719232b541bb6cf3411a4c399a188de21ec0" + integrity sha512-42nyaQOVunX5Pm6GRJobmzbS7iLI+fhERITnETXzzwDZh+TtDr/Au3yAvXVjFmZ4wEUaE4Y3NFZfKv0bV0cbtg== + dependencies: + "@sinonjs/commons" "^1.6.0" + lodash.get "^4.4.2" + type-detect "^4.0.8" + +"@sinonjs/text-encoding@^0.7.1": + version "0.7.1" + resolved "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" + integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ== + "@swc-node/core@^1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@swc-node/core/-/core-1.0.0.tgz#d719abe9d5aa49bb169153d1f3b8ef5364f6f30d" @@ -529,6 +565,18 @@ resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== +"@types/sinon@^9.0.7": + version "9.0.7" + resolved "https://registry.npmjs.org/@types/sinon/-/sinon-9.0.7.tgz#c277e19cf9eb0c71106e785650f1e5c299262302" + integrity sha512-uyFiy2gp4P/FK9pmU3WIbT5ZzH54hCswwRkQFhxX7xl8jzhW3g+xOkVqk5YP4cIO//Few8UDAX0MtzFpqBEqwA== + dependencies: + "@types/sinonjs__fake-timers" "*" + +"@types/sinonjs__fake-timers@*": + version "6.0.2" + resolved "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.2.tgz#3a84cf5ec3249439015e14049bd3161419bf9eae" + integrity sha512-dIPoZ3g5gcx9zZEszaxLSVTvMReD3xxyyDnQUjA6IYDG9Ba2AV0otMPs+77sG9ojB4Qr2N2Vk5RnKeuA0X/0bg== + "@types/through@*": version "0.0.30" resolved "https://registry.npmjs.org/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895" @@ -1349,7 +1397,7 @@ deprecation@^2.0.0, deprecation@^2.3.1: resolved "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== -diff@^4.0.1: +diff@^4.0.1, diff@^4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== @@ -2304,6 +2352,11 @@ is-yarn-global@^0.3.0: resolved "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + isarray@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -2458,6 +2511,11 @@ jsonparse@^1.3.1: resolved "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= +just-extend@^4.0.2: + version "4.1.1" + resolved "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz#158f1fdb01f128c411dc8b286a7b4837b3545282" + integrity sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA== + keyv@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" @@ -2775,6 +2833,17 @@ nice-try@^1.0.4: resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +nise@^4.0.4: + version "4.0.4" + resolved "https://registry.npmjs.org/nise/-/nise-4.0.4.tgz#d73dea3e5731e6561992b8f570be9e363c4512dd" + integrity sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A== + dependencies: + "@sinonjs/commons" "^1.7.0" + "@sinonjs/fake-timers" "^6.0.0" + "@sinonjs/text-encoding" "^0.7.1" + just-extend "^4.0.2" + path-to-regexp "^1.7.0" + node-fetch@^2.6.1: version "2.6.1" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" @@ -3144,6 +3213,13 @@ path-parse@^1.0.6: resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== +path-to-regexp@^1.7.0: + version "1.8.0" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" + integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== + dependencies: + isarray "0.0.1" + path-type@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" @@ -3580,6 +3656,19 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== +sinon@^9.1.0: + version "9.1.0" + resolved "https://registry.npmjs.org/sinon/-/sinon-9.1.0.tgz#4afc90707c8e360fe051398eed2d3b197980ffc3" + integrity sha512-9zQShgaeylYH6qtsnNXlTvv0FGTTckuDfHBi+qhgj5PvW2r2WslHZpgc3uy3e/ZAoPkqaOASPi+juU6EdYRYxA== + dependencies: + "@sinonjs/commons" "^1.7.2" + "@sinonjs/fake-timers" "^6.0.1" + "@sinonjs/formatio" "^5.0.1" + "@sinonjs/samsam" "^5.1.0" + diff "^4.0.2" + nise "^4.0.4" + supports-color "^7.1.0" + slash@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -3950,6 +4039,11 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" +type-detect@4.0.8, type-detect@^4.0.8: + version "4.0.8" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + type-fest@^0.11.0: version "0.11.0" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1"