blob: 0737a362a5f70d0ce401efe3376fd15ef5d53b14 [file] [log] [blame]
/*
* Copyright (C) 2016 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.HeapSnapshotRootPath = class HeapSnapshotRootPath
{
constructor(node, pathComponent, parent, isGlobalScope)
{
console.assert(!node || node instanceof WI.HeapSnapshotNodeProxy);
console.assert(!pathComponent || typeof pathComponent === "string");
console.assert(!parent || parent instanceof WI.HeapSnapshotRootPath);
this._node = node || null;
this._parent = parent || null;
this._pathComponent = typeof pathComponent === "string" ? pathComponent : null;
this._isGlobalScope = isGlobalScope || false;
// Become the new root when appended to an empty path.
if (this._parent && this._parent.isEmpty())
this._parent = null;
}
// Static
static emptyPath()
{
return new WI.HeapSnapshotRootPath(null);
}
static pathComponentForIndividualEdge(edge)
{
switch (edge.type) {
case WI.HeapSnapshotEdgeProxy.EdgeType.Internal:
return null;
case WI.HeapSnapshotEdgeProxy.EdgeType.Index:
return "[" + edge.data + "]";
case WI.HeapSnapshotEdgeProxy.EdgeType.Property:
case WI.HeapSnapshotEdgeProxy.EdgeType.Variable:
if (WI.HeapSnapshotRootPath.canPropertyNameBeDotAccess(edge.data))
return edge.data;
return "[" + doubleQuotedString(edge.data) + "]";
}
}
static canPropertyNameBeDotAccess(propertyName)
{
return /^(?![0-9])\w+$/.test(propertyName);
}
// Public
get node() { return this._node; }
get parent() { return this._parent; }
get pathComponent() { return this._pathComponent; }
get rootNode()
{
return this._parent ? this._parent.rootNode : this._node;
}
get fullPath()
{
let components = [];
for (let p = this; p && p.pathComponent; p = p.parent)
components.push(p.pathComponent);
components.reverse();
return components.join("");
}
isRoot()
{
return !this._parent;
}
isEmpty()
{
return !this._node;
}
isGlobalScope()
{
return this._isGlobalScope;
}
isPathComponentImpossible()
{
return this._pathComponent && this._pathComponent.startsWith("@");
}
isFullPathImpossible()
{
if (this.isEmpty())
return true;
if (this.isPathComponentImpossible())
return true;
if (this._parent)
return this._parent.isFullPathImpossible();
return false;
}
appendInternal(node)
{
return new WI.HeapSnapshotRootPath(node, WI.HeapSnapshotRootPath.SpecialPathComponent.InternalPropertyName, this);
}
appendArrayIndex(node, index)
{
let component = "[" + index + "]";
return new WI.HeapSnapshotRootPath(node, component, this);
}
appendPropertyName(node, propertyName)
{
let component = WI.HeapSnapshotRootPath.canPropertyNameBeDotAccess(propertyName) ? "." + propertyName : "[" + doubleQuotedString(propertyName) + "]";
return new WI.HeapSnapshotRootPath(node, component, this);
}
appendVariableName(node, variableName)
{
// Treat as a property of the global object, e.g. "window.foo".
if (this._isGlobalScope)
return this.appendPropertyName(node, variableName);
return new WI.HeapSnapshotRootPath(node, variableName, this);
}
appendGlobalScopeName(node, globalScopeName)
{
return new WI.HeapSnapshotRootPath(node, globalScopeName, this, true);
}
appendEdge(edge)
{
console.assert(edge instanceof WI.HeapSnapshotEdgeProxy);
switch (edge.type) {
case WI.HeapSnapshotEdgeProxy.EdgeType.Internal:
return this.appendInternal(edge.to);
case WI.HeapSnapshotEdgeProxy.EdgeType.Index:
return this.appendArrayIndex(edge.to, edge.data);
case WI.HeapSnapshotEdgeProxy.EdgeType.Property:
return this.appendPropertyName(edge.to, edge.data);
case WI.HeapSnapshotEdgeProxy.EdgeType.Variable:
return this.appendVariableName(edge.to, edge.data);
}
console.error("Unexpected edge type", edge.type);
}
};
WI.HeapSnapshotRootPath.SpecialPathComponent = {
InternalPropertyName: "@internal",
};