mirror of
https://github.com/dart-lang/sdk
synced 2024-10-02 23:39:19 +00:00
[JS interop] Expose more JavaScript operators in js_util
Exposes helper functions in js_util to access the JavaScript operators `delete`, `||`, `&&`, `!`, `!!`, and `typeof`. Change-Id: I0676b143aa004c7b4ed1c6b695b8d1e78a60778d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/276028 Commit-Queue: Riley Porter <rileyporter@google.com> Reviewed-by: Sigmund Cherem <sigmund@google.com> Reviewed-by: Srujan Gaddam <srujzs@google.com>
This commit is contained in:
parent
0c4c372d5e
commit
b6388f2ea0
|
@ -47,6 +47,11 @@
|
|||
removed. See [#49536](https://github.com/dart-lang/sdk/issues/49536) for
|
||||
details.
|
||||
|
||||
#### `dart:js_util`
|
||||
|
||||
- Added several helper functions to access more JavaScript operator, like
|
||||
`delete` and the `typeof` functionality.
|
||||
|
||||
#### `dart:async`
|
||||
|
||||
- **Breaking change** [#49529][]:
|
||||
|
|
|
@ -345,6 +345,42 @@ bool lessThanOrEqual<T>(Object? first, Object? second) {
|
|||
return JS<bool>('bool', '# <= #', first, second);
|
||||
}
|
||||
|
||||
@patch
|
||||
@pragma('dart2js:tryInline')
|
||||
bool typeofEquals<T>(Object? o, String type) {
|
||||
return JS<bool>('bool', 'typeof # == #', o, type);
|
||||
}
|
||||
|
||||
@patch
|
||||
@pragma('dart2js:tryInline')
|
||||
T not<T>(Object? o) {
|
||||
return JS<dynamic>('Object', '!#', o);
|
||||
}
|
||||
|
||||
@patch
|
||||
@pragma('dart2js:tryInline')
|
||||
bool isTruthy<T>(Object? o) {
|
||||
return JS<bool>('bool', '!!#', o);
|
||||
}
|
||||
|
||||
@patch
|
||||
@pragma('dart2js:tryInline')
|
||||
T or<T>(Object? first, Object? second) {
|
||||
return JS<dynamic>('Object|bool', '# || #', first, second);
|
||||
}
|
||||
|
||||
@patch
|
||||
@pragma('dart2js:tryInline')
|
||||
T and<T>(Object? first, Object? second) {
|
||||
return JS<dynamic>('Object|bool', '# && #', first, second);
|
||||
}
|
||||
|
||||
@patch
|
||||
@pragma('dart2js:tryInline')
|
||||
bool delete<T>(Object o, Object property) {
|
||||
return JS<bool>('bool', 'delete #[#]', o, property);
|
||||
}
|
||||
|
||||
@patch
|
||||
Future<T> promiseToFuture<T>(Object jsPromise) {
|
||||
final completer = Completer<T>();
|
||||
|
|
|
@ -97,6 +97,27 @@ external bool lessThan<T>(Object? first, Object? second);
|
|||
/// Perform JavaScript less than or equal comparison (`<=`) of two values.
|
||||
external bool lessThanOrEqual<T>(Object? first, Object? second);
|
||||
|
||||
/// Perform JavaScript `typeof` operator on the given object and determine if
|
||||
/// the result is equal to the given type. Exposes the whole `typeof` equal
|
||||
/// expression to maximize browser optimization.
|
||||
external bool typeofEquals<T>(Object? o, String type);
|
||||
|
||||
/// Perform JavaScript logical not (`!`) on the given object.
|
||||
external T not<T>(Object? o);
|
||||
|
||||
/// Determines if the given object is truthy or falsy.
|
||||
external bool isTruthy<T>(Object? o);
|
||||
|
||||
/// Perform JavaScript logical or comparison (`||`) of two expressions.
|
||||
external T or<T>(Object? first, Object? second);
|
||||
|
||||
/// Perform JavaScript logical and comparison (`&&`) of two expressions.
|
||||
external T and<T>(Object? first, Object? second);
|
||||
|
||||
/// Perform JavaScript delete operator (`delete`) on the given property of the
|
||||
/// given object.
|
||||
external bool delete<T>(Object o, Object property);
|
||||
|
||||
/// Exception for when the promise is rejected with a `null` or `undefined`
|
||||
/// value.
|
||||
///
|
||||
|
|
138
tests/lib/js/js_util/operator_test.dart
Normal file
138
tests/lib/js/js_util/operator_test.dart
Normal file
|
@ -0,0 +1,138 @@
|
|||
// Copyright (c) 2022, 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.
|
||||
|
||||
// Tests invoking JS operators through js_util.
|
||||
|
||||
@JS()
|
||||
library js_util_operator_test;
|
||||
|
||||
import 'package:js/js.dart';
|
||||
import 'package:js/js_util.dart' as js_util;
|
||||
import 'package:expect/minitest.dart';
|
||||
|
||||
@JS()
|
||||
external void eval(String code);
|
||||
|
||||
@JS()
|
||||
external Object get undefinedObject;
|
||||
|
||||
@JS()
|
||||
class Foo {
|
||||
external Foo();
|
||||
}
|
||||
|
||||
main() {
|
||||
eval(r"""
|
||||
function Foo() {}
|
||||
""");
|
||||
|
||||
test('typeofEquals', () {
|
||||
expect(js_util.typeofEquals(5, 'number'), isTrue);
|
||||
expect(js_util.typeofEquals(5, 'string'), isFalse);
|
||||
|
||||
expect(js_util.typeofEquals('foo', 'string'), isTrue);
|
||||
expect(js_util.typeofEquals('foo', 'number'), isFalse);
|
||||
|
||||
expect(js_util.typeofEquals(null, 'object'), isTrue);
|
||||
expect(js_util.typeofEquals(null, 'boolean'), isFalse);
|
||||
|
||||
expect(js_util.typeofEquals(true, 'boolean'), isTrue);
|
||||
expect(js_util.typeofEquals(true, 'number'), isFalse);
|
||||
|
||||
expect(js_util.typeofEquals(Foo(), 'object'), isTrue);
|
||||
expect(js_util.typeofEquals(Foo(), 'function'), isFalse);
|
||||
|
||||
expect(js_util.typeofEquals(js_util.newObject(), 'object'), isTrue);
|
||||
expect(js_util.typeofEquals(js_util.newObject(), 'function'), isFalse);
|
||||
|
||||
expect(js_util.typeofEquals([], 'object'), isTrue);
|
||||
expect(js_util.typeofEquals([], 'function'), isFalse);
|
||||
|
||||
expect(js_util.typeofEquals(undefinedObject, 'undefined'), isTrue);
|
||||
expect(js_util.typeofEquals(undefinedObject, 'object'), isFalse);
|
||||
|
||||
expect(
|
||||
js_util.typeofEquals(
|
||||
js_util.getProperty(js_util.globalThis, 'Foo'), 'function'),
|
||||
isTrue);
|
||||
});
|
||||
|
||||
test('not', () {
|
||||
expect(js_util.not(true), isFalse);
|
||||
expect(js_util.not(false), isTrue);
|
||||
|
||||
expect(js_util.not(null), isTrue);
|
||||
expect(js_util.not(''), isTrue);
|
||||
expect(js_util.not(0), isTrue);
|
||||
expect(js_util.not(undefinedObject), isTrue);
|
||||
|
||||
expect(js_util.not([]), isFalse);
|
||||
expect(js_util.not({}), isFalse);
|
||||
expect(js_util.not(js_util.newObject()), isFalse);
|
||||
expect(js_util.not(Foo()), isFalse);
|
||||
expect(js_util.not('foo'), isFalse);
|
||||
expect(js_util.not(5), isFalse);
|
||||
});
|
||||
|
||||
test('isTruthy', () {
|
||||
expect(js_util.isTruthy(true), isTrue);
|
||||
expect(js_util.isTruthy(false), isFalse);
|
||||
|
||||
expect(js_util.isTruthy(null), isFalse);
|
||||
expect(js_util.isTruthy(''), isFalse);
|
||||
expect(js_util.isTruthy(0), isFalse);
|
||||
expect(js_util.isTruthy(undefinedObject), isFalse);
|
||||
|
||||
expect(js_util.isTruthy([]), isTrue);
|
||||
expect(js_util.isTruthy({}), isTrue);
|
||||
expect(js_util.isTruthy(js_util.newObject()), isTrue);
|
||||
expect(js_util.isTruthy(Foo()), isTrue);
|
||||
expect(js_util.isTruthy('foo'), isTrue);
|
||||
expect(js_util.isTruthy(5), isTrue);
|
||||
});
|
||||
|
||||
test('or', () {
|
||||
expect(js_util.or(true, false), isTrue);
|
||||
expect(js_util.or(true, true), isTrue);
|
||||
expect(js_util.or(false, true), isTrue);
|
||||
expect(js_util.or(false, false), isFalse);
|
||||
|
||||
expect(js_util.or('foo', 'bar'), equals('foo'));
|
||||
expect(js_util.or(null, 'foo'), equals('foo'));
|
||||
expect(js_util.or(undefinedObject, 'foo'), equals('foo'));
|
||||
expect(js_util.or(0, 'foo'), equals('foo'));
|
||||
expect(js_util.or('', 'foo'), equals('foo'));
|
||||
expect(js_util.or([], 'bar'), equals([]));
|
||||
var o = js_util.newObject();
|
||||
expect(js_util.or(o, 'foo'), equals(o));
|
||||
});
|
||||
|
||||
test('and', () {
|
||||
expect(js_util.and(true, false), isFalse);
|
||||
expect(js_util.and(true, true), isTrue);
|
||||
expect(js_util.and(false, true), isFalse);
|
||||
expect(js_util.and(false, false), isFalse);
|
||||
|
||||
expect(js_util.and('foo', 'bar'), equals('bar'));
|
||||
expect(js_util.and(null, 'foo'), equals(null));
|
||||
// Should be undefined if we had JS types
|
||||
expect(js_util.and(undefinedObject, 'foo'), equals(null));
|
||||
expect(js_util.and(0, 'foo'), equals(0));
|
||||
expect(js_util.and([], 'bar'), equals('bar'));
|
||||
var o = js_util.newObject();
|
||||
expect(js_util.and(o, 'foo'), equals('foo'));
|
||||
});
|
||||
|
||||
test('delete', () {
|
||||
var f = Foo();
|
||||
|
||||
expect(js_util.delete(f, 'unknownProperty'), isTrue);
|
||||
|
||||
expect(js_util.getProperty(f, 'a'), equals(null));
|
||||
js_util.setProperty(f, 'a', 'foo');
|
||||
expect(js_util.getProperty(f, 'a'), equals('foo'));
|
||||
expect(js_util.delete(f, 'a'), isTrue);
|
||||
expect(js_util.getProperty(f, 'a'), equals(null));
|
||||
});
|
||||
}
|
|
@ -52,6 +52,7 @@ js/js_util/async_test: SkipByDesign # Issue 42085. CSP policy disallows injected
|
|||
js/js_util/implicit_downcast_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
|
||||
js/js_util/javascriptobject_extensions_test.dart: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
|
||||
js/js_util/jsify_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
|
||||
js/js_util/operator_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
|
||||
js/js_util/promise_reject_null_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
|
||||
js/js_util/properties_implicit_checks_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
|
||||
js/js_util/properties_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
|
||||
|
|
138
tests/lib_2/js/js_util/operator_test.dart
Normal file
138
tests/lib_2/js/js_util/operator_test.dart
Normal file
|
@ -0,0 +1,138 @@
|
|||
// Copyright (c) 2022, 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.
|
||||
|
||||
// Tests invoking JS operators through js_util.
|
||||
|
||||
@JS()
|
||||
library js_util_operator_test;
|
||||
|
||||
import 'package:js/js.dart';
|
||||
import 'package:js/js_util.dart' as js_util;
|
||||
import 'package:expect/minitest.dart';
|
||||
|
||||
@JS()
|
||||
external void eval(String code);
|
||||
|
||||
@JS()
|
||||
external Object get undefinedObject;
|
||||
|
||||
@JS()
|
||||
class Foo {
|
||||
external Foo();
|
||||
}
|
||||
|
||||
main() {
|
||||
eval(r"""
|
||||
function Foo() {}
|
||||
""");
|
||||
|
||||
test('typeofEquals', () {
|
||||
expect(js_util.typeofEquals(5, 'number'), isTrue);
|
||||
expect(js_util.typeofEquals(5, 'string'), isFalse);
|
||||
|
||||
expect(js_util.typeofEquals('foo', 'string'), isTrue);
|
||||
expect(js_util.typeofEquals('foo', 'number'), isFalse);
|
||||
|
||||
expect(js_util.typeofEquals(null, 'object'), isTrue);
|
||||
expect(js_util.typeofEquals(null, 'boolean'), isFalse);
|
||||
|
||||
expect(js_util.typeofEquals(true, 'boolean'), isTrue);
|
||||
expect(js_util.typeofEquals(true, 'number'), isFalse);
|
||||
|
||||
expect(js_util.typeofEquals(Foo(), 'object'), isTrue);
|
||||
expect(js_util.typeofEquals(Foo(), 'function'), isFalse);
|
||||
|
||||
expect(js_util.typeofEquals(js_util.newObject(), 'object'), isTrue);
|
||||
expect(js_util.typeofEquals(js_util.newObject(), 'function'), isFalse);
|
||||
|
||||
expect(js_util.typeofEquals([], 'object'), isTrue);
|
||||
expect(js_util.typeofEquals([], 'function'), isFalse);
|
||||
|
||||
expect(js_util.typeofEquals(undefinedObject, 'undefined'), isTrue);
|
||||
expect(js_util.typeofEquals(undefinedObject, 'object'), isFalse);
|
||||
|
||||
expect(
|
||||
js_util.typeofEquals(
|
||||
js_util.getProperty(js_util.globalThis, 'Foo'), 'function'),
|
||||
isTrue);
|
||||
});
|
||||
|
||||
test('not', () {
|
||||
expect(js_util.not(true), isFalse);
|
||||
expect(js_util.not(false), isTrue);
|
||||
|
||||
expect(js_util.not(null), isTrue);
|
||||
expect(js_util.not(''), isTrue);
|
||||
expect(js_util.not(0), isTrue);
|
||||
expect(js_util.not(undefinedObject), isTrue);
|
||||
|
||||
expect(js_util.not([]), isFalse);
|
||||
expect(js_util.not({}), isFalse);
|
||||
expect(js_util.not(js_util.newObject()), isFalse);
|
||||
expect(js_util.not(Foo()), isFalse);
|
||||
expect(js_util.not('foo'), isFalse);
|
||||
expect(js_util.not(5), isFalse);
|
||||
});
|
||||
|
||||
test('isTruthy', () {
|
||||
expect(js_util.isTruthy(true), isTrue);
|
||||
expect(js_util.isTruthy(false), isFalse);
|
||||
|
||||
expect(js_util.isTruthy(null), isFalse);
|
||||
expect(js_util.isTruthy(''), isFalse);
|
||||
expect(js_util.isTruthy(0), isFalse);
|
||||
expect(js_util.isTruthy(undefinedObject), isFalse);
|
||||
|
||||
expect(js_util.isTruthy([]), isTrue);
|
||||
expect(js_util.isTruthy({}), isTrue);
|
||||
expect(js_util.isTruthy(js_util.newObject()), isTrue);
|
||||
expect(js_util.isTruthy(Foo()), isTrue);
|
||||
expect(js_util.isTruthy('foo'), isTrue);
|
||||
expect(js_util.isTruthy(5), isTrue);
|
||||
});
|
||||
|
||||
test('or', () {
|
||||
expect(js_util.or(true, false), isTrue);
|
||||
expect(js_util.or(true, true), isTrue);
|
||||
expect(js_util.or(false, true), isTrue);
|
||||
expect(js_util.or(false, false), isFalse);
|
||||
|
||||
expect(js_util.or('foo', 'bar'), equals('foo'));
|
||||
expect(js_util.or(null, 'foo'), equals('foo'));
|
||||
expect(js_util.or(undefinedObject, 'foo'), equals('foo'));
|
||||
expect(js_util.or(0, 'foo'), equals('foo'));
|
||||
expect(js_util.or('', 'foo'), equals('foo'));
|
||||
expect(js_util.or([], 'bar'), equals([]));
|
||||
var o = js_util.newObject();
|
||||
expect(js_util.or(o, 'foo'), equals(o));
|
||||
});
|
||||
|
||||
test('and', () {
|
||||
expect(js_util.and(true, false), isFalse);
|
||||
expect(js_util.and(true, true), isTrue);
|
||||
expect(js_util.and(false, true), isFalse);
|
||||
expect(js_util.and(false, false), isFalse);
|
||||
|
||||
expect(js_util.and('foo', 'bar'), equals('bar'));
|
||||
expect(js_util.and(null, 'foo'), equals(null));
|
||||
// Should be undefined if we had JS types
|
||||
expect(js_util.and(undefinedObject, 'foo'), equals(null));
|
||||
expect(js_util.and(0, 'foo'), equals(0));
|
||||
expect(js_util.and([], 'bar'), equals('bar'));
|
||||
var o = js_util.newObject();
|
||||
expect(js_util.and(o, 'foo'), equals('foo'));
|
||||
});
|
||||
|
||||
test('delete', () {
|
||||
var f = Foo();
|
||||
|
||||
expect(js_util.delete(f, 'unknownProperty'), isTrue);
|
||||
|
||||
expect(js_util.getProperty(f, 'a'), equals(null));
|
||||
js_util.setProperty(f, 'a', 'foo');
|
||||
expect(js_util.getProperty(f, 'a'), equals('foo'));
|
||||
expect(js_util.delete(f, 'a'), isTrue);
|
||||
expect(js_util.getProperty(f, 'a'), equals(null));
|
||||
});
|
||||
}
|
|
@ -52,6 +52,7 @@ js/js_util/async_test: SkipByDesign # Issue 42085. CSP policy disallows injected
|
|||
js/js_util/implicit_downcast_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
|
||||
js/js_util/javascriptobject_extensions_test.dart: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
|
||||
js/js_util/jsify_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
|
||||
js/js_util/operator_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
|
||||
js/js_util/promise_reject_null_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
|
||||
js/js_util/properties_implicit_checks_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
|
||||
js/js_util/properties_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
|
||||
|
|
Loading…
Reference in a new issue