diff --git a/LibTest/js_interop/interop_type_A01_t01.dart b/LibTest/js_interop/interop_type_A01_t01.dart new file mode 100644 index 0000000000..6ad20f141f --- /dev/null +++ b/LibTest/js_interop/interop_type_A01_t01.dart @@ -0,0 +1,55 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// 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. + +/// @assertion When interacting with a JS value, you need to provide a Dart type +/// for it. You can do this by either using or declaring an interop type. +/// Interop types are either a "JS type" provided by Dart or an extension type +/// wrapping an interop type. +/// +/// @description Check that it is a compile-time error if a JS interop type +/// member contains Dart [Object] or a type parameter with [Object] as a bound +/// in its signature. +/// @author sgrekhov22@gmail.com + +import 'dart:js_interop'; + +extension type ET._(JSObject _) implements JSObject { + external ET.fromDartObject(Object value); +// ^^^^^^ +// [analyzer] unspecified +// [web] unspecified + + external Object foo(); +// ^^^^^^ +// [analyzer] unspecified +// [web] unspecified + + external void bar(Object _); +// ^^^^^^ +// [analyzer] unspecified +// [web] unspecified +} + +@JS('ET') +extension type ET2._(JSObject _) implements JSObject { + external factory ET2.fromDartObject(T value); +// ^ +// [analyzer] unspecified +// [web] unspecified + + external T foo(); +// ^ +// [analyzer] unspecified +// [web] unspecified + + external void bar(T _); +// ^ +// [analyzer] unspecified +// [web] unspecified +} + +main() { + print(ET); + print(ET2); +} diff --git a/LibTest/js_interop/interop_type_A01_t02.dart b/LibTest/js_interop/interop_type_A01_t02.dart new file mode 100644 index 0000000000..87a4d491da --- /dev/null +++ b/LibTest/js_interop/interop_type_A01_t02.dart @@ -0,0 +1,59 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// 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. + +/// @assertion When interacting with a JS value, you need to provide a Dart type +/// for it. You can do this by either using or declaring an interop type. +/// Interop types are either a "JS type" provided by Dart or an extension type +/// wrapping an interop type. +/// +/// @description Check that it is a compile-time error if a JS interop type +/// member contains in its signature an extension type with Dart [Object] as a +/// representation type. +/// @author sgrekhov22@gmail.com + +import 'dart:js_interop'; + +extension type ObjectET1(Object o) implements Object {} + +extension type ObjectET2(Object o) {} + +extension type ET._(JSObject _) implements JSObject { + external ET.fromDartObject(ObjectET1 value); +// ^^^^^^^^^ +// [analyzer] unspecified +// [web] unspecified + + external ObjectET1 foo(); +// ^^^^^^^^^ +// [analyzer] unspecified +// [web] unspecified + + external void bar(ObjectET1 _); +// ^^^^^^^^^ +// [analyzer] unspecified +// [web] unspecified +} + +@JS('ET') +extension type ET2._(JSObject _) implements JSObject { + external ET2.fromDartObject(ObjectET2 value); +// ^^^^^^^^^ +// [analyzer] unspecified +// [web] unspecified + + external ObjectET2 foo(); +// ^^^^^^^^^ +// [analyzer] unspecified +// [web] unspecified + + external void bar(ObjectET2 _); +// ^^^^^^^^^ +// [analyzer] unspecified +// [web] unspecified +} + +main() { + print(ET); + print(ET2); +} diff --git a/LibTest/js_interop/interop_type_A01_t03.dart b/LibTest/js_interop/interop_type_A01_t03.dart new file mode 100644 index 0000000000..04c3209c7e --- /dev/null +++ b/LibTest/js_interop/interop_type_A01_t03.dart @@ -0,0 +1,77 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// 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. + +/// @assertion When interacting with a JS value, you need to provide a Dart type +/// for it. You can do this by either using or declaring an interop type. +/// Interop types are either a "JS type" provided by Dart or an extension type +/// wrapping an interop type. +/// +/// @description Check that it is a compile-time error if a JS interop type +/// member contains Dart [dynamic] or a type parameter with [dynamic] as a bound +/// in its signature. +/// @author sgrekhov22@gmail.com + +import 'dart:js_interop'; + +extension type ET._(JSObject _) implements JSObject { + external ET.fromDart(dynamic value); +// ^^^^^^^ +// [analyzer] unspecified +// [web] unspecified + + external dynamic foo(); +// ^^^^^^^ +// [analyzer] unspecified +// [web] unspecified + + external void bar(dynamic _); +// ^^^^^^^ +// [analyzer] unspecified +// [web] unspecified +} + +@JS('ET') +extension type ET2._(JSObject _) implements JSObject { + external factory ET2.fromDart(T value); +// ^ +// [analyzer] unspecified +// [web] unspecified + + external T foo(); +// ^ +// [analyzer] unspecified +// [web] unspecified + + external void bar(T _); +// ^ +// [analyzer] unspecified +// [web] unspecified +} + +@JS('ET') +extension type ET3._(JSObject _) implements JSObject { + external ET3.fromDartDynamic(value); +// ^^^^^ +// [analyzer] unspecified +// [web] unspecified + external factory ET3.fromDart(value); +// ^^^^^ +// [analyzer] unspecified +// [web] unspecified + + external foo(); +// ^ +// [analyzer] unspecified +// [web] unspecified + + external void bar(_); +// ^ +// [analyzer] unspecified +// [web] unspecified +} + +main() { + print(ET); + print(ET2); +} diff --git a/LibTest/js_interop/interop_type_A01_t04.dart b/LibTest/js_interop/interop_type_A01_t04.dart new file mode 100644 index 0000000000..162bc2a377 --- /dev/null +++ b/LibTest/js_interop/interop_type_A01_t04.dart @@ -0,0 +1,63 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// 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. + +/// @assertion When interacting with a JS value, you need to provide a Dart type +/// for it. You can do this by either using or declaring an interop type. +/// Interop types are either a "JS type" provided by Dart or an extension type +/// wrapping an interop type. +/// +/// @description Check that a JS interop type member may contain JS types from +/// 'dart:js_interop' in its signature. +/// @author sgrekhov22@gmail.com + +import 'dart:js_interop'; +import 'dart:js_interop_unsafe'; +import '../../Utils/expect.dart'; +import 'js_utils.dart'; + +extension type ET._(JSObject _) implements JSObject { + external ET.c(JSNumber v1); + external factory ET.f(JSNumber v1, JSBigInt v2); + + external JSNumber v1; + external JSBigInt v2; + external JSString v; + external JSBoolean foo(); + external void bar(JSString _); + external JSSymbol baz(JSSymbol _); +} + +main() { + eval(r''' + class ET { + constructor(v1, v2) { + this.v1 = v1; + this.v2 = v2; + } + foo() { + return true; + } + bar(v) { + this.v = v; + } + baz(val) { + return val; + } + } + globalThis.ET = ET; + globalThis.bi = 123n; + globalThis.smb = Symbol('$name'); + '''); + ET et1 = ET.c(1.toJS); + Expect.equals(1, et1.v1.toDartInt); + Expect.isTrue(et1.foo().toDart); + et1.bar("x".toJS); + Expect.equals("x", et1.v.toDart); + + ET et2 = ET.f(2.toJS, (globalContext["bi"] as JSBigInt)); + Expect.equals(2, et2.v1.toDartInt); + Expect.equals(123.toString(), et2.v2.toString()); + var smb = globalContext["smb"] as JSSymbol; + Expect.equals(smb, et2.baz(smb)); +} diff --git a/LibTest/js_interop/interop_type_A01_t05.dart b/LibTest/js_interop/interop_type_A01_t05.dart new file mode 100644 index 0000000000..0c76183fae --- /dev/null +++ b/LibTest/js_interop/interop_type_A01_t05.dart @@ -0,0 +1,61 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// 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. + +/// @assertion When interacting with a JS value, you need to provide a Dart type +/// for it. You can do this by either using or declaring an interop type. +/// Interop types are either a "JS type" provided by Dart or an extension type +/// wrapping an interop type. +/// +/// @description Check that a JS interop type member may contain an +/// `ExternalDartReference` in its signature. +/// @author sgrekhov22@gmail.com + +import 'dart:js_interop'; +import '../../Utils/expect.dart'; +import 'js_utils.dart'; + +class C { + int id; + String name; + C(this.id, this.name); +} + +extension type ET._(JSObject _) implements JSObject { + external ET.fromDart(ExternalDartReference v); + external factory ET.fromDartFactory(ExternalDartReference v); + + external ExternalDartReference foo(); + external ExternalDartReference bar(ExternalDartReference _); +} + +main() { + eval(r''' + class ET { + constructor(v) { + this.v = v; + } + foo() { + return this.v; + } + bar(v) { + return v; + } + } + globalThis.ET = ET; + '''); + C c1 = C(42, "Object from Dart"); + ET et1 = ET.fromDart(c1.toExternalReference); + ExternalDartReference ref1 = et1.foo(); + Expect.equals(42, ref1.toDartObject.id); + Expect.equals("Object from Dart", ref1.toDartObject.name); + var ref2 = et1.bar(c1.toExternalReference); + Expect.equals(42, ref2.toDartObject.id); + Expect.equals("Object from Dart", ref2.toDartObject.name); + + C c2 = C(1, "one"); + ET et2 = ET.fromDartFactory(c2.toExternalReference); + ExternalDartReference ref3 = et2.foo(); + Expect.equals(1, ref3.toDartObject.id); + Expect.equals("one", ref3.toDartObject.name); +} diff --git a/LibTest/js_interop/interop_type_A01_t06.dart b/LibTest/js_interop/interop_type_A01_t06.dart new file mode 100644 index 0000000000..96b8ab6597 --- /dev/null +++ b/LibTest/js_interop/interop_type_A01_t06.dart @@ -0,0 +1,54 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// 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. + +/// @assertion When interacting with a JS value, you need to provide a Dart type +/// for it. You can do this by either using or declaring an interop type. +/// Interop types are either a "JS type" provided by Dart or an extension type +/// wrapping an interop type. +/// +/// @description Check that a JS interop type member may contain Dart types +/// `void`, `bool`, `num`, `double`, `int` and `String` in its signature. +/// @author sgrekhov22@gmail.com + +import 'dart:js_interop'; +import '../../Utils/expect.dart'; +import 'js_utils.dart'; + +extension type ET._(JSObject _) implements JSObject { + external ET.fromDart(num v1); + external factory ET.fromNum(int v1, double v2); + + external num v1; + external num v2; + external String v; + external bool foo(); + external void bar(String _); +} + +main() { + eval(r''' + class ET { + constructor(v1, v2) { + this.v1 = v1; + this.v2 = v2; + } + foo() { + return true; + } + bar(v) { + this.v = v; + } + } + globalThis.ET = ET; + '''); + ET et1 = ET.fromDart(1); + Expect.equals(1, et1.v1); + Expect.isTrue(et1.foo()); + et1.bar("x"); + Expect.equals("x", et1.v); + + ET et2 = ET.fromNum(2, 3); + Expect.equals(2, et2.v1); + Expect.equals(3, et2.v2); +} diff --git a/LibTest/js_interop/interop_type_A01_t07.dart b/LibTest/js_interop/interop_type_A01_t07.dart new file mode 100644 index 0000000000..cc7a5628ae --- /dev/null +++ b/LibTest/js_interop/interop_type_A01_t07.dart @@ -0,0 +1,61 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// 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. + +/// @assertion When interacting with a JS value, you need to provide a Dart type +/// for it. You can do this by either using or declaring an interop type. +/// Interop types are either a "JS type" provided by Dart or an extension type +/// wrapping an interop type. +/// +/// @description Check that a JS interop type member may contain in its +/// signature extension types with `bool`, `num`, `double`, `int` and `String` +/// as representation types. +/// @author sgrekhov22@gmail.com + +import 'dart:js_interop'; +import '../../Utils/expect.dart'; +import 'js_utils.dart'; + +extension type BoolET(bool v) implements bool {} +extension type NumET(num v) implements num {} +extension type IntET(int v) implements int {} +extension type DoubleET(double v) implements double {} +extension type StringET(String v) implements String {} + +extension type ET._(JSObject _) implements JSObject { + external ET.fromDart(NumET v1); + external factory ET.fromNum(IntET v1, DoubleET v2); + + external NumET v1; + external NumET v2; + external StringET v; + external BoolET foo(); + external void bar(StringET _); +} + +main() { + eval(r''' + class ET { + constructor(v1, v2) { + this.v1 = v1; + this.v2 = v2; + } + foo() { + return true; + } + bar(v) { + this.v = v; + } + } + globalThis.ET = ET; + '''); + ET et1 = ET.fromDart(NumET(1)); + Expect.equals(1, et1.v1); + Expect.isTrue(et1.foo()); + et1.bar(StringET("x")); + Expect.equals("x", et1.v); + + ET et2 = ET.fromNum(IntET(2), DoubleET(3)); + Expect.equals(2, et2.v1); + Expect.equals(3, et2.v2); +} diff --git a/LibTest/js_interop/interop_type_A01_t08.dart b/LibTest/js_interop/interop_type_A01_t08.dart new file mode 100644 index 0000000000..e2466728d1 --- /dev/null +++ b/LibTest/js_interop/interop_type_A01_t08.dart @@ -0,0 +1,62 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// 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. + +/// @assertion When interacting with a JS value, you need to provide a Dart type +/// for it. You can do this by either using or declaring an interop type. +/// Interop types are either a "JS type" provided by Dart or an extension type +/// wrapping an interop type. +/// +/// @description Check that a JS interop type member may contain in its +/// signature extension types with `bool`, `num`, `double`, `int` and `String` +/// as representation types. Test extension types that don't implement their +/// representation types. +/// @author sgrekhov22@gmail.com + +import 'dart:js_interop'; +import '../../Utils/expect.dart'; +import 'js_utils.dart'; + +extension type BoolET(bool v) {} +extension type NumET(num v) {} +extension type IntET(int v) {} +extension type DoubleET(double v) {} +extension type StringET(String v) {} + +extension type ET._(JSObject _) implements JSObject { + external ET.fromDart(NumET v1); + external factory ET.fromNum(IntET v1, DoubleET v2); + + external NumET v1; + external NumET v2; + external StringET v; + external BoolET foo(); + external void bar(StringET _); +} + +main() { + eval(r''' + class ET { + constructor(v1, v2) { + this.v1 = v1; + this.v2 = v2; + } + foo() { + return true; + } + bar(v) { + this.v = v; + } + } + globalThis.ET = ET; + '''); + ET et1 = ET.fromDart(NumET(1)); + Expect.equals(1, et1.v1); + Expect.isTrue(et1.foo()); + et1.bar(StringET("x")); + Expect.equals("x", et1.v); + + ET et2 = ET.fromNum(IntET(2), DoubleET(3)); + Expect.equals(2, et2.v1); + Expect.equals(3, et2.v2); +} diff --git a/LibTest/js_interop/interop_type_A01_t09.dart b/LibTest/js_interop/interop_type_A01_t09.dart new file mode 100644 index 0000000000..abe33b6614 --- /dev/null +++ b/LibTest/js_interop/interop_type_A01_t09.dart @@ -0,0 +1,69 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// 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. + +/// @assertion When interacting with a JS value, you need to provide a Dart type +/// for it. You can do this by either using or declaring an interop type. +/// Interop types are either a "JS type" provided by Dart or an extension type +/// wrapping an interop type. +/// +/// @description Check that a JS interop type member may contain a +/// `@staticInterop` type in its signature. +/// @author sgrekhov22@gmail.com + +import 'dart:js_interop'; +import 'dart:js_interop_unsafe'; +import '../../Utils/expect.dart'; +import 'js_utils.dart'; + +@staticInterop +@JS() +class C { +} + +extension Ext on C { + external String id(); +} + +extension type ET._(JSObject _) implements JSObject { + external ET.fromDart(C c); + external factory ET.fromDartFactory(C c); + + external C foo(); + external C bar(C _); +} + +main() { + eval(r''' + globalThis.obj = { + id: function () { + return "I'm C"; + } + }; + '''); + C c = globalContext["obj"] as C; + eval(r''' + class ET { + constructor(v) { + this.v = v; + } + foo() { + return this.v; + } + bar(v) { + return v; + } + } + globalThis.ET = ET; + '''); + + ET et1 = ET.fromDart(c); + C ref1 = et1.foo(); + Expect.equals("I'm C", ref1.id()); + var ref2 = et1.bar(c); + Expect.equals("I'm C", ref2.id()); + + ET et2 = ET.fromDartFactory(c); + C ref3 = et2.foo(); + Expect.equals("I'm C", ref3.id()); +}