Files
react-native-devtools-frontend/front_end/object_ui/JavaScriptREPL.js
T
Benedikt Meurer 9278806591 [devtools] Disable debug breaks for live expressions.
For live expressions it doesn't make sense to trigger break points, as
that doesn't match the users expectation of the feature. This commit
uses the newly introduced "disableBreaks" parameters for
"Runtime.evaluate" to suppress break points and explicit `debugger`
statements for live expressions.

Bug: chromium:1001216
Change-Id: Ie331761ca66afb813816c7d31e77085a5637ea8a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1831798
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#701066}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 4078092d5b1faccb2dc7ac0c47c078d7a97f179a
2019-09-30 11:42:14 +00:00

109 lines
3.7 KiB
JavaScript

// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
ObjectUI.JavaScriptREPL = class {
/**
* @param {string} code
* @return {string}
*/
static wrapObjectLiteral(code) {
// Only parenthesize what appears to be an object literal.
if (!(/^\s*\{/.test(code) && /\}\s*$/.test(code)))
return code;
const parse = (async () => 0).constructor;
try {
// Check if the code can be interpreted as an expression.
parse('return ' + code + ';');
// No syntax error! Does it work parenthesized?
const wrappedCode = '(' + code + ')';
parse(wrappedCode);
return wrappedCode;
} catch (e) {
return code;
}
}
/**
* @param {string} text
* @return {!Promise<!{text: string, preprocessed: boolean}>}
*/
static async preprocessExpression(text) {
text = ObjectUI.JavaScriptREPL.wrapObjectLiteral(text);
let preprocessed = false;
if (text.indexOf('await') !== -1) {
const preprocessedText = await Formatter.formatterWorkerPool().preprocessTopLevelAwaitExpressions(text);
preprocessed = !!preprocessedText;
text = preprocessedText || text;
}
return {text, preprocessed};
}
/**
* @param {string} text
* @param {boolean} throwOnSideEffect
* @param {number=} timeout
* @param {boolean=} allowErrors
* @param {string=} objectGroup
* @return {!Promise<!{preview: !DocumentFragment, result: ?SDK.RuntimeModel.EvaluationResult}>}
*/
static async evaluateAndBuildPreview(text, throwOnSideEffect, timeout, allowErrors, objectGroup) {
const executionContext = UI.context.flavor(SDK.ExecutionContext);
const isTextLong = text.length > ObjectUI.JavaScriptREPL._MaxLengthForEvaluation;
if (!text || !executionContext || (throwOnSideEffect && isTextLong))
return {preview: createDocumentFragment(), result: null};
const wrappedResult = await ObjectUI.JavaScriptREPL.preprocessExpression(text);
const options = {
expression: wrappedResult.text,
generatePreview: true,
includeCommandLineAPI: true,
throwOnSideEffect: throwOnSideEffect,
timeout: timeout,
objectGroup: objectGroup,
disableBreaks: true
};
const result = await executionContext.evaluate(
options, false /* userGesture */, wrappedResult.preprocessed /* awaitPromise */);
const preview = ObjectUI.JavaScriptREPL._buildEvaluationPreview(result, allowErrors);
return {preview, result};
}
/**
* @param {!SDK.RuntimeModel.EvaluationResult} result
* @param {boolean=} allowErrors
* @return {!DocumentFragment}
*/
static _buildEvaluationPreview(result, allowErrors) {
const fragment = createDocumentFragment();
if (result.error)
return fragment;
if (result.exceptionDetails && result.exceptionDetails.exception && result.exceptionDetails.exception.description) {
const exception = result.exceptionDetails.exception.description;
if (exception.startsWith('TypeError: ') || allowErrors)
fragment.createChild('span').textContent = result.exceptionDetails.text + ' ' + exception;
return fragment;
}
const formatter = new ObjectUI.RemoteObjectPreviewFormatter();
const {preview, type, subtype, description} = result.object;
if (preview && type === 'object' && subtype !== 'node') {
formatter.appendObjectPreview(fragment, preview, false /* isEntry */);
} else {
const nonObjectPreview = formatter.renderPropertyPreview(type, subtype, description.trimEndWithMaxLength(400));
fragment.appendChild(nonObjectPreview);
}
return fragment;
}
};
/**
* @const
* @type {number}
*/
ObjectUI.JavaScriptREPL._MaxLengthForEvaluation = 2000;