From ff7a6ade8cba220d5b67c5269de5cd5e11466a9c Mon Sep 17 00:00:00 2001 From: Alistair Smith Date: Tue, 22 Apr 2025 17:32:02 -0700 Subject: [PATCH] implement test-worker-type-check --- src/js/node/worker_threads.ts | 17 +++++++---- .../test/parallel/test-worker-type-check.js | 29 +++++++++++++++++++ 2 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 test/js/node/test/parallel/test-worker-type-check.js diff --git a/src/js/node/worker_threads.ts b/src/js/node/worker_threads.ts index 59cb63c6773eac..75c34482a905b7 100644 --- a/src/js/node/worker_threads.ts +++ b/src/js/node/worker_threads.ts @@ -13,8 +13,6 @@ const SHARE_ENV = Symbol("nodejs.worker_threads.SHARE_ENV"); const isMainThread = Bun.isMainThread; const { 0: _workerData, 1: _threadId, 2: _receiveMessageOnPort } = $cpp("Worker.cpp", "createNodeWorkerThreadsBinding"); -type NodeWorkerOptions = import("node:worker_threads").WorkerOptions; - // Used to ensure that Blobs created to hold the source code for `eval: true` Workers get cleaned up // after their Worker exits let urlRevokeRegistry: FinalizationRegistry | undefined = undefined; @@ -212,29 +210,36 @@ class Worker extends EventEmitter { #urlToRevoke = ""; #isRunning = false; - constructor(filename: string, options: NodeWorkerOptions = {}) { + constructor(filename: string | URL, options: import("node:worker_threads").WorkerOptions = {}) { super(); + + if (typeof filename !== "string" && !(filename instanceof URL)) { + throw $ERR_INVALID_ARG_TYPE("filename", ["string", "an instance of URL"], filename); + } + for (const key of unsupportedOptions) { if (key in options && options[key] != null) { warnNotImplementedOnce(`worker_threads.Worker option "${key}"`); } } + const filenameAsString = filename instanceof URL ? filename.toString() : filename; + const builtinsGeneratorHatesEval = "ev" + "a" + "l"[0]; if (options && builtinsGeneratorHatesEval in options) { if (options[builtinsGeneratorHatesEval]) { // TODO: consider doing this step in native code and letting the Blob be cleaned up by the // C++ Worker object's destructor - const blob = new Blob([filename], { type: "" }); + const blob = new Blob([filenameAsString], { type: "" }); this.#urlToRevoke = filename = URL.createObjectURL(blob); } else { // if options.eval = false, allow the constructor below to fail, if // we convert the code to a blob, it will succeed. - this.#urlToRevoke = filename; + this.#urlToRevoke = filenameAsString; } } try { - this.#worker = new WebWorker(filename, options); + this.#worker = new WebWorker(filenameAsString, options); } catch (e) { if (this.#urlToRevoke) { URL.revokeObjectURL(this.#urlToRevoke); diff --git a/test/js/node/test/parallel/test-worker-type-check.js b/test/js/node/test/parallel/test-worker-type-check.js new file mode 100644 index 00000000000000..f20e3899cebcf4 --- /dev/null +++ b/test/js/node/test/parallel/test-worker-type-check.js @@ -0,0 +1,29 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const { Worker } = require('worker_threads'); + +{ + [ + undefined, + null, + false, + 0, + Symbol('test'), + {}, + [], + () => {}, + ].forEach((val) => { + assert.throws( + () => new Worker(val), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "filename" argument must be of type string ' + + 'or an instance of URL.' + + common.invalidArgTypeHelper(val) + } + ); + }); +} \ No newline at end of file