From 0bc488c85c4bbc5b900cf5ff7b09227345b87763 Mon Sep 17 00:00:00 2001 From: Nayeem Rahman Date: Mon, 8 Mar 2021 12:27:49 +0000 Subject: [PATCH] fix(runtime/js): add navigator interface objects (#9685) --- cli/dts/lib.deno.window.d.ts | 9 +++- cli/dts/lib.deno.worker.d.ts | 10 +++-- cli/tests/unit/globals_test.ts | 6 +++ cli/tests/workers/test.ts | 2 +- cli/tests/workers/worker_globals.ts | 3 ++ runtime/js/99_main.js | 69 ++++++++++++++++++++++++----- 6 files changed, 83 insertions(+), 16 deletions(-) diff --git a/cli/dts/lib.deno.window.d.ts b/cli/dts/lib.deno.window.d.ts index 2d46e5fe05ed5f..3eebab6775b141 100644 --- a/cli/dts/lib.deno.window.d.ts +++ b/cli/dts/lib.deno.window.d.ts @@ -18,19 +18,24 @@ declare class Window extends EventTarget { confirm: (message?: string) => boolean; prompt: (message?: string, defaultValue?: string) => string | null; Deno: typeof Deno; + Navigator: typeof Navigator; navigator: Navigator; + Location: typeof Location; + location: Location; } declare var window: Window & typeof globalThis; declare var self: Window & typeof globalThis; declare var onload: ((this: Window, ev: Event) => any) | null; declare var onunload: ((this: Window, ev: Event) => any) | null; -declare var navigator: Navigator; -declare interface Navigator { +declare class Navigator { + constructor(); readonly gpu: GPU; } +declare var navigator: Navigator; + /** * Shows the given message and waits for the enter key pressed. * If the stdin is not interactive, it does nothing. diff --git a/cli/dts/lib.deno.worker.d.ts b/cli/dts/lib.deno.worker.d.ts index 93549ecd5cd36f..653a8931beb667 100644 --- a/cli/dts/lib.deno.worker.d.ts +++ b/cli/dts/lib.deno.worker.d.ts @@ -30,15 +30,19 @@ declare class WorkerGlobalScope { close: () => void; postMessage: (message: any) => void; Deno: typeof Deno; + WorkerNavigator: typeof WorkerNavigator; navigator: WorkerNavigator; + WorkerLocation: typeof WorkerLocation; + location: WorkerLocation; } -declare var navigator: WorkerNavigator; - -declare interface WorkerNavigator { +declare class WorkerNavigator { + constructor(); readonly gpu: GPU; } +declare var navigator: WorkerNavigator; + declare class DedicatedWorkerGlobalScope extends WorkerGlobalScope { new(): DedicatedWorkerGlobalScope; name: string; diff --git a/cli/tests/unit/globals_test.ts b/cli/tests/unit/globals_test.ts index dbb9bd90a32f23..ce43fddf197378 100644 --- a/cli/tests/unit/globals_test.ts +++ b/cli/tests/unit/globals_test.ts @@ -48,6 +48,12 @@ unitTest(function globalThisInstanceofEventTarget(): void { assert(globalThis instanceof EventTarget); }); +unitTest(function navigatorInstanceofNavigator(): void { + // TODO(nayeemrmn): Add `Navigator` to deno_lint globals. + // deno-lint-ignore no-undef + assert(navigator instanceof Navigator); +}); + unitTest(function DenoNamespaceExists(): void { assert(Deno != null); }); diff --git a/cli/tests/workers/test.ts b/cli/tests/workers/test.ts index c2dd41aee7f898..e5e9e44f75b4a4 100644 --- a/cli/tests/workers/test.ts +++ b/cli/tests/workers/test.ts @@ -118,7 +118,7 @@ Deno.test({ workerOptions, ); w.onmessage = (e): void => { - assertEquals(e.data, "true, true, true"); + assertEquals(e.data, "true, true, true, true"); promise.resolve(); }; w.postMessage("Hello, world!"); diff --git a/cli/tests/workers/worker_globals.ts b/cli/tests/workers/worker_globals.ts index a9e7efd85c0e8b..f262423069eeae 100644 --- a/cli/tests/workers/worker_globals.ts +++ b/cli/tests/workers/worker_globals.ts @@ -4,6 +4,9 @@ onmessage = function (): void { self instanceof DedicatedWorkerGlobalScope, self instanceof WorkerGlobalScope, self instanceof EventTarget, + // TODO(nayeemrmn): Add `WorkerNavigator` to deno_lint globals. + // deno-lint-ignore no-undef + navigator instanceof WorkerNavigator, ].join(", "), ); close(); diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js index 811412049aa0bc..2c4decd32b99db 100644 --- a/runtime/js/99_main.js +++ b/runtime/js/99_main.js @@ -35,6 +35,7 @@ delete Object.prototype.__proto__; const denoNs = window.__bootstrap.denoNs; const denoNsUnstable = window.__bootstrap.denoNsUnstable; const errors = window.__bootstrap.errors.errors; + const webidl = window.__bootstrap.webidl; const { defineEventHandler } = window.__bootstrap.webUtil; let windowIsClosing = false; @@ -203,6 +204,52 @@ delete Object.prototype.__proto__; ); } + class Navigator { + constructor() { + webidl.illegalConstructor(); + } + + [Symbol.for("Deno.customInspect")](inspect) { + return `${this.constructor.name} ${inspect({})}`; + } + } + + const navigator = webidl.createBranded(Navigator); + + Object.defineProperties(Navigator.prototype, { + gpu: { + configurable: true, + enumerable: true, + get() { + webidl.assertBranded(this, Navigator); + return webgpu.gpu; + }, + }, + }); + + class WorkerNavigator { + constructor() { + webidl.illegalConstructor(); + } + + [Symbol.for("Deno.customInspect")](inspect) { + return `${this.constructor.name} ${inspect({})}`; + } + } + + const workerNavigator = webidl.createBranded(WorkerNavigator); + + Object.defineProperties(WorkerNavigator.prototype, { + gpu: { + configurable: true, + enumerable: true, + get() { + webidl.assertBranded(this, WorkerNavigator); + return webgpu.gpu; + }, + }, + }); + // https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope const windowOrWorkerGlobalScope = { Blob: util.nonEnumerable(file.Blob), @@ -293,17 +340,18 @@ delete Object.prototype.__proto__; // structure, it might be worth it to define a helper in `util` windowOrWorkerGlobalScope.console.enumerable = false; - const windowNavigatorProperties = { - gpu: webgpu.gpu, - }; - const mainRuntimeGlobalProperties = { Location: location.locationConstructorDescriptor, location: location.locationDescriptor, Window: globalInterfaces.windowConstructorDescriptor, window: util.readOnly(globalThis), self: util.readOnly(globalThis), - navigator: util.readOnly(windowNavigatorProperties), + Navigator: util.nonEnumerable(Navigator), + navigator: { + configurable: true, + enumerable: true, + get: () => navigator, + }, // TODO(bartlomieju): from MDN docs (https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope) // it seems those two properties should be available to workers as well onload: util.writable(null), @@ -315,17 +363,18 @@ delete Object.prototype.__proto__; prompt: util.writable(prompt.prompt), }; - const workerNavigatorProperties = { - gpu: webgpu.gpu, - }; - const workerRuntimeGlobalProperties = { WorkerLocation: location.workerLocationConstructorDescriptor, location: location.workerLocationDescriptor, WorkerGlobalScope: globalInterfaces.workerGlobalScopeConstructorDescriptor, DedicatedWorkerGlobalScope: globalInterfaces.dedicatedWorkerGlobalScopeConstructorDescriptor, - navigator: util.readOnly(workerNavigatorProperties), + WorkerNavigator: util.nonEnumerable(WorkerNavigator), + navigator: { + configurable: true, + enumerable: true, + get: () => workerNavigator, + }, self: util.readOnly(globalThis), onmessage: util.writable(onmessage), onerror: util.writable(onerror),