From 183124930aaf6b7a46a490f41f361de5afc735a7 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Fri, 28 Apr 2023 12:21:01 -0400 Subject: [PATCH 1/7] lib: add `navigator.hardwareConcurrency` Co-authored-by: Mestery Co-authored-by: Voltrex --- .eslintrc.js | 1 + doc/api/globals.md | 28 +++++++++++++ lib/.eslintrc.yaml | 4 ++ .../bootstrap/web/exposed-window-or-worker.js | 3 ++ lib/internal/navigator.js | 40 +++++++++++++++++++ test/common/index.js | 8 ++++ test/parallel/test-bootstrap-modules.js | 2 + test/parallel/test-navigator.js | 15 +++++++ 8 files changed, 101 insertions(+) create mode 100644 lib/internal/navigator.js create mode 100644 test/parallel/test-navigator.js diff --git a/.eslintrc.js b/.eslintrc.js index 5a63c79371c984..43e41026b2007e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -328,6 +328,7 @@ module.exports = { DecompressionStream: 'readable', fetch: 'readable', FormData: 'readable', + navigator: 'readable', ReadableStream: 'readable', ReadableStreamDefaultReader: 'readable', ReadableStreamBYOBReader: 'readable', diff --git a/doc/api/globals.md b/doc/api/globals.md index 8285064c2e25e4..c816b3bf76e254 100644 --- a/doc/api/globals.md +++ b/doc/api/globals.md @@ -583,6 +583,32 @@ The `MessagePort` class. See [`MessagePort`][] for more details. This variable may appear to be global but is not. See [`module`][]. +## `Navigator` + + + +> Stability: 1 - Experimental + +An implementation of the [Navigator API][]. Similar to [`window.navigator`][] +in browsers. + +### `navigator.hardwareConcurrency` + + + +* {number} + +The `navigator.hardwareConcurrency` read-only property returns the number of +logical processors available to the current Node.js instance. + +```js +console.log(`This process is running on ${navigator.hardwareConcurrency}`); +``` + ## `PerformanceEntry` + +> Stability: 1 - Experimental + +An implementation of [`window.navigator`][]. ### `navigator.hardwareConcurrency` From 10f375e275ea47c9d5aee6aa7ce601ee335be9bb Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Wed, 21 Jun 2023 13:20:54 -0400 Subject: [PATCH 3/7] lib: apply changes to navigator --- .../bootstrap/web/exposed-window-or-worker.js | 3 +- lib/internal/navigator.js | 28 +++++++++---------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/internal/bootstrap/web/exposed-window-or-worker.js b/lib/internal/bootstrap/web/exposed-window-or-worker.js index 0f0ade6609756a..e6f6dcb4e72e89 100644 --- a/lib/internal/bootstrap/web/exposed-window-or-worker.js +++ b/lib/internal/bootstrap/web/exposed-window-or-worker.js @@ -56,7 +56,8 @@ exposeLazyInterfaces(globalThis, 'perf_hooks', [ defineReplaceableLazyAttribute(globalThis, 'perf_hooks', ['performance']); // https://html.spec.whatwg.org/multipage/system-state.html#the-navigator-object -exposeLazyInterfaces(globalThis, 'internal/navigator', ['Navigator', 'navigator']); +exposeLazyInterfaces(globalThis, 'internal/navigator', ['Navigator']); +defineReplaceableLazyAttribute(globalThis, 'internal/navigator', ['navigator'], false); // https://w3c.github.io/FileAPI/#creating-revoking const { installObjectURLMethods } = require('internal/url'); diff --git a/lib/internal/navigator.js b/lib/internal/navigator.js index 7fa49eb3e7401e..5c179829cb09d4 100644 --- a/lib/internal/navigator.js +++ b/lib/internal/navigator.js @@ -2,13 +2,17 @@ const { ObjectDefineProperties, - ObjectSetPrototypeOf, + ReflectConstruct, } = primordials; const { ERR_ILLEGAL_CONSTRUCTOR, } = require('internal/errors').codes; +const { + kEnumerableProperty, +} = require('internal/util'); + const { getAvailableParallelism, } = internalBinding('os'); @@ -17,24 +21,20 @@ class Navigator { constructor() { throw ERR_ILLEGAL_CONSTRUCTOR(); } -} -class InternalNavigator {} -InternalNavigator.prototype.constructor = Navigator.prototype.constructor; -ObjectSetPrototypeOf(InternalNavigator.prototype, Navigator.prototype); + /** + * @return {number} + */ + get hardwareConcurrency() { + return getAvailableParallelism(); + } +} ObjectDefineProperties(Navigator.prototype, { - hardwareConcurrency: { - __proto__: null, - configurable: true, - enumerable: true, - get() { - return getAvailableParallelism(); - }, - }, + hardwareConcurrency: kEnumerableProperty, }); module.exports = { - navigator: new InternalNavigator(), + navigator: ReflectConstruct(function() {}, [], Navigator), Navigator, }; From db570361699d1e66b59e1c271f4a954b83b16788 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Wed, 21 Jun 2023 17:53:17 -0400 Subject: [PATCH 4/7] lib: fix brand validation and failed test --- lib/internal/navigator.js | 6 +++++- test/parallel/test-global.js | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/internal/navigator.js b/lib/internal/navigator.js index 5c179829cb09d4..d7d6ee38122043 100644 --- a/lib/internal/navigator.js +++ b/lib/internal/navigator.js @@ -18,6 +18,9 @@ const { } = internalBinding('os'); class Navigator { + // Private properties are used to avoid brand validations. + #availableParallelism; + constructor() { throw ERR_ILLEGAL_CONSTRUCTOR(); } @@ -26,7 +29,8 @@ class Navigator { * @return {number} */ get hardwareConcurrency() { - return getAvailableParallelism(); + this.#availableParallelism ??= getAvailableParallelism(); + return this.#availableParallelism; } } diff --git a/test/parallel/test-global.js b/test/parallel/test-global.js index 9ac9b4f7287327..0a8fecd240c8a1 100644 --- a/test/parallel/test-global.js +++ b/test/parallel/test-global.js @@ -58,6 +58,7 @@ builtinModules.forEach((moduleName) => { 'structuredClone', 'fetch', 'crypto', + 'navigator', ]; assert.deepStrictEqual(new Set(Object.keys(global)), new Set(expected)); } From 40cf5ffc3967432b06ce787db4278d7e63b408da Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Thu, 22 Jun 2023 15:32:01 -0400 Subject: [PATCH 5/7] lib: update exposed-window-or-worker.js text --- lib/internal/bootstrap/web/exposed-window-or-worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/bootstrap/web/exposed-window-or-worker.js b/lib/internal/bootstrap/web/exposed-window-or-worker.js index e6f6dcb4e72e89..3cc555b82f35a7 100644 --- a/lib/internal/bootstrap/web/exposed-window-or-worker.js +++ b/lib/internal/bootstrap/web/exposed-window-or-worker.js @@ -2,7 +2,7 @@ /** * This file exposes web interfaces that is defined with the WebIDL - * Exposed=(Window,Worker) extended attribute or exposed in + * Exposed=Window + Exposed=(Window,Worker) extended attribute or exposed in * WindowOrWorkerGlobalScope mixin. * See more details at https://webidl.spec.whatwg.org/#Exposed and * https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope. From 3eccea4c6747ac28889fecfb5ad9fad8d553fb00 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Thu, 22 Jun 2023 15:34:34 -0400 Subject: [PATCH 6/7] test: fix faulty test case --- test/parallel/test-bootstrap-modules.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/parallel/test-bootstrap-modules.js b/test/parallel/test-bootstrap-modules.js index 32f90905b642c1..0a671eb95eb6d4 100644 --- a/test/parallel/test-bootstrap-modules.js +++ b/test/parallel/test-bootstrap-modules.js @@ -46,8 +46,6 @@ const expectedModules = new Set([ 'NativeModule async_hooks', 'NativeModule internal/process/task_queues', 'NativeModule timers', - 'Internal Binding os', - 'NativeModule internal/navigator', 'Internal Binding trace_events', 'NativeModule internal/constants', 'NativeModule path', From 1bca99ba68ce9290c999fdee64afa33b88fec521 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Sat, 24 Jun 2023 13:32:30 -0400 Subject: [PATCH 7/7] lib: apply initialize suggestion --- lib/internal/navigator.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/internal/navigator.js b/lib/internal/navigator.js index d7d6ee38122043..3b8343cd7ed6f8 100644 --- a/lib/internal/navigator.js +++ b/lib/internal/navigator.js @@ -2,7 +2,7 @@ const { ObjectDefineProperties, - ReflectConstruct, + Symbol, } = primordials; const { @@ -17,11 +17,16 @@ const { getAvailableParallelism, } = internalBinding('os'); +const kInitialize = Symbol('kInitialize'); + class Navigator { // Private properties are used to avoid brand validations. #availableParallelism; constructor() { + if (arguments[0] === kInitialize) { + return; + } throw ERR_ILLEGAL_CONSTRUCTOR(); } @@ -39,6 +44,6 @@ ObjectDefineProperties(Navigator.prototype, { }); module.exports = { - navigator: ReflectConstruct(function() {}, [], Navigator), + navigator: new Navigator(kInitialize), Navigator, };