Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(258)

Unified Diff: sdk/lib/js/dart2js/js_dart2js.dart

Issue 2150313003: Add JSNative utility class with static methods methods to efficiently manipulate typed JSInterop ob… (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Add JSNative utility class with static methods methods to efficiently manipulate typed JSInterop ob… Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sdk/lib/js/dart2js/js_dart2js.dart
diff --git a/sdk/lib/js/dart2js/js_dart2js.dart b/sdk/lib/js/dart2js/js_dart2js.dart
index 4b3e4a63d092e65ef16fd8f77f113c8c21f2d0fa..6e2ff1b5d6468e248cf82640188fe5368b85c3da 100644
--- a/sdk/lib/js/dart2js/js_dart2js.dart
+++ b/sdk/lib/js/dart2js/js_dart2js.dart
@@ -707,7 +707,7 @@ _callDartFunctionFastCaptureThis(callback, self, List arguments) {
return Function.apply(callback, [self]..addAll(arguments));
}
-Function /*=F*/ allowInterop/*<F extends Function>*/(Function /*=F*/ f) {
+Function/*=F*/ allowInterop/*<F extends Function>*/(Function/*=F*/ f) {
if (JS('bool', 'typeof(#) == "function"', f)) {
// Already supports interop, just use the existing function.
return f;
@@ -726,3 +726,125 @@ Function allowInteropCaptureThis(Function f) {
return _convertDartFunctionFastCaptureThis(f);
}
}
+
+/// Utility methods to efficiently manipulate typed JSInterop objects in cases
+/// where the name to call is not known at runtime. You should only use these
+/// methods when the same effect cannot be achieved with @JS annotations.
+/// These methods would be extension methods on JSObject if Dart supported
+/// extension methods.
+class JSNative {
sra1 2016/07/20 18:19:20 Maybe call JSUtils ? JavaScriptUtils ? Or a dart:l
Jacob 2016/07/22 19:28:24 added dart:js_util re-export it as package:js/js
+ /**
+ * WARNING: performance of this method is much worse than other methods
+ * in JSNative. Only use this method as a last resort.
+ *
+ * Recursively converts a JSON-like collection of Dart objects to a
+ * collection of JavaScript objects and returns a [JsObject] proxy to it.
+ *
+ * [object] must be a [Map] or [Iterable], the contents of which are also
+ * converted. Maps and Iterables are copied to a new JavaScript object.
+ * Primitives and other transferrable values are directly converted to their
+ * JavaScript type, and all other objects are proxied.
+ */
+ static jsify(object) {
+ if ((object is! Map) && (object is! Iterable)) {
+ throw new ArgumentError("object must be a Map or Iterable");
+ }
+ return _convertDataTree(object);
+ }
+
+ static _convertDataTree(data) {
+ var _convertedObjects = new HashMap.identity();
+
+ _convert(o) {
+ if (_convertedObjects.containsKey(o)) {
+ return _convertedObjects[o];
+ }
+ if (o is Map) {
+ final convertedMap = JS('=Object', '{}');
+ _convertedObjects[o] = convertedMap;
+ for (var key in o.keys) {
+ JS('=Object', '#[#]=#', convertedMap, key, _convert(o[key]));
+ }
+ return convertedMap;
+ } else if (o is Iterable) {
+ var convertedList = [];
+ _convertedObjects[o] = convertedList;
+ convertedList.addAll(o.map(_convert));
+ return convertedList;
+ } else {
+ return o;
+ }
+ }
+
+ return _convert(data);
+ }
+
+ static JSObject newObject() => JS('=Object', '{}');
+
+ static hasProperty(o, name) => JS('bool', '# in #', name, o);
+ static getProperty(o, name) => JS('Object', '#[#]', o, name);
+ static setProperty(o, name, value) => JS('', '#[#]=#', o, name, value);
+
+ static callMethod(o, String method, List args) =>
+ JS('Object', '#[#].apply(#, #)', o, method, o, args);
+
+ static instanceof(o, Function type) => JS('bool', '# instanceof #', o, type);
sra1 2016/07/20 18:19:20 instanceOf ?
Jacob 2016/07/22 19:28:24 ran it by Bob and he thinks it is reasonable to st
+ static callConstructor(Function constr, List arguments) {
+ if (arguments == null) {
+ return JS('Object', 'new #()', constr);
+ }
+
+ if (JS('bool', '# instanceof Array', arguments)) {
+ int argumentCount = JS('int', '#.length', arguments);
+ switch (argumentCount) {
+ case 0:
+ return JS('Object', 'new #()', constr);
+
+ case 1:
+ var arg0 = JS('', '#[0]', arguments);
+ return JS('Object', 'new #(#)', constr, arg0);
+
+ case 2:
+ var arg0 = JS('', '#[0]', arguments);
+ var arg1 = JS('', '#[1]', arguments);
+ return JS('Object', 'new #(#, #)', constr, arg0, arg1);
+
+ case 3:
+ var arg0 = JS('', '#[0]', arguments);
+ var arg1 = JS('', '#[1]', arguments);
+ var arg2 = JS('', '#[2]', arguments);
+ return JS('Object', 'new #(#, #, #)', constr, arg0, arg1, arg2);
+
+ case 4:
+ var arg0 = JS('', '#[0]', arguments);
+ var arg1 = JS('', '#[1]', arguments);
+ var arg2 = JS('', '#[2]', arguments);
+ var arg3 = JS('', '#[3]', arguments);
+ return JS(
+ 'Object', 'new #(#, #, #, #)', constr, arg0, arg1, arg2, arg3);
+ }
+ }
+
+ // The following code solves the problem of invoking a JavaScript
+ // constructor with an unknown number arguments.
+ // First bind the constructor to the argument list using bind.apply().
+ // The first argument to bind() is the binding of 'this', so add 'null' to
+ // the arguments list passed to apply().
+ // After that, use the JavaScript 'new' operator which overrides any binding
+ // of 'this' with the new instance.
+ var args = [null]..addAll(arguments);
+ var factoryFunction = JS('', '#.bind.apply(#, #)', constr, constr, args);
+ // Without this line, calling factoryFunction as a constructor throws
+ JS('String', 'String(#)', factoryFunction);
+ // This could return an UnknownJavaScriptObject, or a native
+ // object for which there is an interceptor
+ return JS('Object', 'new #()', factoryFunction);
+
+ // TODO(sra): Investigate:
+ //
+ // var jsObj = JS('', 'Object.create(#.prototype)', constr);
+ // JS('', '#.apply(#, #)', constr, jsObj,
+ // []..addAll(arguments.map(_convertToJS)));
+ // return _wrapToDart(jsObj);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698