Migrate from deprecated `dart:js`, `dart:js_util`, `package:js_util` to `dart:js_interop` (#2478)
Closes #2447.
diff --git a/pkgs/test/lib/src/runner/browser/compilers/dart2js.dart b/pkgs/test/lib/src/runner/browser/compilers/dart2js.dart
index 3cd6745..9ef1f4e 100644
--- a/pkgs/test/lib/src/runner/browser/compilers/dart2js.dart
+++ b/pkgs/test/lib/src/runner/browser/compilers/dart2js.dart
@@ -112,13 +112,14 @@
var jsPath = p.join(dir, '${p.basename(dartPath)}.browser_test.dart.js');
var bootstrapContent = '''
${suiteConfig.metadata.languageVersionComment ?? await rootPackageLanguageVersionComment}
+ import 'dart:js_interop';
import 'package:test/src/bootstrap/browser.dart';
import 'package:test/src/runner/browser/dom.dart' as dom;
import '${await absoluteUri(dartPath)}' as test;
void main() {
- dom.window.console.log(r'Startup for test path $dartPath');
+ dom.window.console.log(r'Startup for test path $dartPath'.toJS);
internalBootstrapBrowserTest(() => test.main);
}
''';
diff --git a/pkgs/test/lib/src/runner/browser/dom.dart b/pkgs/test/lib/src/runner/browser/dom.dart
index a3a2d96..fe6a658 100644
--- a/pkgs/test/lib/src/runner/browser/dom.dart
+++ b/pkgs/test/lib/src/runner/browser/dom.dart
@@ -2,64 +2,51 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// ignore: deprecated_member_use
-import 'dart:js_util' as js_util;
+import 'dart:js_interop';
+import 'dart:js_interop_unsafe';
-// ignore: deprecated_member_use
-import 'package:js/js.dart';
-
-@JS()
-@staticInterop
-class Window extends EventTarget {}
-
-extension WindowExtension on Window {
+extension type Window(EventTarget _) implements EventTarget {
@pragma('dart2js:as:trust')
- Window get parent => js_util.getProperty<dynamic>(this, 'parent') as Window;
+ Window get parent => getProperty('parent'.toJS) as Window;
+
external Location get location;
- Console get console => js_util.getProperty(this, 'console') as Console;
+
+ Console get console => getProperty('console'.toJS) as Console;
+
CSSStyleDeclaration? getComputedStyle(Element elt, [String? pseudoElt]) =>
- js_util.callMethod(this, 'getComputedStyle', <Object>[
+ callMethodVarArgs('getComputedStyle'.toJS, <JSAny?>[
elt,
- if (pseudoElt != null) pseudoElt
+ if (pseudoElt != null) pseudoElt.toJS
]) as CSSStyleDeclaration?;
+
external Navigator get navigator;
+
void postMessage(Object message, String targetOrigin,
[List<MessagePort>? messagePorts]) =>
- js_util.callMethod(this, 'postMessage', <Object?>[
- js_util.jsify(message),
- targetOrigin,
- if (messagePorts != null) js_util.jsify(messagePorts)
+ callMethodVarArgs('postMessage'.toJS, <JSAny?>[
+ message.jsify(),
+ targetOrigin.toJS,
+ if (messagePorts != null) messagePorts.toJS
]);
}
@JS('window')
external Window get window;
-@JS()
-@staticInterop
-class Console {}
-
-extension ConsoleExtension on Console {
- external void log(Object? object);
- external void warn(Object? object);
+extension type Console(JSObject _) implements JSObject {
+ external void log(JSAny? object);
+ external void warn(JSAny? object);
}
-@JS()
-@staticInterop
-class Document extends Node {}
-
-extension DocumentExtension on Document {
+extension type Document(Node _) implements Node {
external Element? querySelector(String selectors);
- Element createElement(String name, [Object? options]) => js_util.callMethod(
- this, 'createElement', <Object>[name, if (options != null) options])
- as Element;
+
+ Element createElement(String name, [Object? options]) => callMethodVarArgs(
+ 'createElement'.toJS,
+ <JSAny?>[name.toJS, if (options != null) options.jsify()]) as Element;
}
-@JS()
-@staticInterop
-class HTMLDocument extends Document {}
-
-extension HTMLDocumentExtension on HTMLDocument {
+extension type HTMLDocument(Document _) implements Document {
external HTMLBodyElement? get body;
external String? get title;
}
@@ -67,35 +54,19 @@
@JS('document')
external HTMLDocument get document;
-@JS()
-@staticInterop
-class Navigator {}
-
-extension NavigatorExtension on Navigator {
+extension type Navigator(JSObject _) implements JSObject {
external String get userAgent;
}
-@JS()
-@staticInterop
-class Element extends Node {}
-
-extension DomElementExtension on Element {
+extension type Element(Node _) implements Node {
external DomTokenList get classList;
}
-@JS()
-@staticInterop
-class HTMLElement extends Element {}
+extension type HTMLElement(Element _) implements Element {}
-@JS()
-@staticInterop
-class HTMLBodyElement extends HTMLElement {}
+extension type HTMLBodyElement(HTMLElement _) implements HTMLElement {}
-@JS()
-@staticInterop
-class Node extends EventTarget {}
-
-extension NodeExtension on Node {
+extension type Node(EventTarget _) implements EventTarget {
external Node appendChild(Node node);
void remove() {
if (parentNode != null) {
@@ -108,47 +79,43 @@
external Node? get parentNode;
}
-@JS()
-@staticInterop
-class EventTarget {}
-
-extension EventTargetExtension on EventTarget {
+extension type EventTarget(JSObject _) implements JSObject {
void addEventListener(String type, EventListener? listener,
[bool? useCapture]) {
if (listener != null) {
- js_util.callMethod<void>(this, 'addEventListener',
- <Object>[type, listener, if (useCapture != null) useCapture]);
+ callMethodVarArgs('addEventListener'.toJS, <JSAny?>[
+ type.toJS,
+ listener.toJS,
+ if (useCapture != null) useCapture.toJS
+ ]);
}
}
void removeEventListener(String type, EventListener? listener,
[bool? useCapture]) {
if (listener != null) {
- js_util.callMethod<void>(this, 'removeEventListener',
- <Object>[type, listener, if (useCapture != null) useCapture]);
+ callMethodVarArgs('removeEventListener'.toJS, <JSAny?>[
+ type.toJS,
+ listener.toJS,
+ if (useCapture != null) useCapture.toJS
+ ]);
}
}
}
typedef EventListener = void Function(Event event);
-@JS()
-@staticInterop
-class Event {}
-
-extension EventExtension on Event {
+extension type Event(JSObject _) implements JSObject {
external void stopPropagation();
}
-@JS()
-@staticInterop
-class MessageEvent extends Event {}
+extension type MessageEvent(Event _) implements Event {
+ dynamic get data => getProperty('data'.toJS).dartify();
-extension MessageEventExtension on MessageEvent {
- dynamic get data => js_util.dartify(js_util.getProperty(this, 'data'));
external String get origin;
+
List<MessagePort> get ports =>
- js_util.getProperty<List>(this, 'ports').cast<MessagePort>();
+ getProperty<JSArray>('ports'.toJS).toDart.cast<MessagePort>();
/// The source may be a `WindowProxy`, a `MessagePort`, or a `ServiceWorker`.
///
@@ -156,77 +123,47 @@
/// the source will be a `WindowProxy` which has the same methods as [Window].
@pragma('dart2js:as:trust')
MessageEventSource get source =>
- js_util.getProperty<dynamic>(this, 'source') as MessageEventSource;
+ getProperty('source'.toJS) as MessageEventSource;
}
-@JS()
-@staticInterop
-class MessageEventSource {}
-
-extension MessageEventSourceExtension on MessageEventSource {
+extension type MessageEventSource(JSObject _) implements JSObject {
@pragma('dart2js:as:trust')
MessageEventSourceLocation? get location =>
- js_util.getProperty<dynamic>(this, 'location')
- as MessageEventSourceLocation;
+ getProperty('location'.toJS) as MessageEventSourceLocation;
}
-@JS()
-@staticInterop
-class MessageEventSourceLocation {}
-
-extension MessageEventSourceLocationExtension on MessageEventSourceLocation {
+extension type MessageEventSourceLocation(JSObject _) implements JSObject {
external String? get href;
}
-@JS()
-@staticInterop
-class Location {}
-
-extension LocationExtension on Location {
+extension type Location(JSObject _) implements JSObject {
external String get href;
external String get origin;
}
-@JS()
-@staticInterop
-class MessagePort extends EventTarget {}
+extension type MessagePort(EventTarget _) implements EventTarget {
+ void postMessage(Object? message) => callMethodVarArgs(
+ 'postMessage'.toJS, <JSAny?>[if (message != null) message.jsify()]);
-extension MessagePortExtension on MessagePort {
- void postMessage(Object? message) => js_util.callMethod(this, 'postMessage',
- <Object>[if (message != null) js_util.jsify(message) as Object]);
external void start();
}
-@JS()
-@staticInterop
-class CSSStyleDeclaration {}
+extension type CSSStyleDeclaration(JSObject _) implements JSObject {}
-@JS()
-@staticInterop
-class HTMLScriptElement extends HTMLElement {}
-
-extension HTMLScriptElementExtension on HTMLScriptElement {
+extension type HTMLScriptElement(HTMLElement _) implements HTMLElement {
external set src(String value);
}
HTMLScriptElement createHTMLScriptElement() =>
document.createElement('script') as HTMLScriptElement;
-@JS()
-@staticInterop
-class DomTokenList {}
-
-extension DomTokenListExtension on DomTokenList {
+extension type DomTokenList(JSObject _) implements JSObject {
external void add(String value);
external void remove(String value);
external bool contains(String token);
}
-@JS()
-@staticInterop
-class HTMLIFrameElement extends HTMLElement {}
-
-extension HTMLIFrameElementExtension on HTMLIFrameElement {
+extension type HTMLIFrameElement(HTMLElement _) implements HTMLElement {
external String? get src;
external set src(String? value);
external Window get contentWindow;
@@ -235,38 +172,28 @@
HTMLIFrameElement createHTMLIFrameElement() =>
document.createElement('iframe') as HTMLIFrameElement;
-@JS()
-@staticInterop
-class WebSocket extends EventTarget {}
-
-extension WebSocketExtension on WebSocket {
- external void send(Object? data);
+extension type WebSocket(EventTarget _) implements EventTarget {
+ external void send(JSAny? data);
}
WebSocket createWebSocket(String url) =>
- _callConstructor('WebSocket', <Object>[url])! as WebSocket;
+ _callConstructor('WebSocket', <JSAny?>[url.toJS])! as WebSocket;
-@JS()
-@staticInterop
-class MessageChannel {}
-
-extension MessageChannelExtension on MessageChannel {
+extension type MessageChannel(JSObject _) implements JSObject {
external MessagePort get port1;
external MessagePort get port2;
}
MessageChannel createMessageChannel() =>
- _callConstructor('MessageChannel', <Object>[])! as MessageChannel;
+ _callConstructor('MessageChannel', <JSAny?>[])! as MessageChannel;
-Object? _findConstructor(String constructorName) =>
- js_util.getProperty(window, constructorName);
-
-Object? _callConstructor(String constructorName, List<Object?> args) {
- final constructor = _findConstructor(constructorName);
+Object? _callConstructor(String constructorName, List<JSAny?> args) {
+ final constructor = window.getProperty(constructorName.toJS) as JSFunction?;
if (constructor == null) {
return null;
}
- return js_util.callConstructor(constructor, args);
+
+ return constructor.callAsConstructorVarArgs(args);
}
class Subscription {
diff --git a/pkgs/test/lib/src/runner/browser/post_message_channel.dart b/pkgs/test/lib/src/runner/browser/post_message_channel.dart
index 29bb3e5..229a33c 100644
--- a/pkgs/test/lib/src/runner/browser/post_message_channel.dart
+++ b/pkgs/test/lib/src/runner/browser/post_message_channel.dart
@@ -2,8 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// ignore: deprecated_member_use
-import 'dart:js_util';
+import 'dart:js_interop';
import 'package:stream_channel/stream_channel.dart';
@@ -14,15 +13,15 @@
///
/// Sends a [MessagePort] to the host page for the channel.
StreamChannel<Object?> postMessageChannel() {
- dom.window.console.log('Suite starting, sending channel to host');
+ dom.window.console.log('Suite starting, sending channel to host'.toJS);
var controller = StreamChannelController<Object?>(sync: true);
var channel = dom.createMessageChannel();
dom.window.parent
.postMessage('port', dom.window.location.origin, [channel.port2]);
- var portSubscription = dom.Subscription(channel.port1, 'message',
- allowInterop((dom.Event event) {
+ var portSubscription =
+ dom.Subscription(channel.port1, 'message', (dom.Event event) {
controller.local.sink.add((event as dom.MessageEvent).data);
- }));
+ });
channel.port1.start();
controller.local.stream
diff --git a/pkgs/test/test/runner/coverage_test.dart b/pkgs/test/test/runner/coverage_test.dart
index b149345..a49124b 100644
--- a/pkgs/test/test/runner/coverage_test.dart
+++ b/pkgs/test/test/runner/coverage_test.dart
@@ -83,9 +83,8 @@
await d.file('js_with_unicode_test.dart', '''
import 'dart:async';
-
- import 'package:js/js.dart';
- import 'package:js/js_util.dart';
+ import 'dart:js_interop';
+ import 'dart:js_interop_unsafe';
import 'package:test/src/runner/browser/dom.dart' as dom;
import 'package:test/test.dart';
@@ -95,9 +94,9 @@
final scriptLoaded = controller.stream.first;
final script = dom.createHTMLScriptElement()..src = src;
script.addEventListener('load',
- allowInterop((_) {
+ (_) {
controller.add('loaded');
- }));
+ });
dom.document.body!.appendChild(script);
await scriptLoaded.timeout(Duration(seconds: 1));
}
@@ -105,8 +104,8 @@
void main() {
test("test 1", () async {
await loadScript('file_with_unicode.js');
- expect(getProperty(dom.window, 'foo'), isNotNull);
- callMethod(dom.window, 'foo', []);
+ expect(dom.window.getProperty('foo'.toJS), isNotNull);
+ dom.window.callMethodVarArgs('foo'.toJS, []);
expect(true, isTrue);
});
}
diff --git a/pkgs/test/test/runner/test_on_test.dart b/pkgs/test/test/runner/test_on_test.dart
index 96baf0b..f89d92f 100644
--- a/pkgs/test/test/runner/test_on_test.dart
+++ b/pkgs/test/test/runner/test_on_test.dart
@@ -201,7 +201,7 @@
bool loadable = true}) {
var buffer = StringBuffer();
if (suiteTestOn != null) buffer.writeln("@TestOn('$suiteTestOn')");
- if (!loadable) buffer.writeln("import 'dart:js_util';");
+ if (!loadable) buffer.writeln("import 'dart:js_interop';");
buffer
..writeln("import 'package:test/test.dart';")
diff --git a/pkgs/test/tool/host.dart b/pkgs/test/tool/host.dart
index fd5a941..fe8c614 100644
--- a/pkgs/test/tool/host.dart
+++ b/pkgs/test/tool/host.dart
@@ -7,9 +7,8 @@
import 'dart:async';
import 'dart:convert';
+import 'dart:js_interop';
-// ignore: deprecated_member_use
-import 'package:js/js.dart';
import 'package:stack_trace/stack_trace.dart';
import 'package:stream_channel/stream_channel.dart';
import 'package:test/src/runner/browser/dom.dart' as dom;
@@ -104,7 +103,7 @@
/// does mean that the server needs to be sure to nest its [MultiChannel]s at
/// the same place the client does.
void main() {
- dom.window.console.log('Dart test runner browser host running');
+ dom.window.console.log('Dart test runner browser host running'.toJS);
if (_currentUrl.queryParameters['debug'] == 'true') {
dom.document.body!.classList.add('debug');
}
@@ -132,7 +131,7 @@
_domSubscriptions.remove(id)?.cancel();
default:
dom.window.console
- .warn('Unhandled message from test runner: $message');
+ .warn('Unhandled message from test runner: $message'.toJS);
}
});
@@ -142,21 +141,21 @@
(_) => serverChannel.sink.add({'command': 'ping'}));
var play = dom.document.querySelector('#play');
- play!.addEventListener('click', allowInterop((_) {
+ play!.addEventListener('click', (_) {
if (!dom.document.body!.classList.contains('paused')) return;
dom.document.body!.classList.remove('paused');
serverChannel.sink.add({'command': 'resume'});
- }));
+ });
- _jsApi = _JSApi(resume: allowInterop(() {
+ _jsApi = _JSApi(resume: () {
if (!dom.document.body!.classList.contains('paused')) return;
dom.document.body!.classList.remove('paused');
serverChannel.sink.add({'command': 'resume'});
- }), restartCurrent: allowInterop(() {
+ }, restartCurrent: () {
serverChannel.sink.add({'command': 'restart'});
- }));
+ });
}, (error, stackTrace) {
- dom.window.console.warn('$error\n${Trace.from(stackTrace).terse}');
+ dom.window.console.warn('$error\n${Trace.from(stackTrace).terse}'.toJS);
});
}
@@ -169,13 +168,13 @@
dom.createWebSocket(_currentUrl.queryParameters['managerUrl']!);
var controller = StreamChannelController<Object?>(sync: true);
- webSocket.addEventListener('message', allowInterop((message) {
+ webSocket.addEventListener('message', (message) {
controller.local.sink
.add(jsonDecode((message as dom.MessageEvent).data as String));
- }));
+ });
controller.local.stream
- .listen((message) => webSocket.send(jsonEncode(message)));
+ .listen((message) => webSocket.send(jsonEncode(message).toJS));
return MultiChannel(controller.foreign);
}
@@ -199,14 +198,14 @@
/// message channel port is active.
StreamChannel<dynamic> _connectToIframe(String url, int id) {
var suiteUrl = Uri.parse(url).removeFragment();
- dom.window.console.log('Starting suite $suiteUrl');
+ dom.window.console.log('Starting suite $suiteUrl'.toJS);
var iframe = dom.createHTMLIFrameElement();
_iframes[id] = iframe;
var controller = StreamChannelController<Object?>(sync: true);
late dom.Subscription windowSubscription;
windowSubscription =
- dom.Subscription(dom.window, 'message', allowInterop((dom.Event event) {
+ dom.Subscription(dom.window, 'message', (dom.Event event) {
// A message on the Window can theoretically come from any website. It's
// very unlikely that a malicious site would care about hacking someone's
// unit tests, let alone be able to find the test server while it's
@@ -222,14 +221,13 @@
switch (message.data) {
case 'port':
- dom.window.console.log('Connecting channel for suite $suiteUrl');
+ dom.window.console.log('Connecting channel for suite $suiteUrl'.toJS);
// The frame is starting and sending a port to forward for the suite.
final port = message.ports.first;
assert(!_domSubscriptions.containsKey(id));
- _domSubscriptions[id] =
- dom.Subscription(port, 'message', allowInterop((event) {
+ _domSubscriptions[id] = dom.Subscription(port, 'message', (event) {
controller.local.sink.add((event as dom.MessageEvent).data);
- }));
+ });
port.start();
assert(!_subscriptions.containsKey(id));
@@ -239,11 +237,11 @@
// loading the test.
controller.local.sink.add(data);
}
- }));
+ });
iframe.src = url;
dom.document.body!.appendChild(iframe);
- dom.window.console.log('Appended iframe with src $url');
+ dom.window.console.log('Appended iframe with src $url'.toJS);
return controller.foreign;
}