Skip to content

Commit

Permalink
Implement Observable class and subscribe method.
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=276572

Reviewed by NOBODY (OOPS!).

This implements the base `Observable` class, as well as the `subscribe`
method. In addition this adds the `Subscriber` internal class allows
Observables to be subscribed to, and some additional machinery such as
`SubscribeOptions`, `SubscriptionObserver` and so on.

This also includes a fix to IDL generation to correctly generate callback
function + dictionary unions (whatwg/webidl#1353).

This does not implement any of the prototype methods on Observable,
(other than subscribe) such as `takeUntil`, `filter`, `finally` and so
on.

* LayoutTests/imported/w3c/web-platform-tests/dom/observable/tentative/observable-constructor.any-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/dom/observable/tentative/observable-constructor.any.worker-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/dom/observable/tentative/observable-constructor.window-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/dom/observable/tentative/observable-takeUntil.any-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/dom/observable/tentative/observable-takeUntil.any.worker-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/dom/observable/tentative/observable-takeUntil.window-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/dom/observable/tentative/observable-toArray.any-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/dom/observable/tentative/observable-toArray.any.worker-expected.txt:
* Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml:
* Source/WebCore/CMakeLists.txt:
* Source/WebCore/DerivedSources-input.xcfilelist:
* Source/WebCore/DerivedSources-output.xcfilelist:
* Source/WebCore/DerivedSources.make:
* Source/WebCore/Sources.txt:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/bindings/IDLTypes.h:
* Source/WebCore/bindings/js/JSDOMConvertUnion.h:
* Source/WebCore/bindings/js/JSSubscriberCustom.cpp: Added.
(WebCore::JSSubscriber::visitAdditionalChildren):
* Source/WebCore/bindings/js/WebCoreBuiltinNames.h:
* Source/WebCore/bindings/scripts/CodeGeneratorJS.pm:
(AreTypesDistinguishableForOverloadResolution):
* Source/WebCore/bindings/scripts/test/JS/JSTestCallbackWithFunctionOrDict.cpp: Added.
(WebCore::JSTestCallbackWithFunctionOrDict::JSTestCallbackWithFunctionOrDict):
(WebCore::JSTestCallbackWithFunctionOrDict::~JSTestCallbackWithFunctionOrDict):
(WebCore::JSTestCallbackWithFunctionOrDict::handleEvent):
(WebCore::JSTestCallbackWithFunctionOrDict::visitJSFunction):
(WebCore::toJS):
* Source/WebCore/bindings/scripts/test/JS/JSTestCallbackWithFunctionOrDict.h: Added.
(WebCore::toJS):
* Source/WebCore/bindings/scripts/test/SupplementalDependencies.dep:
* Source/WebCore/bindings/scripts/test/TestCallbackOrDict.idl: Added.
* Source/WebCore/dom/Observable.cpp: Added.
(WebCore::Observable::create):
(WebCore::Observable::subscribe):
(WebCore::Observable::makeSubscriber):
(WebCore::Observable::Observable):
* Source/WebCore/dom/Observable.h: Added.
* Source/WebCore/dom/Observable.idl: Added.
* Source/WebCore/dom/SubscribeOptions.h: Added.
* Source/WebCore/dom/SubscribeOptions.idl: Added.
* Source/WebCore/dom/Subscriber.cpp: Added.
(WebCore::Subscriber::create):
(WebCore::Subscriber::Subscriber):
(WebCore::Subscriber::next):
(WebCore::Subscriber::error):
(WebCore::Subscriber::complete):
(WebCore::Subscriber::addTeardown):
(WebCore::Subscriber::followSignal):
(WebCore::Subscriber::close):
(WebCore::Subscriber::isInactiveDocument const):
* Source/WebCore/dom/Subscriber.h: Added.
* Source/WebCore/dom/Subscriber.idl: Added.
* Source/WebCore/dom/SubscriberCallback.h: Added.
* Source/WebCore/dom/SubscriberCallback.idl: Added.
* Source/WebCore/dom/SubscriptionObserver.h: Added.
* Source/WebCore/dom/SubscriptionObserver.idl: Added.
* Source/WebCore/dom/SubscriptionObserverCallback.h: Added.
* Source/WebCore/dom/SubscriptionObserverCallback.idl: Added.
  • Loading branch information
keithamus committed Jul 15, 2024
1 parent 5e9fe48 commit 0ca1b04
Show file tree
Hide file tree
Showing 38 changed files with 1,239 additions and 119 deletions.
Original file line number Diff line number Diff line change
@@ -1,38 +1,50 @@
CONSOLE MESSAGE: Error: custom error
CONSOLE MESSAGE: Error: custom error
CONSOLE MESSAGE: Error: custom error
CONSOLE MESSAGE: Error: custom error
CONSOLE MESSAGE: Error: error 2
CONSOLE MESSAGE: Error: error 2
CONSOLE MESSAGE: not a real error
CONSOLE MESSAGE: not a real error
CONSOLE MESSAGE: not a real error
CONSOLE MESSAGE: Error: assert_false: expected false got true
CONSOLE MESSAGE: Error: custom error
CONSOLE MESSAGE: Error: custom error

FAIL Observable constructor assert_implements: The Observable interface is not implemented undefined
FAIL subscribe() can be called with no arguments Can't find variable: Observable
FAIL Subscriber interface is not constructible assert_implements: The Subscriber interface is not implemented undefined
FAIL Subscribe with just a function as the next handler Can't find variable: Observable
FAIL Observable constructor calls initializer on subscribe Can't find variable: Observable
FAIL Observable error path called synchronously Can't find variable: Observable
FAIL Subscriber must have receiver Can't find variable: Observable
FAIL Subscriber next & error must recieve argument Can't find variable: Observable
FAIL Subscriber complete() will set active to false, and abort signal Can't find variable: Observable
FAIL Subscriber active is readonly Can't find variable: Observable
FAIL Subscriber signal is readonly Can't find variable: Observable
FAIL Observable should error if initializer throws Can't find variable: Observable
FAIL Subscription is inactive after complete() Can't find variable: Observable
FAIL Subscription is inactive after error() Can't find variable: Observable
FAIL Subscription is inactive when aborted signal is passed in Can't find variable: Observable
FAIL Subscriber#signal is not the same AbortSignal as the one passed into `subscribe()` Can't find variable: Observable
FAIL Subscription does not emit values after completion Can't find variable: Observable
FAIL Subscription does not emit values after error Can't find variable: Observable
FAIL Completing or nexting a subscriber after an error does nothing Can't find variable: Observable
FAIL Errors pushed to the subscriber that are not handled by the subscription are reported to the global Can't find variable: Observable
FAIL Errors thrown in the initializer that are not handled by the subscription are reported to the global Can't find variable: Observable
FAIL Subscription reports errors that are pushed after subscriber is closed by completion Can't find variable: Observable
FAIL Errors thrown by initializer function after subscriber is closed by completion are reported Can't find variable: Observable
FAIL Errors thrown by initializer function after subscriber is closed by error are reported Can't find variable: Observable
FAIL Errors pushed by initializer function after subscriber is closed by error are reported Can't find variable: Observable
FAIL Subscriber#complete() cannot re-entrantly invoke itself Can't find variable: Observable
FAIL Subscriber#error() cannot re-entrantly invoke itself Can't find variable: Observable
FAIL Unsubscription lifecycle Can't find variable: Observable
FAIL Aborting a subscription should stop emitting values Can't find variable: Observable
FAIL Calling subscribe should never throw an error synchronously, initializer throws error Can't find variable: Observable
FAIL Calling subscribe should never throw an error synchronously, subscriber pushes error Can't find variable: Observable
FAIL Teardown should be called when subscription is aborted Can't find variable: Observable
FAIL Teardowns should be called when subscription is closed by completion Can't find variable: Observable
FAIL Teardowns should be called when subscription is closed by subscriber pushing an error Can't find variable: Observable
FAIL Teardowns should be called when subscription is closed by subscriber throwing error Can't find variable: Observable
FAIL Teardowns should be called synchronously during addTeardown() if the subscription is inactive Can't find variable: Observable
PASS Observable constructor
PASS subscribe() can be called with no arguments
PASS Subscriber interface is not constructible
PASS Subscribe with just a function as the next handler
PASS Observable constructor calls initializer on subscribe
PASS Observable error path called synchronously
PASS Subscriber must have receiver
PASS Subscriber next & error must recieve argument
PASS Subscriber complete() will set active to false, and abort signal
PASS Subscriber active is readonly
PASS Subscriber signal is readonly
PASS Observable should error if initializer throws
PASS Subscription is inactive after complete()
PASS Subscription is inactive after error()
PASS Subscription is inactive when aborted signal is passed in
PASS Subscriber#signal is not the same AbortSignal as the one passed into `subscribe()`
PASS Subscription does not emit values after completion
PASS Subscription does not emit values after error
PASS Completing or nexting a subscriber after an error does nothing
FAIL Errors pushed to the subscriber that are not handled by the subscription are reported to the global assert_equals: Error message matches expected "Uncaught Error: custom error" but got "Error: custom error"
FAIL Errors thrown in the initializer that are not handled by the subscription are reported to the global assert_equals: Error message matches expected "Uncaught Error: custom error" but got "Error: custom error"
FAIL Subscription reports errors that are pushed after subscriber is closed by completion assert_equals: Error message matches expected "Uncaught Error: custom error" but got "Error: custom error"
PASS Errors thrown by initializer function after subscriber is closed by completion are reported
PASS Errors thrown by initializer function after subscriber is closed by error are reported
PASS Errors pushed by initializer function after subscriber is closed by error are reported
PASS Subscriber#complete() cannot re-entrantly invoke itself
PASS Subscriber#error() cannot re-entrantly invoke itself
FAIL Unsubscription lifecycle assert_array_equals: expected property 1 to be "outer abort handler" but got "inner abort handler" (expected array ["subscribe() callback", "outer abort handler", "teardown 2", "teardown 1", "inner abort handler", "abort() returned"] got ["subscribe() callback", "inner abort handler", "teardown 2", "teardown 1", "outer abort handler", "abort() returned"])
PASS Aborting a subscription should stop emitting values
PASS Calling subscribe should never throw an error synchronously, initializer throws error
PASS Calling subscribe should never throw an error synchronously, subscriber pushes error
PASS Teardown should be called when subscription is aborted
PASS Teardowns should be called when subscription is closed by completion
PASS Teardowns should be called when subscription is closed by subscriber pushing an error
PASS Teardowns should be called when subscription is closed by subscriber throwing error
PASS Teardowns should be called synchronously during addTeardown() if the subscription is inactive

Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@

FAIL Observable constructor assert_implements: The Observable interface is not implemented undefined
FAIL subscribe() can be called with no arguments Can't find variable: Observable
FAIL Subscriber interface is not constructible assert_implements: The Subscriber interface is not implemented undefined
FAIL Subscribe with just a function as the next handler Can't find variable: Observable
FAIL Observable constructor calls initializer on subscribe Can't find variable: Observable
FAIL Observable error path called synchronously Can't find variable: Observable
FAIL Subscriber must have receiver Can't find variable: Observable
FAIL Subscriber next & error must recieve argument Can't find variable: Observable
FAIL Subscriber complete() will set active to false, and abort signal Can't find variable: Observable
FAIL Subscriber active is readonly Can't find variable: Observable
FAIL Subscriber signal is readonly Can't find variable: Observable
FAIL Observable should error if initializer throws Can't find variable: Observable
FAIL Subscription is inactive after complete() Can't find variable: Observable
FAIL Subscription is inactive after error() Can't find variable: Observable
FAIL Subscription is inactive when aborted signal is passed in Can't find variable: Observable
FAIL Subscriber#signal is not the same AbortSignal as the one passed into `subscribe()` Can't find variable: Observable
FAIL Subscription does not emit values after completion Can't find variable: Observable
FAIL Subscription does not emit values after error Can't find variable: Observable
FAIL Completing or nexting a subscriber after an error does nothing Can't find variable: Observable
FAIL Errors pushed to the subscriber that are not handled by the subscription are reported to the global Can't find variable: Observable
FAIL Errors thrown in the initializer that are not handled by the subscription are reported to the global Can't find variable: Observable
FAIL Subscription reports errors that are pushed after subscriber is closed by completion Can't find variable: Observable
FAIL Errors thrown by initializer function after subscriber is closed by completion are reported Can't find variable: Observable
FAIL Errors thrown by initializer function after subscriber is closed by error are reported Can't find variable: Observable
FAIL Errors pushed by initializer function after subscriber is closed by error are reported Can't find variable: Observable
FAIL Subscriber#complete() cannot re-entrantly invoke itself Can't find variable: Observable
FAIL Subscriber#error() cannot re-entrantly invoke itself Can't find variable: Observable
FAIL Unsubscription lifecycle Can't find variable: Observable
FAIL Aborting a subscription should stop emitting values Can't find variable: Observable
FAIL Calling subscribe should never throw an error synchronously, initializer throws error Can't find variable: Observable
FAIL Calling subscribe should never throw an error synchronously, subscriber pushes error Can't find variable: Observable
FAIL Teardown should be called when subscription is aborted Can't find variable: Observable
FAIL Teardowns should be called when subscription is closed by completion Can't find variable: Observable
FAIL Teardowns should be called when subscription is closed by subscriber pushing an error Can't find variable: Observable
FAIL Teardowns should be called when subscription is closed by subscriber throwing error Can't find variable: Observable
FAIL Teardowns should be called synchronously during addTeardown() if the subscription is inactive Can't find variable: Observable
PASS Observable constructor
PASS subscribe() can be called with no arguments
PASS Subscriber interface is not constructible
PASS Subscribe with just a function as the next handler
PASS Observable constructor calls initializer on subscribe
PASS Observable error path called synchronously
PASS Subscriber must have receiver
PASS Subscriber next & error must recieve argument
PASS Subscriber complete() will set active to false, and abort signal
PASS Subscriber active is readonly
PASS Subscriber signal is readonly
PASS Observable should error if initializer throws
PASS Subscription is inactive after complete()
PASS Subscription is inactive after error()
PASS Subscription is inactive when aborted signal is passed in
PASS Subscriber#signal is not the same AbortSignal as the one passed into `subscribe()`
PASS Subscription does not emit values after completion
PASS Subscription does not emit values after error
PASS Completing or nexting a subscriber after an error does nothing
FAIL Errors pushed to the subscriber that are not handled by the subscription are reported to the global assert_equals: Error message matches expected "Uncaught Error: custom error" but got "Error: custom error"
FAIL Errors thrown in the initializer that are not handled by the subscription are reported to the global assert_equals: Error message matches expected "Uncaught Error: custom error" but got "Error: custom error"
FAIL Subscription reports errors that are pushed after subscriber is closed by completion assert_equals: Error message matches expected "Uncaught Error: custom error" but got "Error: custom error"
PASS Errors thrown by initializer function after subscriber is closed by completion are reported
PASS Errors thrown by initializer function after subscriber is closed by error are reported
PASS Errors pushed by initializer function after subscriber is closed by error are reported
PASS Subscriber#complete() cannot re-entrantly invoke itself
PASS Subscriber#error() cannot re-entrantly invoke itself
FAIL Unsubscription lifecycle assert_array_equals: expected property 1 to be "outer abort handler" but got "inner abort handler" (expected array ["subscribe() callback", "outer abort handler", "teardown 2", "teardown 1", "inner abort handler", "abort() returned"] got ["subscribe() callback", "inner abort handler", "teardown 2", "teardown 1", "outer abort handler", "abort() returned"])
PASS Aborting a subscription should stop emitting values
PASS Calling subscribe should never throw an error synchronously, initializer throws error
PASS Calling subscribe should never throw an error synchronously, subscriber pushes error
PASS Teardown should be called when subscription is aborted
PASS Teardowns should be called when subscription is closed by completion
PASS Teardowns should be called when subscription is closed by subscriber pushing an error
PASS Teardowns should be called when subscription is closed by subscriber throwing error
PASS Teardowns should be called synchronously during addTeardown() if the subscription is inactive

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

FAIL No observer handlers can be invoked in detached document promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: Observable"
FAIL Subscriber.error() does not "report the exception" even when an `error()` handler is not present, when it is invoked in a detached document promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: Observable"
FAIL Cannot subscribe to an Observable in a detached document promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: Observable"
PASS No observer handlers can be invoked in detached document
PASS Subscriber.error() does not "report the exception" even when an `error()` handler is not present, when it is invoked in a detached document
PASS Cannot subscribe to an Observable in a detached document
FAIL Observable from EventTarget does not get notified for events in detached documents promise_test: Unhandled rejection with value: object "TypeError: event_target.on is not a function. (In 'event_target.on('customevent')', 'event_target.on' is undefined)"

Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@

FAIL takeUntil subscribes to source Observable and mirrors it uninterrupted promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: Observable"
FAIL takeUntil subscribes to notifier promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: Observable"
FAIL takeUntil: notifier next() unsubscribes to notifier promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: Observable"
FAIL takeUntil: notifier error() unsubscribes to notifier promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: Observable"
FAIL takeUntil: notifier next() unsubscribes from notifier & source observable promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: Observable"
FAIL takeUntil()'s AbortSignal unsubscribes from notifier & source observable promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: Observable"
FAIL takeUntil: source never subscribed to when notifier synchronously emits a value promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: Observable"
FAIL takeUntil: source never subscribed to when notifier synchronously emits error promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: Observable"
FAIL takeUntil: source is uninterrupted when notifier completes, even synchronously promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: Observable"
FAIL takeUntil() mirrors the source Observable until its first next() value promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: Observable"
FAIL takeUntil: notifier calls `Subscriber#error()` twice; second goes to global error handler promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: Observable"
FAIL takeUntil subscribes to source Observable and mirrors it uninterrupted promise_test: Unhandled rejection with value: object "TypeError: source.takeUntil is not a function. (In 'source.takeUntil(new Observable(() => {}))', 'source.takeUntil' is undefined)"
FAIL takeUntil subscribes to notifier promise_test: Unhandled rejection with value: object "TypeError: source.takeUntil is not a function. (In 'source.takeUntil(notifier)', 'source.takeUntil' is undefined)"
FAIL takeUntil: notifier next() unsubscribes to notifier promise_test: Unhandled rejection with value: object "TypeError: source.takeUntil is not a function. (In 'source.takeUntil(notifier)', 'source.takeUntil' is undefined)"
FAIL takeUntil: notifier error() unsubscribes to notifier promise_test: Unhandled rejection with value: object "TypeError: source.takeUntil is not a function. (In 'source.takeUntil(notifier)', 'source.takeUntil' is undefined)"
FAIL takeUntil: notifier next() unsubscribes from notifier & source observable promise_test: Unhandled rejection with value: object "TypeError: source.takeUntil is not a function. (In 'source.takeUntil(notifier)', 'source.takeUntil' is undefined)"
FAIL takeUntil()'s AbortSignal unsubscribes from notifier & source observable promise_test: Unhandled rejection with value: object "TypeError: source.takeUntil is not a function. (In 'source.takeUntil(notifier)', 'source.takeUntil' is undefined)"
FAIL takeUntil: source never subscribed to when notifier synchronously emits a value promise_test: Unhandled rejection with value: object "TypeError: source.takeUntil is not a function. (In 'source.takeUntil(notifier)', 'source.takeUntil' is undefined)"
FAIL takeUntil: source never subscribed to when notifier synchronously emits error promise_test: Unhandled rejection with value: object "TypeError: source.takeUntil is not a function. (In 'source.takeUntil(notifier)', 'source.takeUntil' is undefined)"
FAIL takeUntil: source is uninterrupted when notifier completes, even synchronously promise_test: Unhandled rejection with value: object "TypeError: source.takeUntil is not a function. (In 'source.takeUntil(notifier)', 'source.takeUntil' is undefined)"
FAIL takeUntil() mirrors the source Observable until its first next() value promise_test: Unhandled rejection with value: object "TypeError: source.takeUntil is not a function. (In 'source.takeUntil(notifier)', 'source.takeUntil' is undefined)"
FAIL takeUntil: notifier calls `Subscriber#error()` twice; second goes to global error handler promise_test: Unhandled rejection with value: object "TypeError: source.takeUntil is not a function. (In 'source.takeUntil(notifier)', 'source.takeUntil' is undefined)"

Loading

0 comments on commit 0ca1b04

Please sign in to comment.