@quick-game/cli
Version:
Command line interface for rapid qg development
667 lines • 31.9 kB
JavaScript
/*
* Copyright (C) 2011 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.
*/
import * as Common from '../common/common.js';
import * as Host from '../host/host.js';
import * as i18n from '../i18n/i18n.js';
import * as Platform from '../platform/platform.js';
import { FrontendMessageSource, FrontendMessageType } from './ConsoleModelTypes.js';
export { FrontendMessageSource, FrontendMessageType } from './ConsoleModelTypes.js';
import { CPUProfilerModel, Events as CPUProfilerModelEvents } from './CPUProfilerModel.js';
import { Events as DebuggerModelEvents, COND_BREAKPOINT_SOURCE_URL, LOGPOINT_SOURCE_URL, } from './DebuggerModel.js';
import { LogModel } from './LogModel.js';
import { RemoteObject } from './RemoteObject.js';
import { Events as ResourceTreeModelEvents, ResourceTreeModel, } from './ResourceTreeModel.js';
import { Events as RuntimeModelEvents, RuntimeModel, } from './RuntimeModel.js';
import { Capability, Type } from './Target.js';
import { TargetManager } from './TargetManager.js';
import { SDKModel } from './SDKModel.js';
const UIStrings = {
/**
*@description Text shown when the main frame (page) of the website was navigated to a different URL.
*@example {https://example.com} PH1
*/
navigatedToS: 'Navigated to {PH1}',
/**
*@description Text shown when the main frame (page) of the website was navigated to a different URL
* and the page was restored from back/forward cache (https://web.dev/bfcache/).
*@example {https://example.com} PH1
*/
bfcacheNavigation: 'Navigation to {PH1} was restored from back/forward cache (see https://web.dev/bfcache/)',
/**
*@description Text shown in the console when a performance profile (with the given name) was started.
*@example {title} PH1
*/
profileSStarted: 'Profile \'\'{PH1}\'\' started.',
/**
*@description Text shown in the console when a performance profile (with the given name) was stopped.
*@example {name} PH1
*/
profileSFinished: 'Profile \'\'{PH1}\'\' finished.',
/**
*@description Error message shown in the console after the user tries to save a JavaScript value to a temporary variable.
*/
failedToSaveToTempVariable: 'Failed to save to temp variable.',
};
const str_ = i18n.i18n.registerUIStrings('core/sdk/ConsoleModel.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
export class ConsoleModel extends SDKModel {
#messagesInternal;
#messagesByTimestamp;
#messageByExceptionId;
#warningsInternal;
#errorsInternal;
#violationsInternal;
#pageLoadSequenceNumber;
#targetListeners;
constructor(target) {
super(target);
this.#messagesInternal = [];
this.#messagesByTimestamp = new Platform.MapUtilities.Multimap();
this.#messageByExceptionId = new Map();
this.#warningsInternal = 0;
this.#errorsInternal = 0;
this.#violationsInternal = 0;
this.#pageLoadSequenceNumber = 0;
this.#targetListeners = new WeakMap();
const resourceTreeModel = target.model(ResourceTreeModel);
if (!resourceTreeModel || resourceTreeModel.cachedResourcesLoaded()) {
this.initTarget(target);
return;
}
const eventListener = resourceTreeModel.addEventListener(ResourceTreeModelEvents.CachedResourcesLoaded, () => {
Common.EventTarget.removeEventListeners([eventListener]);
this.initTarget(target);
});
}
initTarget(target) {
const eventListeners = [];
const cpuProfilerModel = target.model(CPUProfilerModel);
if (cpuProfilerModel) {
eventListeners.push(cpuProfilerModel.addEventListener(CPUProfilerModelEvents.ConsoleProfileStarted, this.consoleProfileStarted.bind(this, cpuProfilerModel)));
eventListeners.push(cpuProfilerModel.addEventListener(CPUProfilerModelEvents.ConsoleProfileFinished, this.consoleProfileFinished.bind(this, cpuProfilerModel)));
}
const resourceTreeModel = target.model(ResourceTreeModel);
if (resourceTreeModel && target.parentTarget()?.type() !== Type.Frame) {
eventListeners.push(resourceTreeModel.addEventListener(ResourceTreeModelEvents.PrimaryPageChanged, this.primaryPageChanged, this));
}
const runtimeModel = target.model(RuntimeModel);
if (runtimeModel) {
eventListeners.push(runtimeModel.addEventListener(RuntimeModelEvents.ExceptionThrown, this.exceptionThrown.bind(this, runtimeModel)));
eventListeners.push(runtimeModel.addEventListener(RuntimeModelEvents.ExceptionRevoked, this.exceptionRevoked.bind(this, runtimeModel)));
eventListeners.push(runtimeModel.addEventListener(RuntimeModelEvents.ConsoleAPICalled, this.consoleAPICalled.bind(this, runtimeModel)));
if (target.parentTarget()?.type() !== Type.Frame) {
eventListeners.push(runtimeModel.debuggerModel().addEventListener(DebuggerModelEvents.GlobalObjectCleared, this.clearIfNecessary, this));
}
eventListeners.push(runtimeModel.addEventListener(RuntimeModelEvents.QueryObjectRequested, this.queryObjectRequested.bind(this, runtimeModel)));
}
this.#targetListeners.set(target, eventListeners);
}
targetRemoved(target) {
const runtimeModel = target.model(RuntimeModel);
if (runtimeModel) {
this.#messageByExceptionId.delete(runtimeModel);
}
Common.EventTarget.removeEventListeners(this.#targetListeners.get(target) || []);
}
async evaluateCommandInConsole(executionContext, originatingMessage, expression, useCommandLineAPI) {
const result = await executionContext.evaluate({
expression,
objectGroup: 'console',
includeCommandLineAPI: useCommandLineAPI,
silent: false,
returnByValue: false,
generatePreview: true,
replMode: true,
allowUnsafeEvalBlockedByCSP: false,
}, Common.Settings.Settings.instance().moduleSetting('consoleUserActivationEval').get(), /* awaitPromise */ false);
Host.userMetrics.actionTaken(Host.UserMetrics.Action.ConsoleEvaluated);
if ('error' in result) {
return;
}
await Common.Console.Console.instance().showPromise();
this.dispatchEventToListeners(Events.CommandEvaluated, { result: result.object, commandMessage: originatingMessage, exceptionDetails: result.exceptionDetails });
}
addCommandMessage(executionContext, text) {
const commandMessage = new ConsoleMessage(executionContext.runtimeModel, "javascript" /* Protocol.Log.LogEntrySource.Javascript */, null, text, { type: FrontendMessageType.Command });
commandMessage.setExecutionContextId(executionContext.id);
this.addMessage(commandMessage);
return commandMessage;
}
addMessage(msg) {
msg.setPageLoadSequenceNumber(this.#pageLoadSequenceNumber);
if (msg.source === FrontendMessageSource.ConsoleAPI &&
msg.type === "clear" /* Protocol.Runtime.ConsoleAPICalledEventType.Clear */) {
this.clearIfNecessary();
}
this.#messagesInternal.push(msg);
this.#messagesByTimestamp.set(msg.timestamp, msg);
const runtimeModel = msg.runtimeModel();
const exceptionId = msg.getExceptionId();
if (exceptionId && runtimeModel) {
let modelMap = this.#messageByExceptionId.get(runtimeModel);
if (!modelMap) {
modelMap = new Map();
this.#messageByExceptionId.set(runtimeModel, modelMap);
}
modelMap.set(exceptionId, msg);
}
this.incrementErrorWarningCount(msg);
this.dispatchEventToListeners(Events.MessageAdded, msg);
}
exceptionThrown(runtimeModel, event) {
const exceptionWithTimestamp = event.data;
const affectedResources = extractExceptionMetaData(exceptionWithTimestamp.details.exceptionMetaData);
const consoleMessage = ConsoleMessage.fromException(runtimeModel, exceptionWithTimestamp.details, undefined, exceptionWithTimestamp.timestamp, undefined, affectedResources);
consoleMessage.setExceptionId(exceptionWithTimestamp.details.exceptionId);
this.addMessage(consoleMessage);
}
exceptionRevoked(runtimeModel, event) {
const exceptionId = event.data;
const modelMap = this.#messageByExceptionId.get(runtimeModel);
const exceptionMessage = modelMap ? modelMap.get(exceptionId) : null;
if (!exceptionMessage) {
return;
}
this.#errorsInternal--;
exceptionMessage.level = "verbose" /* Protocol.Log.LogEntryLevel.Verbose */;
this.dispatchEventToListeners(Events.MessageUpdated, exceptionMessage);
}
consoleAPICalled(runtimeModel, event) {
const call = event.data;
let level = "info" /* Protocol.Log.LogEntryLevel.Info */;
if (call.type === "debug" /* Protocol.Runtime.ConsoleAPICalledEventType.Debug */) {
level = "verbose" /* Protocol.Log.LogEntryLevel.Verbose */;
}
else if (call.type === "error" /* Protocol.Runtime.ConsoleAPICalledEventType.Error */ ||
call.type === "assert" /* Protocol.Runtime.ConsoleAPICalledEventType.Assert */) {
level = "error" /* Protocol.Log.LogEntryLevel.Error */;
}
else if (call.type === "warning" /* Protocol.Runtime.ConsoleAPICalledEventType.Warning */) {
level = "warning" /* Protocol.Log.LogEntryLevel.Warning */;
}
else if (call.type === "info" /* Protocol.Runtime.ConsoleAPICalledEventType.Info */ ||
call.type === "log" /* Protocol.Runtime.ConsoleAPICalledEventType.Log */) {
level = "info" /* Protocol.Log.LogEntryLevel.Info */;
}
let message = '';
if (call.args.length && call.args[0].unserializableValue) {
message = call.args[0].unserializableValue;
}
else if (call.args.length && (typeof call.args[0].value !== 'object' || call.args[0].value === null)) {
message = String(call.args[0].value);
}
else if (call.args.length && call.args[0].description) {
message = call.args[0].description;
}
const callFrame = call.stackTrace && call.stackTrace.callFrames.length ? call.stackTrace.callFrames[0] : null;
const details = {
type: call.type,
url: callFrame?.url,
line: callFrame?.lineNumber,
column: callFrame?.columnNumber,
parameters: call.args,
stackTrace: call.stackTrace,
timestamp: call.timestamp,
executionContextId: call.executionContextId,
context: call.context,
};
const consoleMessage = new ConsoleMessage(runtimeModel, FrontendMessageSource.ConsoleAPI, level, message, details);
for (const msg of this.#messagesByTimestamp.get(consoleMessage.timestamp).values()) {
if (consoleMessage.isEqual(msg)) {
return;
}
}
this.addMessage(consoleMessage);
}
queryObjectRequested(runtimeModel, event) {
const { objects, executionContextId } = event.data;
const details = {
type: FrontendMessageType.QueryObjectResult,
parameters: [objects],
executionContextId,
};
const consoleMessage = new ConsoleMessage(runtimeModel, FrontendMessageSource.ConsoleAPI, "info" /* Protocol.Log.LogEntryLevel.Info */, '', details);
this.addMessage(consoleMessage);
}
clearIfNecessary() {
if (!Common.Settings.Settings.instance().moduleSetting('preserveConsoleLog').get()) {
this.clear();
}
++this.#pageLoadSequenceNumber;
}
primaryPageChanged(event) {
if (Common.Settings.Settings.instance().moduleSetting('preserveConsoleLog').get()) {
const { frame } = event.data;
if (frame.backForwardCacheDetails.restoredFromCache) {
Common.Console.Console.instance().log(i18nString(UIStrings.bfcacheNavigation, { PH1: frame.url }));
}
else {
Common.Console.Console.instance().log(i18nString(UIStrings.navigatedToS, { PH1: frame.url }));
}
}
}
consoleProfileStarted(cpuProfilerModel, event) {
const { data } = event;
this.addConsoleProfileMessage(cpuProfilerModel, "profile" /* Protocol.Runtime.ConsoleAPICalledEventType.Profile */, data.scriptLocation, i18nString(UIStrings.profileSStarted, { PH1: data.title }));
}
consoleProfileFinished(cpuProfilerModel, event) {
const { data } = event;
this.addConsoleProfileMessage(cpuProfilerModel, "profileEnd" /* Protocol.Runtime.ConsoleAPICalledEventType.ProfileEnd */, data.scriptLocation, i18nString(UIStrings.profileSFinished, { PH1: data.title }));
}
addConsoleProfileMessage(cpuProfilerModel, type, scriptLocation, messageText) {
const script = scriptLocation.script();
const callFrames = [{
functionName: '',
scriptId: scriptLocation.scriptId,
url: script ? script.contentURL() : '',
lineNumber: scriptLocation.lineNumber,
columnNumber: scriptLocation.columnNumber || 0,
}];
this.addMessage(new ConsoleMessage(cpuProfilerModel.runtimeModel(), FrontendMessageSource.ConsoleAPI, "info" /* Protocol.Log.LogEntryLevel.Info */, messageText, { type, stackTrace: { callFrames } }));
}
incrementErrorWarningCount(msg) {
if (msg.source === "violation" /* Protocol.Log.LogEntrySource.Violation */) {
this.#violationsInternal++;
return;
}
switch (msg.level) {
case "warning" /* Protocol.Log.LogEntryLevel.Warning */:
this.#warningsInternal++;
break;
case "error" /* Protocol.Log.LogEntryLevel.Error */:
this.#errorsInternal++;
break;
}
}
messages() {
return this.#messagesInternal;
}
// messages[] are not ordered by timestamp.
static allMessagesUnordered() {
const messages = [];
for (const target of TargetManager.instance().targets()) {
const targetMessages = target.model(ConsoleModel)?.messages() || [];
messages.push(...targetMessages);
}
return messages;
}
static requestClearMessages() {
for (const logModel of TargetManager.instance().models(LogModel)) {
logModel.requestClear();
}
for (const runtimeModel of TargetManager.instance().models(RuntimeModel)) {
runtimeModel.discardConsoleEntries();
}
for (const target of TargetManager.instance().targets()) {
target.model(ConsoleModel)?.clear();
}
}
clear() {
this.#messagesInternal = [];
this.#messagesByTimestamp.clear();
this.#messageByExceptionId.clear();
this.#errorsInternal = 0;
this.#warningsInternal = 0;
this.#violationsInternal = 0;
this.dispatchEventToListeners(Events.ConsoleCleared);
}
errors() {
return this.#errorsInternal;
}
static allErrors() {
let errors = 0;
for (const target of TargetManager.instance().targets()) {
errors += target.model(ConsoleModel)?.errors() || 0;
}
return errors;
}
warnings() {
return this.#warningsInternal;
}
static allWarnings() {
let warnings = 0;
for (const target of TargetManager.instance().targets()) {
warnings += target.model(ConsoleModel)?.warnings() || 0;
}
return warnings;
}
violations() {
return this.#violationsInternal;
}
static allViolations() {
let violations = 0;
for (const target of TargetManager.instance().targets()) {
violations += target.model(ConsoleModel)?.violations() || 0;
}
return violations;
}
async saveToTempVariable(currentExecutionContext, remoteObject) {
if (!remoteObject || !currentExecutionContext) {
failedToSave(null);
return;
}
const executionContext = currentExecutionContext;
const result = await executionContext.globalObject(/* objectGroup */ '', /* generatePreview */ false);
if ('error' in result || Boolean(result.exceptionDetails) || !result.object) {
failedToSave('object' in result && result.object || null);
return;
}
const globalObject = result.object;
const callFunctionResult =
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// @ts-expect-error
await globalObject.callFunction(saveVariable, [RemoteObject.toCallArgument(remoteObject)]);
globalObject.release();
if (callFunctionResult.wasThrown || !callFunctionResult.object || callFunctionResult.object.type !== 'string') {
failedToSave(callFunctionResult.object || null);
}
else {
const text = callFunctionResult.object.value;
const message = this.addCommandMessage(executionContext, text);
void this.evaluateCommandInConsole(executionContext, message, text, /* useCommandLineAPI */ false);
}
if (callFunctionResult.object) {
callFunctionResult.object.release();
}
function saveVariable(value) {
const prefix = 'temp';
let index = 1;
while ((prefix + index) in this) {
++index;
}
const name = prefix + index;
// @ts-ignore Assignment to global object
this[name] = value;
return name;
}
function failedToSave(result) {
let message = i18nString(UIStrings.failedToSaveToTempVariable);
if (result) {
message = message + ' ' + result.description;
}
Common.Console.Console.instance().error(message);
}
}
}
// TODO(crbug.com/1167717): Make this a const enum again
// eslint-disable-next-line rulesdir/const_enum
export var Events;
(function (Events) {
Events["ConsoleCleared"] = "ConsoleCleared";
Events["MessageAdded"] = "MessageAdded";
Events["MessageUpdated"] = "MessageUpdated";
Events["CommandEvaluated"] = "CommandEvaluated";
})(Events || (Events = {}));
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function extractExceptionMetaData(metaData) {
if (!metaData) {
return undefined;
}
return { requestId: metaData.requestId || undefined, issueId: metaData.issueId || undefined };
}
function areAffectedResourcesEquivalent(a, b) {
// Not considering issueId, as that would prevent de-duplication of console #messages.
return a?.requestId === b?.requestId;
}
function areStackTracesEquivalent(stackTrace1, stackTrace2) {
if (!stackTrace1 !== !stackTrace2) {
return false;
}
if (!stackTrace1 || !stackTrace2) {
return true;
}
const callFrames1 = stackTrace1.callFrames;
const callFrames2 = stackTrace2.callFrames;
if (callFrames1.length !== callFrames2.length) {
return false;
}
for (let i = 0, n = callFrames1.length; i < n; ++i) {
if (callFrames1[i].scriptId !== callFrames2[i].scriptId ||
callFrames1[i].functionName !== callFrames2[i].functionName ||
callFrames1[i].lineNumber !== callFrames2[i].lineNumber ||
callFrames1[i].columnNumber !== callFrames2[i].columnNumber) {
return false;
}
}
return areStackTracesEquivalent(stackTrace1.parent, stackTrace2.parent);
}
export class ConsoleMessage {
#runtimeModelInternal;
source;
level;
messageText;
type;
url;
line;
column;
parameters;
stackTrace;
timestamp;
#executionContextId;
scriptId;
workerId;
context;
#originatingConsoleMessage = null;
#pageLoadSequenceNumber = undefined;
#exceptionId = undefined;
#affectedResources;
category;
/**
* The parent frame of the `console.log` call of logpoints or conditional breakpoints
* if they called `console.*` explicitly. The parent frame is where V8 paused
* and consequently where the logpoint is set.
*
* Is `null` for page console.logs, commands, command results, etc.
*/
stackFrameWithBreakpoint = null;
#originatingBreakpointType = null;
constructor(runtimeModel, source, level, messageText, details) {
this.#runtimeModelInternal = runtimeModel;
this.source = source;
this.level = level;
this.messageText = messageText;
this.type = details?.type || "log" /* Protocol.Runtime.ConsoleAPICalledEventType.Log */;
this.url = details?.url;
this.line = details?.line || 0;
this.column = details?.column || 0;
this.parameters = details?.parameters;
this.stackTrace = details?.stackTrace;
this.timestamp = details?.timestamp || Date.now();
this.#executionContextId = details?.executionContextId || 0;
this.scriptId = details?.scriptId;
this.workerId = details?.workerId;
this.#affectedResources = details?.affectedResources;
this.category = details?.category;
if (!this.#executionContextId && this.#runtimeModelInternal) {
if (this.scriptId) {
this.#executionContextId = this.#runtimeModelInternal.executionContextIdForScriptId(this.scriptId);
}
else if (this.stackTrace) {
this.#executionContextId = this.#runtimeModelInternal.executionContextForStackTrace(this.stackTrace);
}
}
if (details?.context) {
const match = details?.context.match(/[^#]*/);
this.context = match?.[0];
}
if (this.stackTrace) {
const { callFrame, type } = ConsoleMessage.#stackFrameWithBreakpoint(this.stackTrace);
this.stackFrameWithBreakpoint = callFrame;
this.#originatingBreakpointType = type;
}
}
getAffectedResources() {
return this.#affectedResources;
}
setPageLoadSequenceNumber(pageLoadSequenceNumber) {
this.#pageLoadSequenceNumber = pageLoadSequenceNumber;
}
static fromException(runtimeModel, exceptionDetails, messageType, timestamp, forceUrl, affectedResources) {
const details = {
type: messageType,
url: forceUrl || exceptionDetails.url,
line: exceptionDetails.lineNumber,
column: exceptionDetails.columnNumber,
parameters: exceptionDetails.exception ?
[RemoteObject.fromLocalObject(exceptionDetails.text), exceptionDetails.exception] :
undefined,
stackTrace: exceptionDetails.stackTrace,
timestamp,
executionContextId: exceptionDetails.executionContextId,
scriptId: exceptionDetails.scriptId,
affectedResources,
};
return new ConsoleMessage(runtimeModel, "javascript" /* Protocol.Log.LogEntrySource.Javascript */, "error" /* Protocol.Log.LogEntryLevel.Error */, RuntimeModel.simpleTextFromException(exceptionDetails), details);
}
runtimeModel() {
return this.#runtimeModelInternal;
}
target() {
return this.#runtimeModelInternal ? this.#runtimeModelInternal.target() : null;
}
setOriginatingMessage(originatingMessage) {
this.#originatingConsoleMessage = originatingMessage;
this.#executionContextId = originatingMessage.#executionContextId;
}
originatingMessage() {
return this.#originatingConsoleMessage;
}
setExecutionContextId(executionContextId) {
this.#executionContextId = executionContextId;
}
getExecutionContextId() {
return this.#executionContextId;
}
getExceptionId() {
return this.#exceptionId;
}
setExceptionId(exceptionId) {
this.#exceptionId = exceptionId;
}
isGroupMessage() {
return this.type === "startGroup" /* Protocol.Runtime.ConsoleAPICalledEventType.StartGroup */ ||
this.type === "startGroupCollapsed" /* Protocol.Runtime.ConsoleAPICalledEventType.StartGroupCollapsed */ ||
this.type === "endGroup" /* Protocol.Runtime.ConsoleAPICalledEventType.EndGroup */;
}
isGroupStartMessage() {
return this.type === "startGroup" /* Protocol.Runtime.ConsoleAPICalledEventType.StartGroup */ ||
this.type === "startGroupCollapsed" /* Protocol.Runtime.ConsoleAPICalledEventType.StartGroupCollapsed */;
}
isErrorOrWarning() {
return (this.level === "warning" /* Protocol.Log.LogEntryLevel.Warning */ || this.level === "error" /* Protocol.Log.LogEntryLevel.Error */);
}
isGroupable() {
const isUngroupableError = this.level === "error" /* Protocol.Log.LogEntryLevel.Error */ &&
(this.source === "javascript" /* Protocol.Log.LogEntrySource.Javascript */ || this.source === "network" /* Protocol.Log.LogEntrySource.Network */);
return (this.source !== FrontendMessageSource.ConsoleAPI && this.type !== FrontendMessageType.Command &&
this.type !== FrontendMessageType.Result && this.type !== FrontendMessageType.System && !isUngroupableError);
}
groupCategoryKey() {
return [this.source, this.level, this.type, this.#pageLoadSequenceNumber].join(':');
}
isEqual(msg) {
if (!msg) {
return false;
}
if (this.parameters) {
if (!msg.parameters || this.parameters.length !== msg.parameters.length) {
return false;
}
for (let i = 0; i < msg.parameters.length; ++i) {
const msgParam = msg.parameters[i];
const param = this.parameters[i];
if (typeof msgParam === 'string' || typeof param === 'string') {
// TODO(chromium:1136435): Remove this case.
return false;
}
// Never treat objects as equal - their properties might change over time. Errors can be treated as equal
// since they are always formatted as strings.
if (msgParam.type === 'object' && msgParam.subtype !== 'error') {
return false;
}
if (param.type !== msgParam.type || param.value !== msgParam.value ||
param.description !== msgParam.description) {
return false;
}
}
}
return (this.runtimeModel() === msg.runtimeModel()) && (this.source === msg.source) && (this.type === msg.type) &&
(this.level === msg.level) && (this.line === msg.line) && (this.url === msg.url) &&
(this.scriptId === msg.scriptId) && (this.messageText === msg.messageText) &&
(this.#executionContextId === msg.#executionContextId) &&
areAffectedResourcesEquivalent(this.#affectedResources, msg.#affectedResources) &&
areStackTracesEquivalent(this.stackTrace, msg.stackTrace);
}
get originatesFromLogpoint() {
return this.#originatingBreakpointType === "LOGPOINT" /* BreakpointType.LOGPOINT */;
}
/** @returns true, iff this was a console.* call in a conditional breakpoint */
get originatesFromConditionalBreakpoint() {
return this.#originatingBreakpointType === "CONDITIONAL_BREAKPOINT" /* BreakpointType.CONDITIONAL_BREAKPOINT */;
}
static #stackFrameWithBreakpoint({ callFrames }) {
// Note that breakpoint condition code could in theory call into user JS and back into
// "condition-defined" functions. This means that the top-most
// stack frame is not necessarily the `console.log` call, but there could be other things
// on top. We want the LAST marker frame in the stack.
// We search FROM THE TOP for the last marked stack frame and
// return it's parent (successor).
const markerSourceUrls = [COND_BREAKPOINT_SOURCE_URL, LOGPOINT_SOURCE_URL];
const lastBreakpointFrameIndex = callFrames.findLastIndex(({ url }) => markerSourceUrls.includes(url));
if (lastBreakpointFrameIndex === -1 || lastBreakpointFrameIndex === callFrames.length - 1) {
// We either didn't find any breakpoint or we didn't capture enough stack
// frames and the breakpoint condition is the bottom-most frame.
return { callFrame: null, type: null };
}
const type = callFrames[lastBreakpointFrameIndex].url === LOGPOINT_SOURCE_URL ?
"LOGPOINT" /* BreakpointType.LOGPOINT */ :
"CONDITIONAL_BREAKPOINT" /* BreakpointType.CONDITIONAL_BREAKPOINT */;
return { callFrame: callFrames[lastBreakpointFrameIndex + 1], type };
}
}
SDKModel.register(ConsoleModel, { capabilities: Capability.JS, autostart: true });
export const MessageSourceDisplayName = new Map(([
["xml" /* Protocol.Log.LogEntrySource.XML */, 'xml'],
["javascript" /* Protocol.Log.LogEntrySource.Javascript */, 'javascript'],
["network" /* Protocol.Log.LogEntrySource.Network */, 'network'],
[FrontendMessageSource.ConsoleAPI, 'console-api'],
["storage" /* Protocol.Log.LogEntrySource.Storage */, 'storage'],
["appcache" /* Protocol.Log.LogEntrySource.Appcache */, 'appcache'],
["rendering" /* Protocol.Log.LogEntrySource.Rendering */, 'rendering'],
[FrontendMessageSource.CSS, 'css'],
["security" /* Protocol.Log.LogEntrySource.Security */, 'security'],
["deprecation" /* Protocol.Log.LogEntrySource.Deprecation */, 'deprecation'],
["worker" /* Protocol.Log.LogEntrySource.Worker */, 'worker'],
["violation" /* Protocol.Log.LogEntrySource.Violation */, 'violation'],
["intervention" /* Protocol.Log.LogEntrySource.Intervention */, 'intervention'],
["recommendation" /* Protocol.Log.LogEntrySource.Recommendation */, 'recommendation'],
["other" /* Protocol.Log.LogEntrySource.Other */, 'other'],
]));
//# sourceMappingURL=ConsoleModel.js.map