Merge pull request #37 from google/0.3.6

expose additional domains and methods; ready for 0.3.6 publish
diff --git a/changelog.md b/changelog.md
index 34235f1..a4ca4b3 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,8 @@
 # webkit_inspection_protocol.dart
 
+## 0.3.6
+- Expose the `target` domain and additional `runtime` domain calls
+
 ## 0.3.5
 - Widen the Dart SDK constraint
 
diff --git a/lib/src/runtime.dart b/lib/src/runtime.dart
index 076ee47..52be94b 100644
--- a/lib/src/runtime.dart
+++ b/lib/src/runtime.dart
@@ -10,8 +10,59 @@
   WipRuntime(WipConnection connection) : super(connection);
 
   Future enable() => sendCommand('Runtime.enable');
+
   Future disable() => sendCommand('Runtime.disable');
 
+  /// Evaluates expression on global object.
+  Future<RemoteObject> evaluate(String expression) async {
+    final WipResponse response = await sendCommand('Runtime.evaluate', params: {
+      'expression': expression,
+    });
+
+    if (response.result.containsKey('exceptionDetails')) {
+      throw new ExceptionDetails(response.result['exceptionDetails']);
+    } else {
+      return new RemoteObject(response.result['result']);
+    }
+  }
+
+  /// Calls function with given declaration on the given object. Object group of
+  /// the result is inherited from the target object.
+  Future<RemoteObject> callFunctionOn(
+    String functionDeclaration, {
+    String objectId,
+    int executionContextId,
+    List<dynamic> arguments,
+  }) async {
+    Map<String, dynamic> params = {
+      'functionDeclaration': functionDeclaration,
+    };
+
+    if (objectId != null) {
+      params['objectId'] = objectId;
+    }
+
+    if (executionContextId != null) {
+      params['executionContextId'] = executionContextId;
+    }
+
+    if (objectId != null) {
+      // Convert to a ist of CallArguments.
+      params['arguments'] = arguments.map((dynamic value) {
+        return {'value': value};
+      }).toList();
+    }
+
+    final WipResponse response =
+        await sendCommand('Runtime.callFunctionOn', params: params);
+
+    if (response.result.containsKey('exceptionDetails')) {
+      throw new ExceptionDetails(response.result['exceptionDetails']);
+    } else {
+      return new RemoteObject(response.result['result']);
+    }
+  }
+
   Stream<ConsoleAPIEvent> get onConsoleAPICalled => eventStream(
       'Runtime.consoleAPICalled',
       (WipEvent event) => new ConsoleAPIEvent(event));
@@ -36,7 +87,7 @@
   List<RemoteObject> get args =>
       (params['args'] as List).map((m) => new RemoteObject(m)).toList();
 
-  // TODO: stackTrace, StackTrace, Stack trace captured when the call was made.
+// TODO: stackTrace, StackTrace, Stack trace captured when the call was made.
 }
 
 class ExceptionThrownEvent extends WrappedWipEvent {
@@ -86,7 +137,7 @@
   RemoteObject get exception =>
       _map['exception'] == null ? null : new RemoteObject(_map['exception']);
 
-  String toString() => text;
+  String toString() => '$text, $url, $scriptId, $lineNumber, $exception';
 }
 
 class StackTrace {
@@ -144,13 +195,25 @@
   String toString() => '$functionName() ($url $lineNumber:$columnNumber)';
 }
 
+/// Mirror object referencing original JavaScript object.
 class RemoteObject {
   final Map<String, dynamic> _map;
 
   RemoteObject(this._map);
 
+  /// Object type.object, function, undefined, string, number, boolean, symbol,
+  /// bigint.
   String get type => _map['type'];
+
+  /// Remote object value in case of primitive values or JSON values (if it was
+  /// requested). (optional)
   String get value => _map['value'];
 
+  /// String representation of the object. (optional)
+  String get description => _map['description'];
+
+  /// Unique object identifier (for non-primitive values). (optional)
+  String get objectId => _map['objectId'];
+
   String toString() => '$type $value';
 }
