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

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: 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
« no previous file with comments | « pkg/js/pubspec.yaml ('k') | tests/html/js_native_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..01058b3d1844fb657a50fe3f0d9fced94e704b09 100644
--- a/sdk/lib/js/dart2js/js_dart2js.dart
+++ b/sdk/lib/js/dart2js/js_dart2js.dart
@@ -726,3 +726,123 @@ 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 {
+ /**
+ * 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);
Alan Knight 2016/07/19 16:56:04 nit: line length
Jacob 2016/07/19 17:42:19 Done. Ran dartfmt.
+
+ static instanceof(o, Function type) => JS('bool', '# instanceof #', o, type);
+ 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);
Alan Knight 2016/07/19 16:56:04 Also line length
Jacob 2016/07/19 17:42:19 Done.
+ }
+ }
+
+ // 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);
+ }
+}
« no previous file with comments | « pkg/js/pubspec.yaml ('k') | tests/html/js_native_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698