Constructor and prototype reform tracking
Constructor and prototype reform has landed in https://github.com/jsdom/jsdom/commit/5e39a4c60377c95ac09ea938ecbf5f1f91cb0360, but not yet been released. This issue is meant as a meta tracking issue for remaining potential work items.
Currently I do not think any of these should block the next release, and am considering doing the release some time in the next few days. So please speak up if you disagree! I am worried a bit about how fixing these issues could be considered a breaking change, in which case we may want to bundle it with the existing constructor and prototype reform breaking change that has already landed.
Classes from external packages are not yet migrated
Namely, DOMException, URL, URLSearchParams, and XMLSerializer.
@pmdartus is working on this, and it shouldn't be too hard, except he ran into the following issue while doing so...
ECMAScript spec globals are handled inconsistently
Discussed in https://github.com/jsdom/domexception/pull/3#discussion_r349866219.
Currently, if runScripts is set to either "outside-only" or "dangerously", the Node.js vm machinery will install all the ECMAScript globals onto the JSDOM Window. I.e., dom.window.TypeError, dom.window.Map, etc. will exist, and will be fresh copies: dom.window.TypeError !== global.TypeError. If runScripts is left as its default undefined, then these will not exist.
The exception is the typed arrays, which we alias from the Node.js outer environment. We do this regardless of the runScripts value. Presumably this was to cause us to pass more tests in some way, but as noted in the comment, it's an inconsistent hack. I'd like to stop doing this, one way or another.
I see a few options here:
Remove support for disabling scripting, i.e. make the new default equivalent to
"outside-only". And, remove the typed array special-casing. Now, fresh copies of all ECMAScript globals will be installed, just like fresh copies of web globals are now installed. This is nice for consistency, but may hurt performance in the simple case where people don't need to run scripts.Remove the aliasing of typed arrays entirely. Now, there will be no ECMAScript globals if scripting is disabled, which is at least somewhat more consistent. Presumably in this case any JSDOM code that wants to use the globals will use copies from the outer Node.js environment, at least when scripting is disabled. (E.g.,
dom.window.DOMExceptionwould inherit fromglobal.Error, not fromdom.window.Error, since the latter does not exist.)Alias all the ECMAScript globals when scripting is disabled (and remove the typed array aliasing for when scripting is enabled). Now at least there's a full set of globals at all times, although when scripting is disabled, it will be inconsistent where they come from between ES globals (aliases of the outer Node.js ones) and web ones (fresh).
Any of these options seem reasonable to me; thoughts appreciated.
Errors and other globals from the outer Node.js environment are still used
Exception-realm handling is tracked separately in #4326, including implementation-wide design options. The discussion below also covers other globals, such as arrays and promises.
For example, webidl2js-generated TypeErrors, or manually-thrown ones inside impl classes, are thrown using global.TypeError, not dom.window.TypeError.
This also holds for other globals that we expose outward to the world. The notable ones I can think of are return values that are arrays or promises.
This is even more complicated because the exact realm in which these globals is created is not always the same. Specs need to explicitly state which of (at least) two choices they are using: the relevant realm, i.e. the global of this, or the current realm, i.e. the global of the currently running function. These would differ in cases like dom1.window.SomeInterface.prototype.someOperation.call(new dom2.window.SomeInterface()): there the relevant realm is that of dom2 and the current realm is that of dom1.
Generally speaking, thrown errors always use the current realm, and promises created by the automatic Web IDL machinery will use the current realm, but most other cases will use the relevant realm.
One solution here is to update all of our code (including generated code) to use the relevant realm, e.g. changing new TypeError() to new this._globalObject.TypeError(). But since relevant is not current, that isn't really correct in cross-realm cases. The only way to get correct current-realm behavior, I believe, is discussed in the next section.
Functions are not instanceof dom.window.Function
That is, dom.window.Blob instanceof dom.window.Function is false. Instead, dom.window.Blob instanceof global.Function is true. This causes at least one web platform test to fail.
Although you could imagine "reparenting" every function created with webidl2js via Object.setPrototypeOf, that seems pretty annoying.
An alternate route would be to consider mashing all of the generated wrapper files into a vm.Script and running them inside the VM, so that the classes in question are actually created inside the VM realm, instead of created outside and then attached to the VM instance. This gets pretty scary. For example: do we need to drag along the impl files to? Or maybe we consider smuggling them in through a different channel, e.g. global properties which are grabbed during startup and then deleted afterward? How does this interact with people who want to debug jsdom code---probably debugging a giant vm.Script is less good than debugging Node.js modules? Etc. This would also solve the previous problem though, as automatically all textual instances of new TypeError() would be interpreted as being done in the correct "current realm".
Source: jsdom/jsdom