diff --git a/lib/src/target.dart b/lib/src/target.dart
new file mode 100644
index 0000000..82b5cd7
--- /dev/null
+++ b/lib/src/target.dart
@@ -0,0 +1,59 @@
+// Copyright 2018 Google. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import '../webkit_inspection_protocol.dart';
+
+class WipTarget extends WipDomain {
+  WipTarget(WipConnection connection) : super(connection);
+
+  /// Creates a new page.
+  ///
+  /// [url] The initial URL the page will be navigated to.
+  ///
+  /// Returns the targetId of the page opened.
+  Future<String> createTarget(String url) async {
+    WipResponse response =
+        await sendCommand('Target.createTarget', params: {'url': url});
+    return response.result['targetId'];
+  }
+
+  /// Activates (focuses) the target.
+  Future activateTarget(String targetId) =>
+      sendCommand('Target.activateTarget', params: {'targetId': targetId});
+
+  /// Closes the target. If the target is a page that gets closed too.
+  ///
+  /// Returns `true` on success.
+  Future<bool> closeTarget(String targetId) async {
+    WipResponse response =
+        await sendCommand('Target.closeTarget', params: {'targetId': targetId});
+    return response.result['success'];
+  }
+
+  /// Inject object to the target's main frame that provides a communication
+  /// channel with browser target. Injected object will be available as
+  /// `window[bindingName]`. The object has the following API:
+  ///
+  ///  - binding.send(json) - a method to send messages over the remote
+  ///    debugging protocol
+  ///  - binding.onmessage = json => handleMessage(json) - a callback that will
+  ///    be called for the protocol notifications and command responses.
+  @experimental
+  Future<void> exposeDevToolsProtocol(
+    String targetId, {
+    String bindingName,
+  }) async {
+    final Map<String, dynamic> params = {'targetId': targetId};
+    if (bindingName != null) {
+      params['bindingName'] = bindingName;
+    }
+    final WipResponse response = await sendCommand(
+      'Target.exposeDevToolsProtocol',
+      params: params,
+    );
+    dynamic foo = await response.result['targetId'];
+    print(foo);
+  }
+}
diff --git a/lib/webkit_inspection_protocol.dart b/lib/webkit_inspection_protocol.dart
index a8e525d..41688f8 100644
--- a/lib/webkit_inspection_protocol.dart
+++ b/lib/webkit_inspection_protocol.dart
@@ -1,9 +1,7 @@
 // Copyright 2015 Google. All rights reserved. Use of this source code is
 // governed by a BSD-style license that can be found in the LICENSE file.
 
-/**
- * A library to connect to a Webkit Inspection Protocol server (like Chrome).
- */
+/// A library to connect to a Webkit Inspection Protocol server (like Chrome).
 library wip;
 
 import 'dart:async';
@@ -18,6 +16,7 @@
 import 'src/log.dart';
 import 'src/page.dart';
 import 'src/runtime.dart';
+import 'src/target.dart';
 
 export 'src/console.dart';
 export 'src/debugger.dart';
@@ -25,6 +24,7 @@
 export 'src/log.dart';
 export 'src/page.dart';
 export 'src/runtime.dart';
+export 'src/target.dart';
 
 /**
  * A class to connect to a Chrome instance and reflect on its available tabs.
@@ -89,7 +89,9 @@
   ChromeTab(this._map);
 
   String get description => _map['description'];
+
   String get devtoolsFrontendUrl => _map['devtoolsFrontendUrl'];
+
   String get faviconUrl => _map['faviconUrl'];
 
   /// Ex. `E1999E8A-EE27-0450-9900-5BFF4C69CA83`.
@@ -106,7 +108,9 @@
   String get webSocketDebuggerUrl => _map['webSocketDebuggerUrl'];
 
   bool get hasIcon => _map.containsKey('faviconUrl');
+
   bool get isChromeExtension => url.startsWith('chrome-extension://');
+
   bool get isBackgroundPage => type == 'background_page';
 
   Future<WipConnection> connect() =>
@@ -135,18 +139,27 @@
   WipConsole get console => _console;
 
   WipDebugger _debugger;
+
   WipDebugger get debugger => _debugger;
 
   WipDom _dom;
+
   WipDom get dom => _dom;
 
   WipPage _page;
+
   WipPage get page => _page;
 
+  WipTarget _target;
+
+  WipTarget get target => _target;
+
   WipLog _log;
+
   WipLog get log => _log;
 
   WipRuntime _runtime;
+
   WipRuntime get runtime => _runtime;
 
   final Map _completers = <int, Completer<WipResponse>>{};
@@ -167,6 +180,7 @@
     _debugger = new WipDebugger(this);
     _dom = new WipDom(this);
     _page = new WipPage(this);
+    _target = new WipTarget(this);
     _log = new WipLog(this);
     _runtime = new WipRuntime(this);
 
@@ -182,6 +196,7 @@
   }
 
   Stream<WipConnection> get onClose => _closeController.stream;
+
   Stream<WipEvent> get onNotification => _notificationController.stream;
 
   Future close() => _ws.close();
@@ -268,6 +283,7 @@
 
   final WipConnection connection;
   var _onClosed;
+
   Stream<WipDomain> get onClosed => _onClosed;
 
   WipDomain(WipConnection connection) : this.connection = connection {
@@ -309,3 +325,9 @@
   @override
   Map<String, dynamic> get params => _wrapped.params;
 }
+
+const _Experimental experimental = const _Experimental();
+
+class _Experimental {
+  const _Experimental();
+}
diff --git a/pubspec.yaml b/pubspec.yaml
index e87fc81..1e7b1ca 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: webkit_inspection_protocol
-version: 0.3.5
+version: 0.3.6
 description: A client for the Webkit Inspection Protocol (WIP).
 
 homepage: https://github.com/google/webkit_inspection_protocol.dart