Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v16.x backport] events: add CustomEvent #44082

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ module.exports = {
'node-core/no-duplicate-requires': 'error',
},
globals: {
CustomEvent: 'readable',
Crypto: 'readable',
CryptoKey: 'readable',
fetch: 'readable',
Expand Down
10 changes: 10 additions & 0 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,14 @@ added: v16.15.0

Enable experimental support for the [Fetch API][].

### `--experimental-global-customevent`

<!-- YAML
added: REPLACEME
-->

Expose the [CustomEvent Web API][] on the global scope.

### `--experimental-global-webcrypto`

<!-- YAML
Expand Down Expand Up @@ -1619,6 +1627,7 @@ Node.js options that are allowed are:
* `--enable-source-maps`
* `--experimental-abortcontroller`
* `--experimental-fetch`
* `--experimental-global-customevent`
* `--experimental-global-webcrypto`
* `--experimental-import-meta-resolve`
* `--experimental-json-modules`
Expand Down Expand Up @@ -2041,6 +2050,7 @@ done
[#42511]: https://github.com/nodejs/node/issues/42511
[Chrome DevTools Protocol]: https://chromedevtools.github.io/devtools-protocol/
[CommonJS]: modules.md
[CustomEvent Web API]: https://dom.spec.whatwg.org/#customevent
[ECMAScript module loader]: esm.md#loaders
[Fetch API]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
[Modules loaders]: packages.md#modules-loaders
Expand Down
26 changes: 26 additions & 0 deletions doc/api/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -1978,6 +1978,31 @@ added: v14.5.0

Removes the `listener` from the list of handlers for event `type`.

### Class: `CustomEvent`

<!-- YAML
added: REPLACEME
-->

> Stability: 1 - Experimental.

* Extends: {Event}

The `CustomEvent` object is an adaptation of the [`CustomEvent` Web API][].
Instances are created internally by Node.js.

#### `event.detail`

<!-- YAML
added: REPLACEME
-->

> Stability: 1 - Experimental.

* Type: {any} Returns custom data passed when initializing.

Read-only.

### Class: `NodeEventTarget`

<!-- YAML
Expand Down Expand Up @@ -2115,6 +2140,7 @@ to the `EventTarget`.

[WHATWG-EventTarget]: https://dom.spec.whatwg.org/#interface-eventtarget
[`--trace-warnings`]: cli.md#--trace-warnings
[`CustomEvent` Web API]: https://dom.spec.whatwg.org/#customevent
[`EventTarget` Web API]: https://dom.spec.whatwg.org/#eventtarget
[`EventTarget` error handling]: #eventtarget-error-handling
[`Event` Web API]: https://dom.spec.whatwg.org/#event
Expand Down
15 changes: 15 additions & 0 deletions doc/api/globals.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,19 @@ A browser-compatible implementation of {CryptoKey}. This global is available
only if the Node.js binary was compiled with including support for the
`node:crypto` module.

## `CustomEvent`

<!-- YAML
added: REPLACEME
-->

> Stability: 1 - Experimental. Enable this API with the
> [`--experimental-global-customevent`][] CLI flag.

<!-- type=global -->

A browser-compatible implementation of the [`CustomEvent` Web API][].

## `Event`

<!-- YAML
Expand Down Expand Up @@ -607,8 +620,10 @@ The object that acts as the namespace for all W3C

[Web Crypto API]: webcrypto.md
[`--experimental-fetch`]: cli.md#--experimental-fetch
[`--experimental-global-customevent`]: cli.md#--experimental-global-customevent
[`--experimental-global-webcrypto`]: cli.md#--experimental-global-webcrypto
[`AbortController`]: https://developer.mozilla.org/en-US/docs/Web/API/AbortController
[`CustomEvent` Web API]: https://dom.spec.whatwg.org/#customevent
[`EventTarget` and `Event` API]: events.md#eventtarget-and-event-api
[`MessageChannel`]: worker_threads.md#class-messagechannel
[`MessageEvent`]: https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/MessageEvent
Expand Down
3 changes: 3 additions & 0 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ Enable Source Map V3 support for stack traces.
.It Fl -experimental-fetch
Enable experimental support for the Fetch API.
.
.It Fl -experimental-global-customevent
Expose the CustomEvent on the global scope.
.
.It Fl -experimental-global-webcrypto
Expose the Web Crypto API on the global scope.
.
Expand Down
2 changes: 2 additions & 0 deletions lib/.eslintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ rules:
message: Use `const { BroadcastChannel } = require('internal/worker/io');` instead of the global.
- name: Buffer
message: Use `const { Buffer } = require('buffer');` instead of the global.
- name: CustomEvent
message: Use `const { CustomEvent } = require('internal/event_target');` instead of the global.
- name: Event
message: Use `const { Event } = require('internal/event_target');` instead of the global.
- name: EventTarget
Expand Down
13 changes: 13 additions & 0 deletions lib/internal/bootstrap/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ function prepareMainThreadExecution(expandArgv1 = false,
setupWarningHandler();
setupFetch();
setupWebCrypto();
setupCustomEvent();

// Resolve the coverage directory to an absolute path, and
// overwrite process.env so that the original path gets passed
Expand Down Expand Up @@ -229,6 +230,17 @@ function setupWebCrypto() {
}
}

// TODO(daeyeon): move this to internal/bootstrap/browser when the CLI flag is
// removed.
function setupCustomEvent() {
if (process.config.variables.node_no_browser_globals ||
!getOptionValue('--experimental-global-customevent')) {
return;
}
const { CustomEvent } = require('internal/event_target');
exposeInterface(globalThis, 'CustomEvent', CustomEvent);
}

// Setup User-facing NODE_V8_COVERAGE environment variable that writes
// ScriptCoverage to a specified file.
function setupCoverageHooks(dir) {
Expand Down Expand Up @@ -576,6 +588,7 @@ module.exports = {
setupWarningHandler,
setupFetch,
setupWebCrypto,
setupCustomEvent,
setupDebugEnv,
setupPerfHooks,
prepareMainThreadExecution,
Expand Down
45 changes: 45 additions & 0 deletions lib/internal/event_target.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ const kTimestamp = Symbol('timestamp');
const kBubbles = Symbol('bubbles');
const kComposed = Symbol('composed');
const kPropagationStopped = Symbol('propagationStopped');
const kDetail = Symbol('detail');

const isTrustedSet = new SafeWeakSet();
const isTrusted = ObjectGetOwnPropertyDescriptor({
Expand Down Expand Up @@ -327,6 +328,49 @@ ObjectDefineProperties(
stopPropagation: kEnumerableProperty,
});

function isCustomEvent(value) {
return isEvent(value) && (value?.[kDetail] !== undefined);
}

class CustomEvent extends Event {
/**
* @constructor
* @param {string} type
* @param {{
* bubbles?: boolean,
* cancelable?: boolean,
* composed?: boolean,
* detail?: any,
* }} [options]
*/
constructor(type, options = kEmptyObject) {
if (arguments.length === 0)
throw new ERR_MISSING_ARGS('type');
super(type, options);
this[kDetail] = options?.detail ?? null;
}

/**
* @type {any}
*/
get detail() {
if (!isCustomEvent(this))
throw new ERR_INVALID_THIS('CustomEvent');
return this[kDetail];
}
}

ObjectDefineProperties(CustomEvent.prototype, {
[SymbolToStringTag]: {
__proto__: null,
writable: false,
enumerable: false,
configurable: true,
value: 'CustomEvent',
},
detail: kEnumerableProperty,
});

class NodeCustomEvent extends Event {
constructor(type, options) {
super(type, options);
Expand Down Expand Up @@ -989,6 +1033,7 @@ const EventEmitterMixin = (Superclass) => {

module.exports = {
Event,
CustomEvent,
EventEmitterMixin,
EventTarget,
NodeEventTarget,
Expand Down
2 changes: 2 additions & 0 deletions lib/internal/main/worker_thread.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const {
setupWarningHandler,
setupFetch,
setupWebCrypto,
setupCustomEvent,
setupDebugEnv,
setupPerfHooks,
initializeDeprecations,
Expand Down Expand Up @@ -71,6 +72,7 @@ setupDebugEnv();
setupWarningHandler();
setupFetch();
setupWebCrypto();
setupCustomEvent();
initializeSourceMapsHandlers();

// Since worker threads cannot switch cwd, we do not need to
Expand Down
4 changes: 4 additions & 0 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
&EnvironmentOptions::experimental_fetch,
kAllowedInEnvironment);
AddOption("--experimental-json-modules", "", NoOp{}, kAllowedInEnvironment);
AddOption("--experimental-global-customevent",
"expose experimental CustomEvent on the global scope",
&EnvironmentOptions::experimental_global_customevent,
kAllowedInEnvironment);
AddOption("--experimental-global-webcrypto",
"expose experimental Web Crypto API on the global scope",
&EnvironmentOptions::experimental_global_web_crypto,
Expand Down
1 change: 1 addition & 0 deletions src/node_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ class EnvironmentOptions : public Options {
bool enable_source_maps = false;
bool experimental_https_modules = false;
bool experimental_fetch = false;
bool experimental_global_customevent = false;
bool experimental_global_web_crypto = false;
std::string experimental_specifier_resolution;
bool experimental_wasm_modules = false;
Expand Down
3 changes: 3 additions & 0 deletions test/common/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,9 @@ if (hasCrypto && global.crypto) {
knownGlobals.push(global.CryptoKey);
knownGlobals.push(global.SubtleCrypto);
}
if (global.CustomEvent) {
knownGlobals.push(global.CustomEvent);
}

function allowGlobals(...allowlist) {
knownGlobals = knownGlobals.concat(allowlist);
Expand Down
Loading