blob: 691751cb76f27e9e9faa241ff62745fa17caee48 [file] [log] [blame]
/*
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @unrestricted
*/
export default class RuntimeModel extends SDK.SDKModel {
/**
* @param {!SDK.Target} target
*/
constructor(target) {
super(target);
this._agent = target.runtimeAgent();
this.target().registerRuntimeDispatcher(new RuntimeDispatcher(this));
this._agent.enable();
/** @type {!Map<number, !ExecutionContext>} */
this._executionContextById = new Map();
this._executionContextComparator = ExecutionContext.comparator;
/** @type {?boolean} */
this._hasSideEffectSupport = null;
if (Common.moduleSetting('customFormatters').get()) {
this._agent.setCustomObjectFormatterEnabled(true);
}
Common.moduleSetting('customFormatters').addChangeListener(this._customFormattersStateChanged.bind(this));
}
/**
* @param {!SDK.RuntimeModel.EvaluationResult} response
* @return {boolean}
*/
static isSideEffectFailure(response) {
const exceptionDetails = !response[Protocol.Error] && response.exceptionDetails;
return !!(
exceptionDetails && exceptionDetails.exception && exceptionDetails.exception.description &&
exceptionDetails.exception.description.startsWith('EvalError: Possible side-effect in debug-evaluate'));
}
/**
* @return {!SDK.DebuggerModel}
*/
debuggerModel() {
return /** @type {!SDK.DebuggerModel} */ (this.target().model(SDK.DebuggerModel));
}
/**
* @return {!SDK.HeapProfilerModel}
*/
heapProfilerModel() {
return /** @type {!SDK.HeapProfilerModel} */ (this.target().model(SDK.HeapProfilerModel));
}
/**
* @return {!Array.<!ExecutionContext>}
*/
executionContexts() {
return this._executionContextById.valuesArray().sort(this.executionContextComparator());
}
/**
* @param {function(!ExecutionContext,!ExecutionContext)} comparator
*/
setExecutionContextComparator(comparator) {
this._executionContextComparator = comparator;
}
/**
* @return {function(!ExecutionContext,!ExecutionContext)} comparator
*/
executionContextComparator() {
return this._executionContextComparator;
}
/**
* @return {?ExecutionContext}
*/
defaultExecutionContext() {
for (const context of this.executionContexts()) {
if (context.isDefault) {
return context;
}
}
return null;
}
/**
* @param {!Protocol.Runtime.ExecutionContextId} id
* @return {?ExecutionContext}
*/
executionContext(id) {
return this._executionContextById.get(id) || null;
}
/**
* @param {!Protocol.Runtime.ExecutionContextDescription} context
*/
_executionContextCreated(context) {
const data = context.auxData || {isDefault: true};
const executionContext =
new ExecutionContext(this, context.id, context.name, context.origin, data['isDefault'], data['frameId']);
this._executionContextById.set(executionContext.id, executionContext);
this.dispatchEventToListeners(Events.ExecutionContextCreated, executionContext);
}
/**
* @param {number} executionContextId
*/
_executionContextDestroyed(executionContextId) {
const executionContext = this._executionContextById.get(executionContextId);
if (!executionContext) {
return;
}
this.debuggerModel().executionContextDestroyed(executionContext);
this._executionContextById.delete(executionContextId);
this.dispatchEventToListeners(Events.ExecutionContextDestroyed, executionContext);
}
fireExecutionContextOrderChanged() {
this.dispatchEventToListeners(Events.ExecutionContextOrderChanged, this);
}
_executionContextsCleared() {
this.debuggerModel().globalObjectCleared();
const contexts = this.executionContexts();
this._executionContextById.clear();
for (let i = 0; i < contexts.length; ++i) {
this.dispatchEventToListeners(Events.ExecutionContextDestroyed, contexts[i]);
}
}
/**
* @param {!Protocol.Runtime.RemoteObject} payload
* @return {!SDK.RemoteObject}
*/
createRemoteObject(payload) {
console.assert(typeof payload === 'object', 'Remote object payload should only be an object');
return new SDK.RemoteObjectImpl(
this, payload.objectId, payload.type, payload.subtype, payload.value, payload.unserializableValue,
payload.description, payload.preview, payload.customPreview, payload.className);
}
/**
* @param {!Protocol.Runtime.RemoteObject} payload
* @param {!SDK.ScopeRef} scopeRef
* @return {!SDK.RemoteObject}
*/
createScopeRemoteObject(payload, scopeRef) {
return new SDK.ScopeRemoteObject(
this, payload.objectId, scopeRef, payload.type, payload.subtype, payload.value, payload.unserializableValue,
payload.description, payload.preview);
}
/**
* @param {number|string|boolean|undefined|bigint} value
* @return {!SDK.RemoteObject}
*/
createRemoteObjectFromPrimitiveValue(value) {
const type = typeof value;
let unserializableValue = undefined;
const unserializableDescription = SDK.RemoteObject.unserializableDescription(value);
if (unserializableDescription !== null) {
unserializableValue = /** @type {!Protocol.Runtime.UnserializableValue} */ (unserializableDescription);
}
if (typeof unserializableValue !== 'undefined') {
value = undefined;
}
return new SDK.RemoteObjectImpl(this, undefined, type, undefined, value, unserializableValue);
}
/**
* @param {string} name
* @param {number|string|boolean} value
* @return {!SDK.RemoteObjectProperty}
*/
createRemotePropertyFromPrimitiveValue(name, value) {
return new SDK.RemoteObjectProperty(name, this.createRemoteObjectFromPrimitiveValue(value));
}
discardConsoleEntries() {
this._agent.discardConsoleEntries();
}
/**
* @param {string} objectGroupName
*/
releaseObjectGroup(objectGroupName) {
this._agent.releaseObjectGroup(objectGroupName);
}
/**
* @param {!SDK.RuntimeModel.EvaluationResult} result
*/
releaseEvaluationResult(result) {
if (result.object) {
result.object.release();
}
if (result.exceptionDetails && result.exceptionDetails.exception) {
const exception = result.exceptionDetails.exception;
const exceptionObject = this.createRemoteObject({type: exception.type, objectId: exception.objectId});
exceptionObject.release();
}
}
runIfWaitingForDebugger() {
this._agent.runIfWaitingForDebugger();
}
/**
* @param {!Common.Event} event
*/
_customFormattersStateChanged(event) {
const enabled = /** @type {boolean} */ (event.data);
this._agent.setCustomObjectFormatterEnabled(enabled);
}
/**
* @param {string} expression
* @param {string} sourceURL
* @param {boolean} persistScript
* @param {number} executionContextId
* @return {!Promise<?SDK.RuntimeModel.CompileScriptResult>}
*/
async compileScript(expression, sourceURL, persistScript, executionContextId) {
const response = await this._agent.invoke_compileScript({
expression: String.escapeInvalidUnicodeCharacters(expression),
sourceURL: sourceURL,
persistScript: persistScript,
executionContextId: executionContextId
});
if (response[Protocol.Error]) {
console.error(response[Protocol.Error]);
return null;
}
return {scriptId: response.scriptId, exceptionDetails: response.exceptionDetails};
}
/**
* @param {!Protocol.Runtime.ScriptId} scriptId
* @param {number} executionContextId
* @param {string=} objectGroup
* @param {boolean=} silent
* @param {boolean=} includeCommandLineAPI
* @param {boolean=} returnByValue
* @param {boolean=} generatePreview
* @param {boolean=} awaitPromise
* @return {!Promise<!SDK.RuntimeModel.EvaluationResult>}
*/
async runScript(
scriptId, executionContextId, objectGroup, silent, includeCommandLineAPI, returnByValue, generatePreview,
awaitPromise) {
const response = await this._agent.invoke_runScript({
scriptId,
executionContextId,
objectGroup,
silent,
includeCommandLineAPI,
returnByValue,
generatePreview,
awaitPromise
});
const error = response[Protocol.Error];
if (error) {
console.error(error);
return {error: error};
}
return {object: this.createRemoteObject(response.result), exceptionDetails: response.exceptionDetails};
}
/**
* @param {!SDK.RemoteObject} prototype
* @return {!Promise<!SDK.RuntimeModel.QueryObjectResult>}
*/
async queryObjects(prototype) {
if (!prototype.objectId) {
return {error: 'Prototype should be an Object.'};
}
const response = await this._agent.invoke_queryObjects(
{prototypeObjectId: /** @type {string} */ (prototype.objectId), objectGroup: 'console'});
const error = response[Protocol.Error];
if (error) {
console.error(error);
return {error: error};
}
return {objects: this.createRemoteObject(response.objects)};
}
/**
* @return {!Promise<string>}
*/
async isolateId() {
return (await this._agent.getIsolateId()) || this.target().id();
}
/**
* @return {!Promise<?{usedSize: number, totalSize: number}>}
*/
async heapUsage() {
const result = await this._agent.invoke_getHeapUsage({});
return result[Protocol.Error] ? null : result;
}
/**
* @param {!Protocol.Runtime.RemoteObject} payload
* @param {!Object=} hints
*/
_inspectRequested(payload, hints) {
const object = this.createRemoteObject(payload);
if (hints.copyToClipboard) {
this._copyRequested(object);
return;
}
if (hints.queryObjects) {
this._queryObjectsRequested(object);
return;
}
if (object.isNode()) {
Common.Revealer.reveal(object).then(object.release.bind(object));
return;
}
if (object.type === 'function') {
SDK.RemoteFunction.objectAsFunction(object).targetFunctionDetails().then(didGetDetails);
return;
}
/**
* @param {?SDK.DebuggerModel.FunctionDetails} response
*/
function didGetDetails(response) {
object.release();
if (!response || !response.location) {
return;
}
Common.Revealer.reveal(response.location);
}
object.release();
}
/**
* @param {!SDK.RemoteObject} object
*/
_copyRequested(object) {
if (!object.objectId) {
Host.InspectorFrontendHost.copyText(object.unserializableValue() || /** @type {string} */ (object.value));
return;
}
object.callFunctionJSON(toStringForClipboard, [{value: object.subtype}])
.then(Host.InspectorFrontendHost.copyText.bind(Host.InspectorFrontendHost));
/**
* @param {string} subtype
* @this {Object}
* @suppressReceiverCheck
*/
function toStringForClipboard(subtype) {
if (subtype === 'node') {
return this.outerHTML;
}
if (subtype && typeof this === 'undefined') {
return subtype + '';
}
try {
return JSON.stringify(this, null, ' ');
} catch (e) {
return '' + this;
}
}
}
/**
* @param {!SDK.RemoteObject} object
*/
async _queryObjectsRequested(object) {
const result = await this.queryObjects(object);
object.release();
if (result.error) {
Common.console.error(result.error);
return;
}
this.dispatchEventToListeners(Events.QueryObjectRequested, {objects: result.objects});
}
/**
* @param {!Protocol.Runtime.ExceptionDetails} exceptionDetails
* @return {string}
*/
static simpleTextFromException(exceptionDetails) {
let text = exceptionDetails.text;
if (exceptionDetails.exception && exceptionDetails.exception.description) {
let description = exceptionDetails.exception.description;
if (description.indexOf('\n') !== -1) {
description = description.substring(0, description.indexOf('\n'));
}
text += ' ' + description;
}
return text;
}
/**
* @param {number} timestamp
* @param {!Protocol.Runtime.ExceptionDetails} exceptionDetails
*/
exceptionThrown(timestamp, exceptionDetails) {
const exceptionWithTimestamp = {timestamp: timestamp, details: exceptionDetails};
this.dispatchEventToListeners(Events.ExceptionThrown, exceptionWithTimestamp);
}
/**
* @param {number} exceptionId
*/
_exceptionRevoked(exceptionId) {
this.dispatchEventToListeners(Events.ExceptionRevoked, exceptionId);
}
/**
* @param {string} type
* @param {!Array.<!Protocol.Runtime.RemoteObject>} args
* @param {number} executionContextId
* @param {number} timestamp
* @param {!Protocol.Runtime.StackTrace=} stackTrace
* @param {string=} context
*/
_consoleAPICalled(type, args, executionContextId, timestamp, stackTrace, context) {
const consoleAPICall = {
type: type,
args: args,
executionContextId: executionContextId,
timestamp: timestamp,
stackTrace: stackTrace,
context: context
};
this.dispatchEventToListeners(Events.ConsoleAPICalled, consoleAPICall);
}
/**
* @param {!Protocol.Runtime.ScriptId} scriptId
* @return {number}
*/
executionContextIdForScriptId(scriptId) {
const script = this.debuggerModel().scriptForId(scriptId);
return script ? script.executionContextId : 0;
}
/**
* @param {!Protocol.Runtime.StackTrace} stackTrace
* @return {number}
*/
executionContextForStackTrace(stackTrace) {
while (stackTrace && !stackTrace.callFrames.length) {
stackTrace = stackTrace.parent;
}
if (!stackTrace || !stackTrace.callFrames.length) {
return 0;
}
return this.executionContextIdForScriptId(stackTrace.callFrames[0].scriptId);
}
/**
* @return {?boolean}
*/
hasSideEffectSupport() {
return this._hasSideEffectSupport;
}
/**
* @return {!Promise<boolean>}
*/
async checkSideEffectSupport() {
const testContext = this.executionContexts().peekLast();
if (!testContext) {
return false;
}
// Check for a positive throwOnSideEffect response without triggering side effects.
const response = await this._agent.invoke_evaluate({
expression: String.escapeInvalidUnicodeCharacters(_sideEffectTestExpression),
contextId: testContext.id,
throwOnSideEffect: true
});
this._hasSideEffectSupport = RuntimeModel.isSideEffectFailure(response);
return this._hasSideEffectSupport;
}
/**
* @return {!Promise}
*/
terminateExecution() {
return this._agent.invoke_terminateExecution({});
}
}
/**
* This expression:
* - IMPORTANT: must not actually cause user-visible or JS-visible side-effects.
* - Must throw when evaluated with `throwOnSideEffect: true`.
* - Must be valid when run from any ExecutionContext that supports `throwOnSideEffect`.
* @const
* @type {string}
*/
const _sideEffectTestExpression = '(async function(){ await 1; })()';
/** @enum {symbol} */
export const Events = {
ExecutionContextCreated: Symbol('ExecutionContextCreated'),
ExecutionContextDestroyed: Symbol('ExecutionContextDestroyed'),
ExecutionContextChanged: Symbol('ExecutionContextChanged'),
ExecutionContextOrderChanged: Symbol('ExecutionContextOrderChanged'),
ExceptionThrown: Symbol('ExceptionThrown'),
ExceptionRevoked: Symbol('ExceptionRevoked'),
ConsoleAPICalled: Symbol('ConsoleAPICalled'),
QueryObjectRequested: Symbol('QueryObjectRequested'),
};
/**
* @extends {Protocol.RuntimeDispatcher}
* @unrestricted
*/
class RuntimeDispatcher {
/**
* @param {!RuntimeModel} runtimeModel
*/
constructor(runtimeModel) {
this._runtimeModel = runtimeModel;
}
/**
* @override
* @param {!Protocol.Runtime.ExecutionContextDescription} context
*/
executionContextCreated(context) {
this._runtimeModel._executionContextCreated(context);
}
/**
* @override
* @param {!Protocol.Runtime.ExecutionContextId} executionContextId
*/
executionContextDestroyed(executionContextId) {
this._runtimeModel._executionContextDestroyed(executionContextId);
}
/**
* @override
*/
executionContextsCleared() {
this._runtimeModel._executionContextsCleared();
}
/**
* @override
* @param {number} timestamp
* @param {!Protocol.Runtime.ExceptionDetails} exceptionDetails
*/
exceptionThrown(timestamp, exceptionDetails) {
this._runtimeModel.exceptionThrown(timestamp, exceptionDetails);
}
/**
* @override
* @param {string} reason
* @param {number} exceptionId
*/
exceptionRevoked(reason, exceptionId) {
this._runtimeModel._exceptionRevoked(exceptionId);
}
/**
* @override
* @param {string} type
* @param {!Array.<!Protocol.Runtime.RemoteObject>} args
* @param {number} executionContextId
* @param {number} timestamp
* @param {!Protocol.Runtime.StackTrace=} stackTrace
* @param {string=} context
*/
consoleAPICalled(type, args, executionContextId, timestamp, stackTrace, context) {
this._runtimeModel._consoleAPICalled(type, args, executionContextId, timestamp, stackTrace, context);
}
/**
* @override
* @param {!Protocol.Runtime.RemoteObject} payload
* @param {!Object=} hints
*/
inspectRequested(payload, hints) {
this._runtimeModel._inspectRequested(payload, hints);
}
}
/**
* @unrestricted
*/
export class ExecutionContext {
/**
* @param {!RuntimeModel} runtimeModel
* @param {number} id
* @param {string} name
* @param {string} origin
* @param {boolean} isDefault
* @param {string=} frameId
*/
constructor(runtimeModel, id, name, origin, isDefault, frameId) {
this.id = id;
this.name = name;
this.origin = origin;
this.isDefault = isDefault;
this.runtimeModel = runtimeModel;
this.debuggerModel = runtimeModel.debuggerModel();
this.frameId = frameId;
this._setLabel('');
}
/**
* @return {!SDK.Target}
*/
target() {
return this.runtimeModel.target();
}
/**
* @param {!ExecutionContext} a
* @param {!ExecutionContext} b
* @return {number}
*/
static comparator(a, b) {
/**
* @param {!SDK.Target} target
* @return {number}
*/
function targetWeight(target) {
if (!target.parentTarget()) {
return 5;
}
if (target.type() === SDK.Target.Type.Frame) {
return 4;
}
if (target.type() === SDK.Target.Type.ServiceWorker) {
return 3;
}
if (target.type() === SDK.Target.Type.Worker) {
return 2;
}
return 1;
}
/**
* @param {!SDK.Target} target
* @return {!Array<!SDK.Target>}
*/
function targetPath(target) {
let currentTarget = target;
const parents = [];
while (currentTarget) {
parents.push(currentTarget);
currentTarget = currentTarget.parentTarget();
}
return parents.reverse();
}
const tagetsA = targetPath(a.target());
const targetsB = targetPath(b.target());
let targetA;
let targetB;
for (let i = 0;; i++) {
if (!tagetsA[i] || !targetsB[i] || (tagetsA[i] !== targetsB[i])) {
targetA = tagetsA[i];
targetB = targetsB[i];
break;
}
}
if (!targetA && targetB) {
return -1;
}
if (!targetB && targetA) {
return 1;
}
if (targetA && targetB) {
const weightDiff = targetWeight(targetA) - targetWeight(targetB);
if (weightDiff) {
return -weightDiff;
}
return targetA.id().localeCompare(targetB.id());
}
// Main world context should always go first.
if (a.isDefault) {
return -1;
}
if (b.isDefault) {
return +1;
}
return a.name.localeCompare(b.name);
}
/**
* @param {!SDK.RuntimeModel.EvaluationOptions} options
* @param {boolean} userGesture
* @param {boolean} awaitPromise
* @return {!Promise<!SDK.RuntimeModel.EvaluationResult>}
*/
evaluate(options, userGesture, awaitPromise) {
// FIXME: It will be moved to separate ExecutionContext.
if (this.debuggerModel.selectedCallFrame()) {
return this.debuggerModel.evaluateOnSelectedCallFrame(options);
}
// Assume backends either support both throwOnSideEffect and timeout options or neither.
const needsTerminationOptions = !!options.throwOnSideEffect || options.timeout !== undefined;
if (!needsTerminationOptions || this.runtimeModel.hasSideEffectSupport()) {
return this._evaluateGlobal(options, userGesture, awaitPromise);
}
/** @type {!SDK.RuntimeModel.EvaluationResult} */
const unsupportedError = {error: 'Side-effect checks not supported by backend.'};
if (this.runtimeModel.hasSideEffectSupport() === false) {
return Promise.resolve(unsupportedError);
}
return this.runtimeModel.checkSideEffectSupport().then(() => {
if (this.runtimeModel.hasSideEffectSupport()) {
return this._evaluateGlobal(options, userGesture, awaitPromise);
}
return Promise.resolve(unsupportedError);
});
}
/**
* @param {string} objectGroup
* @param {boolean} generatePreview
* @return {!Promise<!SDK.RuntimeModel.EvaluationResult>}
*/
globalObject(objectGroup, generatePreview) {
return this._evaluateGlobal(
{
expression: 'this',
objectGroup: objectGroup,
includeCommandLineAPI: false,
silent: true,
returnByValue: false,
generatePreview: generatePreview
},
/* userGesture */ false, /* awaitPromise */ false);
}
/**
* @param {!SDK.RuntimeModel.EvaluationOptions} options
* @param {boolean} userGesture
* @param {boolean} awaitPromise
* @return {!Promise<!SDK.RuntimeModel.EvaluationResult>}
*/
async _evaluateGlobal(options, userGesture, awaitPromise) {
if (!options.expression) {
// There is no expression, so the completion should happen against global properties.
options.expression = 'this';
}
const response = await this.runtimeModel._agent.invoke_evaluate({
expression: String.escapeInvalidUnicodeCharacters(options.expression),
objectGroup: options.objectGroup,
includeCommandLineAPI: options.includeCommandLineAPI,
silent: options.silent,
contextId: this.id,
returnByValue: options.returnByValue,
generatePreview: options.generatePreview,
userGesture: userGesture,
awaitPromise: awaitPromise,
throwOnSideEffect: options.throwOnSideEffect,
timeout: options.timeout,
disableBreaks: options.disableBreaks,
replMode: options.replMode
});
const error = response[Protocol.Error];
if (error) {
console.error(error);
return {error: error};
}
return {object: this.runtimeModel.createRemoteObject(response.result), exceptionDetails: response.exceptionDetails};
}
/**
* @return {!Promise<?Array<string>>}
*/
async globalLexicalScopeNames() {
const response = await this.runtimeModel._agent.invoke_globalLexicalScopeNames({executionContextId: this.id});
return response[Protocol.Error] ? [] : response.names;
}
/**
* @return {string}
*/
label() {
return this._label;
}
/**
* @param {string} label
*/
setLabel(label) {
this._setLabel(label);
this.runtimeModel.dispatchEventToListeners(Events.ExecutionContextChanged, this);
}
/**
* @param {string} label
*/
_setLabel(label) {
if (label) {
this._label = label;
return;
}
if (this.name) {
this._label = this.name;
return;
}
const parsedUrl = Common.ParsedURL.fromString(this.origin);
this._label = parsedUrl ? parsedUrl.lastPathComponentWithFragment() : '';
}
}
/* Legacy exported object */
self.SDK = self.SDK || {};
/* Legacy exported object */
SDK = SDK || {};
/** @constructor */
SDK.RuntimeModel = RuntimeModel;
/** @enum {symbol} */
SDK.RuntimeModel.Events = Events;
/** @constructor */
SDK.ExecutionContext = ExecutionContext;
/** @typedef {{
* scriptId: (Protocol.Runtime.ScriptId|undefined),
* exceptionDetails: (!Protocol.Runtime.ExceptionDetails|undefined)
* }}
*/
SDK.RuntimeModel.CompileScriptResult;
/** @typedef {{
* expression: string,
* objectGroup: (string|undefined),
* includeCommandLineAPI: (boolean|undefined),
* silent: (boolean|undefined),
* returnByValue: (boolean|undefined),
* generatePreview: (boolean|undefined),
* throwOnSideEffect: (boolean|undefined),
* timeout: (number|undefined),
* disableBreaks: (boolean|undefined),
* replMode: (boolean|undefined)
* }}
*/
SDK.RuntimeModel.EvaluationOptions;
/** @typedef {{
* object: (!SDK.RemoteObject|undefined),
* exceptionDetails: (!Protocol.Runtime.ExceptionDetails|undefined),
* error: (!Protocol.Error|undefined)}
* }}
*/
SDK.RuntimeModel.EvaluationResult;
/** @typedef {{
* objects: (!SDK.RemoteObject|undefined),
* error: (!Protocol.Error|undefined)}
* }}
*/
SDK.RuntimeModel.QueryObjectResult;
/**
* @typedef {{
* type: string,
* args: !Array<!Protocol.Runtime.RemoteObject>,
* executionContextId: number,
* timestamp: number,
* stackTrace: (!Protocol.Runtime.StackTrace|undefined)
* }}
*/
SDK.RuntimeModel.ConsoleAPICall;
/** @typedef {{timestamp: number, details: !Protocol.Runtime.ExceptionDetails}} */
SDK.RuntimeModel.ExceptionWithTimestamp;
SDK.SDKModel.register(SDK.RuntimeModel, SDK.Target.Capability.JS, true);