blob: 3ef8ffe8c9db7cd478f434bde95a9e9622663ab7 [file] [log] [blame]
/*
* Copyright (C) 2013, 2014 Apple 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:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
*/
WI.JavaScriptBreakpoint = class JavaScriptBreakpoint extends WI.Breakpoint
{
constructor(sourceCodeLocation, {contentIdentifier, resolved, disabled, condition, actions, ignoreCount, autoContinue} = {})
{
console.assert(sourceCodeLocation instanceof WI.SourceCodeLocation, sourceCodeLocation);
console.assert(!contentIdentifier || typeof contentIdentifier === "string", contentIdentifier);
console.assert(resolved === undefined || typeof resolved === "boolean", resolved);
super({disabled, condition, actions, ignoreCount, autoContinue});
this._id = null;
this._sourceCodeLocation = sourceCodeLocation;
let sourceCode = this._sourceCodeLocation.sourceCode;
if (sourceCode) {
this._contentIdentifier = sourceCode.contentIdentifier;
console.assert(!contentIdentifier || contentIdentifier === this._contentIdentifier, "The content identifier from the source code should match the given value.");
} else
this._contentIdentifier = contentIdentifier || null;
console.assert(this._contentIdentifier || this._isSpecial(), "There should always be a content identifier for a breakpoint.");
this._scriptIdentifier = sourceCode instanceof WI.Script ? sourceCode.id : null;
this._target = sourceCode instanceof WI.Script ? sourceCode.target : null;
this._resolved = !!resolved;
this._sourceCodeLocation.addEventListener(WI.SourceCodeLocation.Event.LocationChanged, this._sourceCodeLocationLocationChanged, this);
this._sourceCodeLocation.addEventListener(WI.SourceCodeLocation.Event.DisplayLocationChanged, this._sourceCodeLocationDisplayLocationChanged, this);
}
// Static
static supportsMicrotasks(parameter)
{
// COMPATIBILITY (iOS 13): Debugger.setPauseOnMicrotasks did not exist yet.
return InspectorBackend.hasCommand("Debugger.setPauseOnMicrotasks", parameter);
}
static supportsDebuggerStatements(parameter)
{
// COMPATIBILITY (iOS 13.1): Debugger.setPauseOnDebuggerStatements did not exist yet.
return InspectorBackend.hasCommand("Debugger.setPauseOnDebuggerStatements", parameter);
}
// Import / Export
static fromJSON(json)
{
const sourceCode = null;
return new WI.JavaScriptBreakpoint(new WI.SourceCodeLocation(sourceCode, json.lineNumber || 0, json.columnNumber || 0), {
// The 'url' fallback is for transitioning from older frontends and should be removed.
contentIdentifier: json.contentIdentifier || json.url,
resolved: json.resolved,
disabled: json.disabled,
condition: json.condition,
actions: json.actions?.map((actionJSON) => WI.BreakpointAction.fromJSON(actionJSON)) || [],
ignoreCount: json.ignoreCount,
autoContinue: json.autoContinue,
});
}
toJSON(key)
{
// The id, scriptIdentifier, target, and resolved state are tied to the current session, so don't include them for serialization.
let json = super.toJSON(key);
if (this._contentIdentifier)
json.contentIdentifier = this._contentIdentifier;
if (isFinite(this._sourceCodeLocation.lineNumber))
json.lineNumber = this._sourceCodeLocation.lineNumber;
if (isFinite(this._sourceCodeLocation.columnNumber))
json.columnNumber = this._sourceCodeLocation.columnNumber;
if (key === WI.ObjectStore.toJSONSymbol)
json[WI.objectStores.breakpoints.keyPath] = this._contentIdentifier + ":" + this._sourceCodeLocation.lineNumber + ":" + this._sourceCodeLocation.columnNumber;
return json;
}
// Public
get sourceCodeLocation() { return this._sourceCodeLocation; }
get contentIdentifier() { return this._contentIdentifier; }
get scriptIdentifier() { return this._scriptIdentifier; }
get target() { return this._target; }
get displayName()
{
switch (this) {
case WI.debuggerManager.debuggerStatementsBreakpoint:
return WI.repeatedUIString.debuggerStatements();
case WI.debuggerManager.allExceptionsBreakpoint:
return WI.repeatedUIString.allExceptions();
case WI.debuggerManager.uncaughtExceptionsBreakpoint:
return WI.repeatedUIString.uncaughtExceptions();
case WI.debuggerManager.assertionFailuresBreakpoint:
return WI.repeatedUIString.assertionFailures();
case WI.debuggerManager.allMicrotasksBreakpoint:
return WI.repeatedUIString.allMicrotasks();
}
return this._sourceCodeLocation.displayLocationString()
}
get special()
{
switch (this) {
case WI.debuggerManager.debuggerStatementsBreakpoint:
case WI.debuggerManager.allExceptionsBreakpoint:
case WI.debuggerManager.uncaughtExceptionsBreakpoint:
case WI.debuggerManager.assertionFailuresBreakpoint:
case WI.debuggerManager.allMicrotasksBreakpoint:
return true;
}
if (this._isSpecial())
return true;
return super.special;
}
get removable()
{
switch (this) {
case WI.debuggerManager.debuggerStatementsBreakpoint:
case WI.debuggerManager.allExceptionsBreakpoint:
case WI.debuggerManager.uncaughtExceptionsBreakpoint:
return false;
}
return super.removable;
}
get editable()
{
switch (this) {
case WI.debuggerManager.debuggerStatementsBreakpoint:
// COMPATIBILITY (iOS 14): Debugger.setPauseOnDebuggerStatements did not have an "options" parameter yet.
return WI.JavaScriptBreakpoint.supportsDebuggerStatements("options");
case WI.debuggerManager.allExceptionsBreakpoint:
case WI.debuggerManager.uncaughtExceptionsBreakpoint:
// COMPATIBILITY (iOS 14): Debugger.setPauseOnExceptions did not have an "options" parameter yet.
return InspectorBackend.hasCommand("Debugger.setPauseOnExceptions", "options");
case WI.debuggerManager.assertionFailuresBreakpoint:
// COMPATIBILITY (iOS 14): Debugger.setPauseOnAssertions did not have an "options" parameter yet.
return InspectorBackend.hasCommand("Debugger.setPauseOnAssertions", "options");
case WI.debuggerManager.allMicrotasksBreakpoint:
// COMPATIBILITY (iOS 14): Debugger.setPauseOnMicrotasks did not have an "options" parameter yet.
return WI.JavaScriptBreakpoint.supportsMicrotasks("options");
}
return true;
}
get identifier()
{
return this._id;
}
set identifier(id)
{
this._id = id || null;
}
get resolved()
{
return super.resolved && this._resolved;
}
set resolved(resolved)
{
if (this._resolved === resolved)
return;
console.assert(!resolved || this._sourceCodeLocation.sourceCode || this._isSpecial(), "Breakpoints must have a SourceCode to be resolved.", this);
this._resolved = resolved || false;
this.dispatchEventToListeners(WI.JavaScriptBreakpoint.Event.ResolvedStateDidChange);
}
remove()
{
super.remove();
WI.debuggerManager.removeBreakpoint(this);
}
saveIdentityToCookie(cookie)
{
cookie["javascript-breakpoint-content-identifier"] = this._contentIdentifier;
cookie["javascript-breakpoint-line-number"] = this._sourceCodeLocation.lineNumber;
cookie["javascript-breakpoint-column-number"] = this._sourceCodeLocation.columnNumber;
}
// Private
_isSpecial()
{
return this._sourceCodeLocation.isEqual(WI.SourceCodeLocation.specialBreakpointLocation);
}
_sourceCodeLocationLocationChanged(event)
{
this.dispatchEventToListeners(WI.JavaScriptBreakpoint.Event.LocationDidChange, event.data);
}
_sourceCodeLocationDisplayLocationChanged(event)
{
this.dispatchEventToListeners(WI.JavaScriptBreakpoint.Event.DisplayLocationDidChange, event.data);
}
};
WI.JavaScriptBreakpoint.TypeIdentifier = "javascript-breakpoint";
WI.JavaScriptBreakpoint.Event = {
ResolvedStateDidChange: "javascript-breakpoint-resolved-state-did-change",
LocationDidChange: "javascript-breakpoint-location-did-change",
DisplayLocationDidChange: "javascript-breakpoint-display-location-did-change",
};
WI.JavaScriptBreakpoint.ReferencePage = WI.ReferencePage.JavaScriptBreakpoints;