// Copyright (c) 2023, 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. /// Utility methods to manipulate JavaScript objects dynamically. /// /// This library is typically meant to be used when the names of properties or /// methods are not known statically. This library is similar to `dart:js_util`, /// except the methods here are extension methods that use JS types. This /// allows code using these functions to also be compiled to WebAssembly. /// /// In general, prefer to write JS interop interfaces and external static /// interop members using `dart:js_interop`. This library is meant to work /// around issues and help with migration from older JS interop libraries. /// /// > [!NOTE] /// > As the name suggests, usage of this library *can* be unsafe. This means /// > that safe usage of these methods cannot necessarily be verified /// > statically. Prefer using statically analyzable values like constants or /// > literals for property or method names so that usage can be verified. This /// > library should be used cautiously and only when the same effect cannot be /// > achieved with static interop. /// /// {@category Web} library; import 'dart:js_interop'; /// Utility methods to check, get, set, and call properties on a [JSObject]. /// /// See the [JavaScript specification](https://tc39.es/ecma262/#sec-object-type) /// for more details on using properties. extension JSObjectUnsafeUtilExtension on JSObject { /// Shorthand helper for [hasProperty] to check whether this [JSObject] /// contains the property key [property], but takes and returns a Dart value. bool has(String property) => hasProperty(property.toJS).toDart; /// Whether or not this [JSObject] contains the property key [property]. /// /// Uses JavaScript's `in` to check. external JSBoolean hasProperty(JSAny property); /// Shorthand helper for [getProperty] to get the value of the property key /// [property] of this [JSObject], but takes a Dart value. JSAny? operator [](String property) => getProperty(property.toJS); /// The value of the property key [property] of this [JSObject]. external R getProperty(JSAny property); /// Shorthand helper for [setProperty] to write the [value] of the property /// key [property] of this [JSObject], but takes a Dart value. void operator []=(String property, JSAny? value) => setProperty(property.toJS, value); /// Write the [value] of property key [property] of this [JSObject]. external void setProperty(JSAny property, JSAny? value); external JSAny? _callMethod( JSAny method, [ JSAny? arg1, JSAny? arg2, JSAny? arg3, JSAny? arg4, ]); /// Calls [method] on this [JSObject] with up to four arguments. /// /// Returns the result of calling [method], which must be an [R]. /// /// This helper doesn't allow passing nulls, as it determines whether an /// argument is passed based on whether it was null or not. Prefer /// [callMethodVarArgs] if you need to pass nulls. R callMethod( JSAny method, [ JSAny? arg1, JSAny? arg2, JSAny? arg3, JSAny? arg4, ]) => _callMethod(method, arg1, arg2, arg3, arg4) as R; external JSAny? _callMethodVarArgs(JSAny method, [List? arguments]); /// Calls [method] on this [JSObject] with a variable number of [arguments]. /// /// Returns the result of calling [method], which must be an [R]. R callMethodVarArgs( JSAny method, [ List? arguments, ]) => _callMethodVarArgs(method, arguments) as R; /// Deletes the property with key [property] from this [JSObject]. /// /// Uses JavaScript's `delete` to delete the property. external JSBoolean delete(JSAny property); } /// Utility methods to call [JSFunction]s as constructors. extension JSFunctionUnsafeUtilExtension on JSFunction { external JSObject _callAsConstructor([ JSAny? arg1, JSAny? arg2, JSAny? arg3, JSAny? arg4, ]); /// Calls this [JSFunction] as a constructor with up to four arguments. /// /// Returns the constructed object, which must be an [R]. /// /// This helper doesn't allow passing nulls, as it determines whether an /// argument is passed based on whether it was null or not. Prefer /// [callAsConstructorVarArgs] if you need to pass nulls. // TODO(srujzs): The type bound should extend `JSObject`. R callAsConstructor([ JSAny? arg1, JSAny? arg2, JSAny? arg3, JSAny? arg4, ]) => _callAsConstructor(arg1, arg2, arg3, arg4) as R; external JSObject _callAsConstructorVarArgs([List? arguments]); /// Calls this [JSFunction] as a constructor with a variable number of /// arguments. /// /// Returns the constructed [JSObject], which must be an [R]. R callAsConstructorVarArgs([List? arguments]) => _callAsConstructorVarArgs(arguments) as R; }