summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/inspector/InjectedScriptSource.js
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2015-05-20 09:56:07 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2015-05-20 09:56:07 +0000
commit41386e9cb918eed93b3f13648cbef387e371e451 (patch)
treea97f9d7bd1d9d091833286085f72da9d83fd0606 /Source/JavaScriptCore/inspector/InjectedScriptSource.js
parente15dd966d523731101f70ccf768bba12435a0208 (diff)
downloadWebKitGtk-tarball-41386e9cb918eed93b3f13648cbef387e371e451.tar.gz
webkitgtk-2.4.9webkitgtk-2.4.9
Diffstat (limited to 'Source/JavaScriptCore/inspector/InjectedScriptSource.js')
-rw-r--r--Source/JavaScriptCore/inspector/InjectedScriptSource.js1314
1 files changed, 467 insertions, 847 deletions
diff --git a/Source/JavaScriptCore/inspector/InjectedScriptSource.js b/Source/JavaScriptCore/inspector/InjectedScriptSource.js
index 55874a633..7bff7f6d4 100644
--- a/Source/JavaScriptCore/inspector/InjectedScriptSource.js
+++ b/Source/JavaScriptCore/inspector/InjectedScriptSource.js
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2007, 2014-2015 Apple Inc. All rights reserved.
- * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -11,7 +10,7 @@
* 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.
- * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -29,36 +28,19 @@
//# sourceURL=__WebInspectorInjectedScript__
+/**
+ * @param {InjectedScriptHost} InjectedScriptHost
+ * @param {GlobalObject} inspectedGlobalObject
+ * @param {number} injectedScriptId
+ */
(function (InjectedScriptHost, inspectedGlobalObject, injectedScriptId) {
// Protect against Object overwritten by the user code.
var Object = {}.constructor;
-function toString(obj)
-{
- return String(obj);
-}
-
-function toStringDescription(obj)
-{
- if (obj === 0 && 1 / obj < 0)
- return "-0";
-
- return toString(obj);
-}
-
-function isUInt32(obj)
-{
- if (typeof obj === "number")
- return obj >>> 0 === obj && (obj > 0 || 1 / obj > 0);
- return "" + (obj >>> 0) === obj;
-}
-
-function isSymbol(obj)
-{
- return typeof obj === "symbol";
-}
-
+/**
+ * @constructor
+ */
var InjectedScript = function()
{
this._lastBoundObjectId = 1;
@@ -66,30 +48,37 @@ var InjectedScript = function()
this._idToObjectGroupName = {};
this._objectGroups = {};
this._modules = {};
- this._nextSavedResultIndex = 1;
- this._savedResults = [];
}
+/**
+ * @type {Object.<string, boolean>}
+ * @const
+ */
InjectedScript.primitiveTypes = {
undefined: true,
boolean: true,
number: true,
- string: true,
-}
-
-InjectedScript.CollectionMode = {
- OwnProperties: 1 << 0, // own properties.
- NativeGetterProperties: 1 << 1, // native getter properties in the prototype chain.
- AllProperties: 1 << 2, // all properties in the prototype chain.
+ string: true
}
InjectedScript.prototype = {
+ /**
+ * @param {*} object
+ * @return {boolean}
+ */
isPrimitiveValue: function(object)
{
// FIXME(33716): typeof document.all is always 'undefined'.
return InjectedScript.primitiveTypes[typeof object] && !this._isHTMLAllCollection(object);
},
+ /**
+ * @param {*} object
+ * @param {string} groupName
+ * @param {boolean} canAccessInspectedGlobalObject
+ * @param {boolean} generatePreview
+ * @return {!RuntimeAgent.RemoteObject}
+ */
wrapObject: function(object, groupName, canAccessInspectedGlobalObject, generatePreview)
{
if (canAccessInspectedGlobalObject)
@@ -97,16 +86,10 @@ InjectedScript.prototype = {
return this._fallbackWrapper(object);
},
- setExceptionValue: function(value)
- {
- this._exceptionValue = value;
- },
-
- clearExceptionValue: function()
- {
- delete this._exceptionValue;
- },
-
+ /**
+ * @param {*} object
+ * @return {!RuntimeAgent.RemoteObject}
+ */
_fallbackWrapper: function(object)
{
var result = {};
@@ -114,38 +97,50 @@ InjectedScript.prototype = {
if (this.isPrimitiveValue(object))
result.value = object;
else
- result.description = toString(object);
- return result;
+ result.description = this._toString(object);
+ return /** @type {!RuntimeAgent.RemoteObject} */ (result);
},
+ /**
+ * @param {boolean} canAccessInspectedGlobalObject
+ * @param {Object} table
+ * @param {Array.<string>|string|boolean} columns
+ * @return {!RuntimeAgent.RemoteObject}
+ */
wrapTable: function(canAccessInspectedGlobalObject, table, columns)
{
if (!canAccessInspectedGlobalObject)
return this._fallbackWrapper(table);
-
- // FIXME: Currently columns are ignored. Instead, the frontend filters all
- // properties based on the provided column names and in the provided order.
- // Should we filter here too?
-
var columnNames = null;
if (typeof columns === "string")
columns = [columns];
-
- if (InjectedScriptHost.subtype(columns) === "array") {
+ if (InjectedScriptHost.type(columns) == "array") {
columnNames = [];
for (var i = 0; i < columns.length; ++i)
- columnNames.push(toString(columns[i]));
+ columnNames.push(String(columns[i]));
}
-
return this._wrapObject(table, "console", false, true, columnNames);
},
+ /**
+ * @param {*} object
+ */
inspectObject: function(object)
{
if (this._commandLineAPIImpl)
this._commandLineAPIImpl.inspect(object);
},
+ /**
+ * This method cannot throw.
+ * @param {*} object
+ * @param {string=} objectGroupName
+ * @param {boolean=} forceValueType
+ * @param {boolean=} generatePreview
+ * @param {?Array.<string>=} columnNames
+ * @return {!RuntimeAgent.RemoteObject}
+ * @suppress {checkTypes}
+ */
_wrapObject: function(object, objectGroupName, forceValueType, generatePreview, columnNames)
{
try {
@@ -160,6 +155,11 @@ InjectedScript.prototype = {
}
},
+ /**
+ * @param {*} object
+ * @param {string=} objectGroupName
+ * @return {string}
+ */
_bind: function(object, objectGroupName)
{
var id = this._lastBoundObjectId++;
@@ -177,34 +177,39 @@ InjectedScript.prototype = {
return objectId;
},
+ /**
+ * @param {string} objectId
+ * @return {Object}
+ */
_parseObjectId: function(objectId)
{
return InjectedScriptHost.evaluate("(" + objectId + ")");
},
+ /**
+ * @param {string} objectGroupName
+ */
releaseObjectGroup: function(objectGroupName)
{
- if (objectGroupName === "console") {
- delete this._lastResult;
- this._nextSavedResultIndex = 1;
- this._savedResults = [];
- }
-
var group = this._objectGroups[objectGroupName];
if (!group)
return;
-
for (var i = 0; i < group.length; i++)
this._releaseObject(group[i]);
-
delete this._objectGroups[objectGroupName];
},
+ /**
+ * @param {string} methodName
+ * @param {string} args
+ * @return {*}
+ */
dispatch: function(methodName, args)
{
var argsArray = InjectedScriptHost.evaluate("(" + args + ")");
var result = this[methodName].apply(this, argsArray);
if (typeof result === "undefined") {
+ // FIXME: JS Context inspection currently does not have a global.console object.
if (inspectedGlobalObject.console)
inspectedGlobalObject.console.error("Web Inspector error: InjectedScript.%s returns undefined", methodName);
result = null;
@@ -212,7 +217,12 @@ InjectedScript.prototype = {
return result;
},
- _getProperties: function(objectId, collectionMode, generatePreview)
+ /**
+ * @param {string} objectId
+ * @param {boolean} ownProperties
+ * @return {Array.<RuntimeAgent.PropertyDescriptor>|boolean}
+ */
+ getProperties: function(objectId, ownProperties)
{
var parsedObjectId = this._parseObjectId(objectId);
var object = this._objectForId(parsedObjectId);
@@ -220,11 +230,7 @@ InjectedScript.prototype = {
if (!this._isDefined(object))
return false;
-
- if (isSymbol(object))
- return false;
-
- var descriptors = this._propertyDescriptors(object, collectionMode);
+ var descriptors = this._propertyDescriptors(object, ownProperties);
// Go over properties, wrap object values.
for (var i = 0; i < descriptors.length; ++i) {
@@ -234,90 +240,45 @@ InjectedScript.prototype = {
if ("set" in descriptor)
descriptor.set = this._wrapObject(descriptor.set, objectGroupName);
if ("value" in descriptor)
- descriptor.value = this._wrapObject(descriptor.value, objectGroupName, false, generatePreview);
+ descriptor.value = this._wrapObject(descriptor.value, objectGroupName);
if (!("configurable" in descriptor))
descriptor.configurable = false;
if (!("enumerable" in descriptor))
descriptor.enumerable = false;
- if ("symbol" in descriptor)
- descriptor.symbol = this._wrapObject(descriptor.symbol, objectGroupName);
}
-
return descriptors;
},
- getProperties: function(objectId, ownProperties, generatePreview)
- {
- var collectionMode = ownProperties ? InjectedScript.CollectionMode.OwnProperties : InjectedScript.CollectionMode.AllProperties;
- return this._getProperties(objectId, collectionMode, generatePreview);
- },
-
- getDisplayableProperties: function(objectId, generatePreview)
- {
- var collectionMode = InjectedScript.CollectionMode.OwnProperties | InjectedScript.CollectionMode.NativeGetterProperties;
- return this._getProperties(objectId, collectionMode, generatePreview);
- },
-
- getInternalProperties: function(objectId, generatePreview)
+ /**
+ * @param {string} objectId
+ * @return {Array.<Object>|boolean}
+ */
+ getInternalProperties: function(objectId, ownProperties)
{
var parsedObjectId = this._parseObjectId(objectId);
var object = this._objectForId(parsedObjectId);
var objectGroupName = this._idToObjectGroupName[parsedObjectId.id];
-
if (!this._isDefined(object))
return false;
-
- if (isSymbol(object))
- return false;
-
- var descriptors = this._internalPropertyDescriptors(object);
- if (!descriptors)
- return [];
-
- // Go over properties, wrap object values.
- for (var i = 0; i < descriptors.length; ++i) {
- var descriptor = descriptors[i];
- if ("value" in descriptor)
- descriptor.value = this._wrapObject(descriptor.value, objectGroupName, false, generatePreview);
+ var descriptors = [];
+ var internalProperties = InjectedScriptHost.getInternalProperties(object);
+ if (internalProperties) {
+ for (var i = 0; i < internalProperties.length; i++) {
+ var property = internalProperties[i];
+ var descriptor = {
+ name: property.name,
+ value: this._wrapObject(property.value, objectGroupName)
+ };
+ descriptors.push(descriptor);
+ }
}
-
return descriptors;
},
- getCollectionEntries: function(objectId, objectGroupName, startIndex, numberToFetch)
- {
- var parsedObjectId = this._parseObjectId(objectId);
- var object = this._objectForId(parsedObjectId);
- var objectGroupName = objectGroupName || this._idToObjectGroupName[parsedObjectId.id];
-
- if (!this._isDefined(object))
- return;
-
- if (typeof object !== "object")
- return;
-
- var entries = this._entries(object, InjectedScriptHost.subtype(object), startIndex, numberToFetch);
- return entries.map(function(entry) {
- entry.value = injectedScript._wrapObject(entry.value, objectGroupName, false, true);
- if ("key" in entry)
- entry.key = injectedScript._wrapObject(entry.key, objectGroupName, false, true);
- return entry;
- });
- },
-
- saveResult: function(callArgumentJSON)
- {
- this._savedResultIndex = 0;
-
- try {
- var callArgument = InjectedScriptHost.evaluate("(" + callArgumentJSON + ")");
- var value = this._resolveCallArgument(callArgument);
- this._saveResult(value);
- } catch (e) {}
-
- return this._savedResultIndex;
- },
-
+ /**
+ * @param {string} functionId
+ * @return {!DebuggerAgent.FunctionDetails|string}
+ */
getFunctionDetails: function(functionId)
{
var parsedFunctionId = this._parseObjectId(functionId);
@@ -339,24 +300,96 @@ InjectedScript.prototype = {
return details;
},
+ /**
+ * @param {string} objectId
+ */
releaseObject: function(objectId)
{
var parsedObjectId = this._parseObjectId(objectId);
this._releaseObject(parsedObjectId.id);
},
+ /**
+ * @param {string} id
+ */
_releaseObject: function(id)
{
delete this._idToWrappedObject[id];
delete this._idToObjectGroupName[id];
},
- evaluate: function(expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview, saveResult)
+ /**
+ * @param {Object} object
+ * @param {boolean} ownProperties
+ * @return {Array.<Object>}
+ */
+ _propertyDescriptors: function(object, ownProperties)
{
- return this._evaluateAndWrap(InjectedScriptHost.evaluate, InjectedScriptHost, expression, objectGroup, false, injectCommandLineAPI, returnByValue, generatePreview, saveResult);
+ var descriptors = [];
+ var nameProcessed = {};
+ nameProcessed["__proto__"] = null;
+ for (var o = object; this._isDefined(o); o = o.__proto__) {
+ var names = Object.getOwnPropertyNames(/** @type {!Object} */ (o));
+ for (var i = 0; i < names.length; ++i) {
+ var name = names[i];
+ if (nameProcessed[name])
+ continue;
+
+ try {
+ nameProcessed[name] = true;
+ var descriptor = Object.getOwnPropertyDescriptor(/** @type {!Object} */ (object), name);
+ if (!descriptor) {
+ // Not all bindings provide proper descriptors. Fall back to the writable, configurable property.
+ try {
+ descriptor = { name: name, value: object[name], writable: false, configurable: false, enumerable: false};
+ if (o === object)
+ descriptor.isOwn = true;
+ descriptors.push(descriptor);
+ } catch (e) {
+ // Silent catch.
+ }
+ continue;
+ }
+ } catch (e) {
+ var descriptor = {};
+ descriptor.value = e;
+ descriptor.wasThrown = true;
+ }
+
+ descriptor.name = name;
+ if (o === object)
+ descriptor.isOwn = true;
+ descriptors.push(descriptor);
+ }
+ if (ownProperties) {
+ if (object.__proto__)
+ descriptors.push({ name: "__proto__", value: object.__proto__, writable: true, configurable: true, enumerable: false, isOwn: true});
+ break;
+ }
+ }
+ return descriptors;
},
- callFunctionOn: function(objectId, expression, args, returnByValue, generatePreview)
+ /**
+ * @param {string} expression
+ * @param {string} objectGroup
+ * @param {boolean} injectCommandLineAPI
+ * @param {boolean} returnByValue
+ * @param {boolean} generatePreview
+ * @return {*}
+ */
+ evaluate: function(expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview)
+ {
+ return this._evaluateAndWrap(InjectedScriptHost.evaluate, InjectedScriptHost, expression, objectGroup, false, injectCommandLineAPI, returnByValue, generatePreview);
+ },
+
+ /**
+ * @param {string} objectId
+ * @param {string} expression
+ * @param {boolean} returnByValue
+ * @return {Object|string}
+ */
+ callFunctionOn: function(objectId, expression, args, returnByValue)
{
var parsedObjectId = this._parseObjectId(objectId);
var object = this._objectForId(parsedObjectId);
@@ -365,13 +398,15 @@ InjectedScript.prototype = {
if (args) {
var resolvedArgs = [];
- var callArgs = InjectedScriptHost.evaluate(args);
- for (var i = 0; i < callArgs.length; ++i) {
+ args = InjectedScriptHost.evaluate(args);
+ for (var i = 0; i < args.length; ++i) {
+ var resolvedCallArgument;
try {
- resolvedArgs[i] = this._resolveCallArgument(callArgs[i]);
+ resolvedCallArgument = this._resolveCallArgument(args[i]);
} catch (e) {
return String(e);
}
+ resolvedArgs.push(resolvedCallArgument)
}
}
@@ -381,21 +416,21 @@ InjectedScript.prototype = {
if (typeof func !== "function")
return "Given expression does not evaluate to a function";
- return {
- wasThrown: false,
- result: this._wrapObject(func.apply(object, resolvedArgs), objectGroup, returnByValue, generatePreview)
- };
+ return { wasThrown: false,
+ result: this._wrapObject(func.apply(object, resolvedArgs), objectGroup, returnByValue) };
} catch (e) {
return this._createThrownValue(e, objectGroup);
}
},
- _resolveCallArgument: function(callArgumentJSON)
- {
- if ("value" in callArgumentJSON)
- return callArgumentJSON.value;
-
- var objectId = callArgumentJSON.objectId;
+ /**
+ * Resolves a value from CallArgument description.
+ * @param {RuntimeAgent.CallArgument} callArgumentJson
+ * @return {*} resolved value
+ * @throws {string} error message
+ */
+ _resolveCallArgument: function(callArgumentJson) {
+ var objectId = callArgumentJson.objectId;
if (objectId) {
var parsedArgId = this._parseObjectId(objectId);
if (!parsedArgId || parsedArgId["injectedScriptId"] !== injectedScriptId)
@@ -406,43 +441,57 @@ InjectedScript.prototype = {
throw "Could not find object with given id";
return resolvedArg;
- }
-
- return undefined;
+ } else if ("value" in callArgumentJson)
+ return callArgumentJson.value;
+ else
+ return undefined;
},
- _evaluateAndWrap: function(evalFunction, object, expression, objectGroup, isEvalOnCallFrame, injectCommandLineAPI, returnByValue, generatePreview, saveResult)
+ /**
+ * @param {Function} evalFunction
+ * @param {Object} object
+ * @param {string} objectGroup
+ * @param {boolean} isEvalOnCallFrame
+ * @param {boolean} injectCommandLineAPI
+ * @param {boolean} returnByValue
+ * @param {boolean} generatePreview
+ * @return {*}
+ */
+ _evaluateAndWrap: function(evalFunction, object, expression, objectGroup, isEvalOnCallFrame, injectCommandLineAPI, returnByValue, generatePreview)
{
try {
- this._savedResultIndex = 0;
-
- var returnObject = {
- wasThrown: false,
- result: this._wrapObject(this._evaluateOn(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI, saveResult), objectGroup, returnByValue, generatePreview)
- };
-
- if (saveResult && this._savedResultIndex)
- returnObject.savedResultIndex = this._savedResultIndex;
-
- return returnObject;
+ return { wasThrown: false,
+ result: this._wrapObject(this._evaluateOn(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI), objectGroup, returnByValue, generatePreview) };
} catch (e) {
return this._createThrownValue(e, objectGroup);
}
},
+ /**
+ * @param {*} value
+ * @param {string} objectGroup
+ * @return {Object}
+ */
_createThrownValue: function(value, objectGroup)
{
var remoteObject = this._wrapObject(value, objectGroup);
try {
- remoteObject.description = toStringDescription(value);
+ remoteObject.description = this._toString(value);
} catch (e) {}
- return {
- wasThrown: true,
- result: remoteObject
- };
+ return { wasThrown: true,
+ result: remoteObject };
},
- _evaluateOn: function(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI, saveResult)
+ /**
+ * @param {Function} evalFunction
+ * @param {Object} object
+ * @param {string} objectGroup
+ * @param {string} expression
+ * @param {boolean} isEvalOnCallFrame
+ * @param {boolean} injectCommandLineAPI
+ * @return {*}
+ */
+ _evaluateOn: function(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI)
{
var commandLineAPI = null;
if (injectCommandLineAPI) {
@@ -487,8 +536,8 @@ InjectedScript.prototype = {
var expressionFunction = evalFunction.call(object, boundExpressionFunctionString);
var result = expressionFunction.apply(null, parameters);
- if (objectGroup === "console" && saveResult)
- this._saveResult(result);
+ if (objectGroup === "console")
+ this._lastResult = result;
return result;
}
@@ -496,6 +545,7 @@ InjectedScript.prototype = {
// When not evaluating on a call frame we use a 'with' statement to allow var and function statements to leak
// into the global scope. This allow them to stick around between evaluations.
+ // FIXME: JS Context inspection currently does not have a global.console object.
try {
if (commandLineAPI) {
if (inspectedGlobalObject.console)
@@ -507,8 +557,8 @@ InjectedScript.prototype = {
var result = evalFunction.call(inspectedGlobalObject, expression);
- if (objectGroup === "console" && saveResult)
- this._saveResult(result);
+ if (objectGroup === "console")
+ this._lastResult = result;
return result;
} finally {
@@ -521,6 +571,10 @@ InjectedScript.prototype = {
}
},
+ /**
+ * @param {Object} callFrame
+ * @return {Array.<InjectedScript.CallFrameProxy>|boolean}
+ */
wrapCallFrames: function(callFrame)
{
if (!callFrame)
@@ -535,14 +589,29 @@ InjectedScript.prototype = {
return result;
},
- evaluateOnCallFrame: function(topCallFrame, callFrameId, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview, saveResult)
+ /**
+ * @param {Object} topCallFrame
+ * @param {string} callFrameId
+ * @param {string} expression
+ * @param {string} objectGroup
+ * @param {boolean} injectCommandLineAPI
+ * @param {boolean} returnByValue
+ * @param {boolean} generatePreview
+ * @return {*}
+ */
+ evaluateOnCallFrame: function(topCallFrame, callFrameId, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview)
{
var callFrame = this._callFrameForId(topCallFrame, callFrameId);
if (!callFrame)
return "Could not find call frame with given id";
- return this._evaluateAndWrap(callFrame.evaluate, callFrame, expression, objectGroup, true, injectCommandLineAPI, returnByValue, generatePreview, saveResult);
+ return this._evaluateAndWrap(callFrame.evaluate, callFrame, expression, objectGroup, true, injectCommandLineAPI, returnByValue, generatePreview);
},
+ /**
+ * @param {Object} topCallFrame
+ * @param {string} callFrameId
+ * @return {Object}
+ */
_callFrameForId: function(topCallFrame, callFrameId)
{
var parsedCallFrameId = InjectedScriptHost.evaluate("(" + callFrameId + ")");
@@ -553,215 +622,89 @@ InjectedScript.prototype = {
return callFrame;
},
+ /**
+ * @param {Object} objectId
+ * @return {Object}
+ */
_objectForId: function(objectId)
{
return this._idToWrappedObject[objectId.id];
},
+ /**
+ * @param {string} objectId
+ * @return {Object}
+ */
findObjectById: function(objectId)
{
var parsedObjectId = this._parseObjectId(objectId);
return this._objectForId(parsedObjectId);
},
+ /**
+ * @param {string} name
+ * @return {Object}
+ */
module: function(name)
{
return this._modules[name];
},
+ /**
+ * @param {string} name
+ * @param {string} source
+ * @return {Object}
+ */
injectModule: function(name, source, host)
{
delete this._modules[name];
-
var moduleFunction = InjectedScriptHost.evaluate("(" + source + ")");
if (typeof moduleFunction !== "function") {
+ // FIXME: JS Context inspection currently does not have a global.console object.
if (inspectedGlobalObject.console)
inspectedGlobalObject.console.error("Web Inspector error: A function was expected for module %s evaluation", name);
return null;
}
-
var module = moduleFunction.call(inspectedGlobalObject, InjectedScriptHost, inspectedGlobalObject, injectedScriptId, this, host);
this._modules[name] = module;
return module;
},
- _internalPropertyDescriptors: function(object, completeDescriptor)
- {
- var internalProperties = InjectedScriptHost.getInternalProperties(object);
- if (!internalProperties)
- return null;
-
- var descriptors = [];
- for (var i = 0; i < internalProperties.length; i++) {
- var property = internalProperties[i];
- var descriptor = {name: property.name, value: property.value};
- if (completeDescriptor) {
- descriptor.writable = false;
- descriptor.configurable = false;
- descriptor.enumerable = false;
- descriptor.isOwn = true;
- }
- descriptors.push(descriptor);
- }
- return descriptors;
- },
-
- _propertyDescriptors: function(object, collectionMode)
- {
- var descriptors = [];
- var nameProcessed = new Set;
-
- function createFakeValueDescriptor(name, symbol, descriptor, isOwnProperty, possibleNativeBindingGetter)
- {
- try {
- var descriptor = {name, value: object[name], writable: descriptor.writable || false, configurable: descriptor.configurable || false, enumerable: descriptor.enumerable || false};
- if (possibleNativeBindingGetter)
- descriptor.nativeGetter = true;
- if (isOwnProperty)
- descriptor.isOwn = true;
- if (symbol)
- descriptor.symbol = symbol;
- return descriptor;
- } catch (e) {
- var errorDescriptor = {name, value: e, wasThrown: true};
- if (isOwnProperty)
- errorDescriptor.isOwn = true;
- if (symbol)
- errorDescriptor.symbol = symbol;
- return errorDescriptor;
- }
- }
-
- function processDescriptor(descriptor, isOwnProperty, possibleNativeBindingGetter)
- {
- // All properties.
- if (collectionMode & InjectedScript.CollectionMode.AllProperties) {
- descriptors.push(descriptor);
- return;
- }
-
- // Own properties.
- if (collectionMode & InjectedScript.CollectionMode.OwnProperties && isOwnProperty) {
- descriptors.push(descriptor);
- return;
- }
-
- // Native Getter properties.
- if (collectionMode & InjectedScript.CollectionMode.NativeGetterProperties) {
- // FIXME: <https://webkit.org/b/140575> Web Inspector: Native Bindings Descriptors are Incomplete
- // if (descriptor.hasOwnProperty("get") && descriptor.get && isNativeFunction(descriptor.get)) { ... }
-
- if (possibleNativeBindingGetter) {
- // Possible getter property in the prototype chain.
- descriptors.push(descriptor);
- return;
- }
- }
- }
-
- function processProperties(o, properties, isOwnProperty)
- {
- for (var i = 0; i < properties.length; ++i) {
- var property = properties[i];
- if (nameProcessed.has(property) || property === "__proto__")
- continue;
-
- nameProcessed.add(property);
-
- var name = toString(property);
- var symbol = isSymbol(property) ? property : null;
-
- var descriptor = Object.getOwnPropertyDescriptor(o, property);
- if (!descriptor) {
- // FIXME: Bad descriptor. Can we get here?
- // Fall back to very restrictive settings.
- var fakeDescriptor = createFakeValueDescriptor(name, symbol, {writable: false, configurable: false, enumerable: false}, isOwnProperty);
- processDescriptor(fakeDescriptor, isOwnProperty);
- continue;
- }
-
- if (descriptor.hasOwnProperty("get") && descriptor.hasOwnProperty("set") && !descriptor.get && !descriptor.set) {
- // FIXME: <https://webkit.org/b/140575> Web Inspector: Native Bindings Descriptors are Incomplete
- // Developers may create such a descriptors, so we should be resilient:
- // var x = {}; Object.defineProperty(x, "p", {get:undefined}); Object.getOwnPropertyDescriptor(x, "p")
- var fakeDescriptor = createFakeValueDescriptor(name, symbol, descriptor, isOwnProperty, true);
- processDescriptor(fakeDescriptor, isOwnProperty, true);
- continue;
- }
-
- descriptor.name = name;
- if (isOwnProperty)
- descriptor.isOwn = true;
- if (symbol)
- descriptor.symbol = symbol;
- processDescriptor(descriptor, isOwnProperty);
- }
- }
-
- function arrayIndexPropertyNames(o, length)
- {
- var array = new Array(length);
- for (var i = 0; i < length; ++i) {
- if (i in o)
- array.push("" + i);
- }
- return array;
- }
-
- // FIXME: <https://webkit.org/b/143589> Web Inspector: Better handling for large collections in Object Trees
- // For array types with a large length we attempt to skip getOwnPropertyNames and instead just sublist of indexes.
- var isArrayTypeWithLargeLength = false;
- try {
- isArrayTypeWithLargeLength = injectedScript._subtype(object) === "array" && isFinite(object.length) && object.length > 100;
- } catch(e) {}
-
- for (var o = object; this._isDefined(o); o = o.__proto__) {
- var isOwnProperty = o === object;
-
- if (isArrayTypeWithLargeLength && isOwnProperty)
- processProperties(o, arrayIndexPropertyNames(o, 100), isOwnProperty);
- else {
- processProperties(o, Object.getOwnPropertyNames(o), isOwnProperty);
- if (Object.getOwnPropertySymbols)
- processProperties(o, Object.getOwnPropertySymbols(o), isOwnProperty);
- }
-
- if (collectionMode === InjectedScript.CollectionMode.OwnProperties)
- break;
- }
-
- // Always include __proto__ at the end.
- try {
- if (object.__proto__)
- descriptors.push({name: "__proto__", value: object.__proto__, writable: true, configurable: true, enumerable: false, isOwn: true});
- } catch (e) {}
-
- return descriptors;
- },
-
+ /**
+ * @param {*} object
+ * @return {boolean}
+ */
_isDefined: function(object)
{
return !!object || this._isHTMLAllCollection(object);
},
+ /**
+ * @param {*} object
+ * @return {boolean}
+ */
_isHTMLAllCollection: function(object)
{
// document.all is reported as undefined, but we still want to process it.
return (typeof object === "undefined") && InjectedScriptHost.isHTMLAllCollection(object);
},
+ /**
+ * @param {Object=} obj
+ * @return {string?}
+ */
_subtype: function(obj)
{
if (obj === null)
return "null";
- if (this.isPrimitiveValue(obj) || isSymbol(obj))
+ if (this.isPrimitiveValue(obj))
return null;
if (this._isHTMLAllCollection(obj))
return "array";
- var preciseType = InjectedScriptHost.subtype(obj);
+ var preciseType = InjectedScriptHost.type(obj);
if (preciseType)
return preciseType;
@@ -769,644 +712,321 @@ InjectedScript.prototype = {
try {
if (typeof obj.splice === "function" && isFinite(obj.length))
return "array";
+ if (Object.prototype.toString.call(obj) === "[object Arguments]" && isFinite(obj.length)) // arguments.
+ return "array";
} catch (e) {
}
+ // If owning frame has navigated to somewhere else window properties will be undefined.
return null;
},
- _nodeDescription: function(node)
- {
- var isXMLDocument = node.ownerDocument && !!node.ownerDocument.xmlVersion;
- var description = isXMLDocument ? node.nodeName : node.nodeName.toLowerCase();
-
- switch (node.nodeType) {
- case 1: // Node.ELEMENT_NODE
- if (node.id)
- description += "#" + node.id;
- if (node.hasAttribute("class")) {
- // Using .getAttribute() is a workaround for SVG*Element.className returning SVGAnimatedString,
- // which doesn't have any useful String methods. See <https://webkit.org/b/145363/>.
- description += "." + node.getAttribute("class").trim().replace(/\s+/g, ".");
- }
- return description;
-
- default:
- return description;
- }
- },
-
- _classPreview: function(classConstructorValue)
- {
- return "class " + classConstructorValue.name;
- },
-
- _nodePreview: function(node)
- {
- var isXMLDocument = node.ownerDocument && !!node.ownerDocument.xmlVersion;
- var nodeName = isXMLDocument ? node.nodeName : node.nodeName.toLowerCase();
-
- switch (node.nodeType) {
- case 1: // Node.ELEMENT_NODE
- if (node.id)
- return "<" + nodeName + " id=\"" + node.id + "\">";
- if (node.classList.length)
- return "<" + nodeName + " class=\"" + node.classList.toString() + "\">";
- if (nodeName === "input" && node.type)
- return "<" + nodeName + " type=\"" + node.type + "\">";
- return "<" + nodeName + ">";
-
- case 3: // Node.TEXT_NODE
- return nodeName + " \"" + node.nodeValue + "\"";
-
- case 8: // Node.COMMENT_NODE
- return "<!--" + node.nodeValue + "-->";
-
- case 10: // Node.DOCUMENT_TYPE_NODE
- return "<!DOCTYPE " + nodeName + ">";
-
- default:
- return nodeName;
- }
- },
-
+ /**
+ * @param {*} obj
+ * @return {string?}
+ */
_describe: function(obj)
{
if (this.isPrimitiveValue(obj))
return null;
- if (isSymbol(obj))
- return toString(obj);
+ obj = /** @type {Object} */ (obj);
+ // Type is object, get subtype.
var subtype = this._subtype(obj);
if (subtype === "regexp")
- return toString(obj);
+ return this._toString(obj);
if (subtype === "date")
- return toString(obj);
-
- if (subtype === "error")
- return toString(obj);
-
- if (subtype === "node")
- return this._nodeDescription(obj);
+ return this._toString(obj);
+
+ if (subtype === "node") {
+ var description = obj.nodeName.toLowerCase();
+ switch (obj.nodeType) {
+ case 1 /* Node.ELEMENT_NODE */:
+ description += obj.id ? "#" + obj.id : "";
+ var className = obj.className;
+ description += className ? "." + className : "";
+ break;
+ case 10 /*Node.DOCUMENT_TYPE_NODE */:
+ description = "<!DOCTYPE " + description + ">";
+ break;
+ }
+ return description;
+ }
var className = InjectedScriptHost.internalConstructorName(obj);
- if (subtype === "array")
+ if (subtype === "array") {
+ if (typeof obj.length === "number")
+ className += "[" + obj.length + "]";
return className;
+ }
// NodeList in JSC is a function, check for array prior to this.
if (typeof obj === "function")
- return toString(obj);
+ return this._toString(obj);
- // If Object, try for a better name from the constructor.
if (className === "Object") {
+ // In Chromium DOM wrapper prototypes will have Object as their constructor name,
+ // get the real DOM wrapper name from the constructor property.
var constructorName = obj.constructor && obj.constructor.name;
if (constructorName)
return constructorName;
}
-
return className;
},
- _getSetEntries: function(object, skip, numberToFetch)
- {
- var entries = [];
-
- for (var value of object) {
- if (skip > 0) {
- skip--;
- continue;
- }
-
- entries.push({value});
-
- if (numberToFetch && entries.length === numberToFetch)
- break;
- }
-
- return entries;
- },
-
- _getMapEntries: function(object, skip, numberToFetch)
- {
- var entries = [];
-
- for (var [key, value] of object) {
- if (skip > 0) {
- skip--;
- continue;
- }
-
- entries.push({key, value});
-
- if (numberToFetch && entries.length === numberToFetch)
- break;
- }
-
- return entries;
- },
-
- _getWeakMapEntries: function(object, numberToFetch)
- {
- return InjectedScriptHost.weakMapEntries(object, numberToFetch);
- },
-
- _getWeakSetEntries: function(object, numberToFetch)
- {
- return InjectedScriptHost.weakSetEntries(object, numberToFetch);
- },
-
- _getIteratorEntries: function(object, numberToFetch)
- {
- return InjectedScriptHost.iteratorEntries(object, numberToFetch);
- },
-
- _entries: function(object, subtype, startIndex, numberToFetch)
- {
- if (subtype === "set")
- return this._getSetEntries(object, startIndex, numberToFetch);
- if (subtype === "map")
- return this._getMapEntries(object, startIndex, numberToFetch);
- if (subtype === "weakmap")
- return this._getWeakMapEntries(object, numberToFetch);
- if (subtype === "weakset")
- return this._getWeakSetEntries(object, numberToFetch);
- if (subtype === "iterator")
- return this._getIteratorEntries(object, numberToFetch);
-
- throw "unexpected type";
- },
-
- _saveResult: function(result)
- {
- this._lastResult = result;
-
- if (result === undefined || result === null)
- return;
-
- var existingIndex = this._savedResults.indexOf(result);
- if (existingIndex !== -1) {
- this._savedResultIndex = existingIndex;
- return;
- }
-
- this._savedResultIndex = this._nextSavedResultIndex;
- this._savedResults[this._nextSavedResultIndex++] = result;
-
- // $n is limited from $1-$99. $0 is special.
- if (this._nextSavedResultIndex >= 100)
- this._nextSavedResultIndex = 1;
- },
-
- _savedResult: function(index)
+ /**
+ * @param {*} obj
+ * @return {string}
+ */
+ _toString: function(obj)
{
- return this._savedResults[index];
+ // We don't use String(obj) because inspectedGlobalObject.String is undefined if owning frame navigated to another page.
+ return "" + obj;
}
}
-var injectedScript = new InjectedScript;
-
-
+/**
+ * @type {InjectedScript}
+ * @const
+ */
+var injectedScript = new InjectedScript();
+
+/**
+ * @constructor
+ * @param {*} object
+ * @param {string=} objectGroupName
+ * @param {boolean=} forceValueType
+ * @param {boolean=} generatePreview
+ * @param {?Array.<string>=} columnNames
+ */
InjectedScript.RemoteObject = function(object, objectGroupName, forceValueType, generatePreview, columnNames)
{
this.type = typeof object;
-
- if (this.type === "undefined" && injectedScript._isHTMLAllCollection(object))
- this.type = "object";
-
if (injectedScript.isPrimitiveValue(object) || object === null || forceValueType) {
// We don't send undefined values over JSON.
- if (this.type !== "undefined")
+ if (typeof object !== "undefined")
this.value = object;
- // Null object is object with 'null' subtype.
+ // Null object is object with 'null' subtype'
if (object === null)
this.subtype = "null";
// Provide user-friendly number values.
- if (this.type === "number")
- this.description = toStringDescription(object);
+ if (typeof object === "number")
+ this.description = object + "";
return;
}
- this.objectId = injectedScript._bind(object, objectGroupName);
+ object = /** @type {Object} */ (object);
+ this.objectId = injectedScript._bind(object, objectGroupName);
var subtype = injectedScript._subtype(object);
if (subtype)
this.subtype = subtype;
-
this.className = InjectedScriptHost.internalConstructorName(object);
this.description = injectedScript._describe(object);
- if (subtype === "array")
- this.size = typeof object.length === "number" ? object.length : 0;
- else if (subtype === "set" || subtype === "map")
- this.size = object.size;
- else if (subtype === "weakmap")
- this.size = InjectedScriptHost.weakMapSize(object);
- else if (subtype === "weakset")
- this.size = InjectedScriptHost.weakSetSize(object);
- else if (subtype === "class") {
- this.classPrototype = injectedScript._wrapObject(object.prototype, objectGroupName);
- this.className = object.name;
- }
-
- if (generatePreview && this.type === "object")
+ if (generatePreview && (this.type === "object" || injectedScript._isHTMLAllCollection(object)))
this.preview = this._generatePreview(object, undefined, columnNames);
}
InjectedScript.RemoteObject.prototype = {
- _initialPreview: function()
- {
- var preview = {
- type: this.type,
- description: this.description || toString(this.value),
- lossless: true,
- };
-
- if (this.subtype) {
- preview.subtype = this.subtype;
- if (this.subtype !== "null") {
- preview.overflow = false;
- preview.properties = [];
- }
- }
-
- if ("size" in this)
- preview.size = this.size;
-
- return preview;
- },
-
- _emptyPreview: function()
- {
- var preview = this._initialPreview();
-
- if (this.subtype === "map" || this.subtype === "set" || this.subtype === "weakmap" || this.subtype === "weakset" || this.subtype === "iterator") {
- if (this.size) {
- preview.entries = [];
- preview.lossless = false;
- preview.overflow = true;
- }
- }
-
- return preview;
- },
-
- _createObjectPreviewForValue: function(value, generatePreview)
- {
- var remoteObject = new InjectedScript.RemoteObject(value, undefined, false, generatePreview, undefined);
- if (remoteObject.objectId)
- injectedScript.releaseObject(remoteObject.objectId);
- if (remoteObject.classPrototype && remoteObject.classPrototype.objectId)
- injectedScript.releaseObject(remoteObject.classPrototype.objectId);
-
- return remoteObject.preview || remoteObject._emptyPreview();
- },
-
+ /**
+ * @param {Object} object
+ * @param {Array.<string>=} firstLevelKeys
+ * @param {?Array.<string>=} secondLevelKeys
+ * @return {Object} preview
+ */
_generatePreview: function(object, firstLevelKeys, secondLevelKeys)
{
- var preview = this._initialPreview();
-
- // Primitives just have a value.
- if (this.type !== "object")
- return;
+ var preview = {};
+ preview.lossless = true;
+ preview.overflow = false;
+ preview.properties = [];
var isTableRowsRequest = secondLevelKeys === null || secondLevelKeys;
var firstLevelKeysCount = firstLevelKeys ? firstLevelKeys.length : 0;
var propertiesThreshold = {
properties: isTableRowsRequest ? 1000 : Math.max(5, firstLevelKeysCount),
- indexes: isTableRowsRequest ? 1000 : Math.max(10, firstLevelKeysCount)
+ indexes: isTableRowsRequest ? 1000 : Math.max(100, firstLevelKeysCount)
};
-
- try {
- // Maps, Sets, and Iterators have entries.
- if (this.subtype === "map" || this.subtype === "set" || this.subtype === "weakmap" || this.subtype === "weakset" || this.subtype === "iterator")
- this._appendEntryPreviews(object, preview);
-
- preview.properties = [];
-
- // Internal Properties.
- var internalPropertyDescriptors = injectedScript._internalPropertyDescriptors(object, true);
- if (internalPropertyDescriptors) {
- this._appendPropertyPreviews(object, preview, internalPropertyDescriptors, true, propertiesThreshold, firstLevelKeys, secondLevelKeys);
- if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0)
- return preview;
- }
-
- if (preview.entries)
- return preview;
-
- // Properties.
- var descriptors = injectedScript._propertyDescriptors(object, InjectedScript.CollectionMode.AllProperties);
- this._appendPropertyPreviews(object, preview, descriptors, false, propertiesThreshold, firstLevelKeys, secondLevelKeys);
- if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0)
- return preview;
- } catch (e) {
- preview.lossless = false;
- }
-
+ for (var o = object; injectedScript._isDefined(o); o = o.__proto__)
+ this._generateProtoPreview(o, preview, propertiesThreshold, firstLevelKeys, secondLevelKeys);
return preview;
},
- _appendPropertyPreviews: function(object, preview, descriptors, internal, propertiesThreshold, firstLevelKeys, secondLevelKeys)
+ /**
+ * @param {Object} object
+ * @param {Object} preview
+ * @param {Object} propertiesThreshold
+ * @param {Array.<string>=} firstLevelKeys
+ * @param {Array.<string>=} secondLevelKeys
+ */
+ _generateProtoPreview: function(object, preview, propertiesThreshold, firstLevelKeys, secondLevelKeys)
{
- for (var descriptor of descriptors) {
- // Seen enough.
- if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0)
- break;
-
- // Error in descriptor.
- if (descriptor.wasThrown) {
- preview.lossless = false;
- continue;
- }
-
- // Do not show "__proto__" in preview.
- var name = descriptor.name;
- if (name === "__proto__")
- continue;
-
- // For arrays, only allow indexes.
- if (this.subtype === "array" && !isUInt32(name))
- continue;
-
- // Do not show non-enumerable non-own properties. Special case to allow array indexes that may be on the prototype.
- if (!descriptor.enumerable && !descriptor.isOwn && this.subtype !== "array")
- continue;
-
- // If we have a filter, only show properties in the filter.
- // FIXME: Currently these filters do nothing on the backend.
- if (firstLevelKeys && !firstLevelKeys.includes(name))
- continue;
-
- // Getter/setter.
- if (!("value" in descriptor)) {
- preview.lossless = false;
- this._appendPropertyPreview(preview, internal, {name, type: "accessor"}, propertiesThreshold);
- continue;
- }
-
- // Null value.
- var value = descriptor.value;
- if (value === null) {
- this._appendPropertyPreview(preview, internal, {name, type: "object", subtype: "null", value: "null"}, propertiesThreshold);
- continue;
- }
-
- // Ignore non-enumerable functions.
- var type = typeof value;
- if (!descriptor.enumerable && type === "function")
- continue;
-
- // Fix type of document.all.
- if (type === "undefined" && injectedScript._isHTMLAllCollection(value))
- type = "object";
-
- // Primitive.
- const maxLength = 100;
- if (InjectedScript.primitiveTypes[type]) {
- if (type === "string" && value.length > maxLength) {
- value = this._abbreviateString(value, maxLength, true);
+ var propertyNames = firstLevelKeys ? firstLevelKeys : Object.keys(/** @type {!Object} */(object));
+ try {
+ for (var i = 0; i < propertyNames.length; ++i) {
+ if (!propertiesThreshold.properties || !propertiesThreshold.indexes) {
+ preview.overflow = true;
preview.lossless = false;
+ break;
}
- this._appendPropertyPreview(preview, internal, {name, type, value: toStringDescription(value)}, propertiesThreshold);
- continue;
- }
+ var name = propertyNames[i];
+ if (this.subtype === "array" && name === "length")
+ continue;
- // Symbol.
- if (isSymbol(value)) {
- var symbolString = toString(value);
- if (symbolString.length > maxLength) {
- symbolString = this._abbreviateString(symbolString, maxLength, true);
+ var descriptor = Object.getOwnPropertyDescriptor(/** @type {!Object} */(object), name);
+ if (!("value" in descriptor) || !descriptor.enumerable) {
preview.lossless = false;
+ continue;
}
- this._appendPropertyPreview(preview, internal, {name, type, value: symbolString}, propertiesThreshold);
- return;
- }
- // Object.
- var property = {name, type};
- var subtype = injectedScript._subtype(value);
- if (subtype)
- property.subtype = subtype;
-
- // Second level.
- if ((secondLevelKeys === null || secondLevelKeys) || this._isPreviewableObject(value, object)) {
- // FIXME: If we want secondLevelKeys filter to continue we would need some refactoring.
- var subPreview = this._createObjectPreviewForValue(value, value !== object);
- property.valuePreview = subPreview;
- if (!subPreview.lossless)
- preview.lossless = false;
- if (subPreview.overflow)
- preview.overflow = true;
- } else {
- var description = "";
- if (type !== "function" || subtype === "class") {
- var fullDescription;
- if (subtype === "class")
- fullDescription = "class " + value.name;
- else if (subtype === "node")
- fullDescription = injectedScript._nodePreview(value);
- else
- fullDescription = injectedScript._describe(value);
- description = this._abbreviateString(fullDescription, maxLength, subtype === "regexp");
+ var value = descriptor.value;
+ if (value === null) {
+ this._appendPropertyPreview(preview, { name: name, type: "object", value: "null" }, propertiesThreshold);
+ continue;
}
- property.value = description;
- preview.lossless = false;
- }
-
- this._appendPropertyPreview(preview, internal, property, propertiesThreshold);
- }
- },
-
- _appendPropertyPreview: function(preview, internal, property, propertiesThreshold)
- {
- if (toString(property.name >>> 0) === property.name)
- propertiesThreshold.indexes--;
- else
- propertiesThreshold.properties--;
- if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0) {
- preview.overflow = true;
- preview.lossless = false;
- return;
- }
-
- if (internal)
- property.internal = true;
-
- preview.properties.push(property);
- },
-
- _appendEntryPreviews: function(object, preview)
- {
- // Fetch 6, but only return 5, so we can tell if we overflowed.
- var entries = injectedScript._entries(object, this.subtype, 0, 6);
- if (!entries)
- return;
+ const maxLength = 100;
+ var type = typeof value;
+
+ if (InjectedScript.primitiveTypes[type]) {
+ if (type === "string") {
+ if (value.length > maxLength) {
+ value = this._abbreviateString(value, maxLength, true);
+ preview.lossless = false;
+ }
+ value = value.replace(/\n/g, "\u21B5");
+ }
+ this._appendPropertyPreview(preview, { name: name, type: type, value: value + "" }, propertiesThreshold);
+ continue;
+ }
- if (entries.length > 5) {
- entries.pop();
- preview.overflow = true;
- preview.lossless = false;
- }
+ if (secondLevelKeys === null || secondLevelKeys) {
+ var subPreview = this._generatePreview(value, secondLevelKeys || undefined);
+ var property = { name: name, type: type, valuePreview: subPreview };
+ this._appendPropertyPreview(preview, property, propertiesThreshold);
+ if (!subPreview.lossless)
+ preview.lossless = false;
+ if (subPreview.overflow)
+ preview.overflow = true;
+ continue;
+ }
- function updateMainPreview(subPreview) {
- if (!subPreview.lossless)
preview.lossless = false;
- }
-
- preview.entries = entries.map(function(entry) {
- entry.value = this._createObjectPreviewForValue(entry.value, entry.value !== object);
- updateMainPreview(entry.value);
- if ("key" in entry) {
- entry.key = this._createObjectPreviewForValue(entry.key, entry.key !== object);
- updateMainPreview(entry.key);
- }
- return entry;
- }, this);
- },
-
- _isPreviewableObject: function(value, object)
- {
- return this._isPreviewableObjectInternal(value, new Set([object]), 1);
- },
-
- _isPreviewableObjectInternal: function(object, knownObjects, depth)
- {
- // Deep object.
- if (depth > 3)
- return false;
-
- // Primitive.
- if (injectedScript.isPrimitiveValue(object) || isSymbol(object))
- return true;
- // Null.
- if (object === null)
- return true;
-
- // Cyclic objects.
- if (knownObjects.has(object))
- return false;
-
- ++depth;
- knownObjects.add(object);
+ var subtype = injectedScript._subtype(value);
+ var description = "";
+ if (type !== "function")
+ description = this._abbreviateString(/** @type {string} */ (injectedScript._describe(value)), maxLength, subtype === "regexp");
- // Arrays are simple if they have 5 or less simple objects.
- var subtype = injectedScript._subtype(object);
- if (subtype === "array") {
- var length = object.length;
- if (length > 5)
- return false;
- for (var i = 0; i < length; ++i) {
- if (!this._isPreviewableObjectInternal(object[i], knownObjects, depth))
- return false;
+ var property = { name: name, type: type, value: description };
+ if (subtype)
+ property.subtype = subtype;
+ this._appendPropertyPreview(preview, property, propertiesThreshold);
}
- return true;
- }
-
- // Not a basic object.
- if (object.__proto__ && object.__proto__.__proto__)
- return false;
-
- // Objects are simple if they have 3 or less simple properties.
- var ownPropertyNames = Object.getOwnPropertyNames(object);
- if (ownPropertyNames.length > 3)
- return false;
- for (var propertyName of ownPropertyNames) {
- if (!this._isPreviewableObjectInternal(object[propertyName], knownObjects, depth))
- return false;
+ } catch (e) {
}
+ },
- return true;
+ /**
+ * @param {Object} preview
+ * @param {Object} property
+ * @param {Object} propertiesThreshold
+ */
+ _appendPropertyPreview: function(preview, property, propertiesThreshold)
+ {
+ if (isNaN(property.name))
+ propertiesThreshold.properties--;
+ else
+ propertiesThreshold.indexes--;
+ preview.properties.push(property);
},
+ /**
+ * @param {string} string
+ * @param {number} maxLength
+ * @param {boolean=} middle
+ * @returns
+ */
_abbreviateString: function(string, maxLength, middle)
{
if (string.length <= maxLength)
return string;
-
if (middle) {
var leftHalf = maxLength >> 1;
var rightHalf = maxLength - leftHalf - 1;
return string.substr(0, leftHalf) + "\u2026" + string.substr(string.length - rightHalf, rightHalf);
}
-
return string.substr(0, maxLength) + "\u2026";
}
}
-
+/**
+ * @constructor
+ * @param {number} ordinal
+ * @param {Object} callFrame
+ */
InjectedScript.CallFrameProxy = function(ordinal, callFrame)
{
this.callFrameId = "{\"ordinal\":" + ordinal + ",\"injectedScriptId\":" + injectedScriptId + "}";
this.functionName = (callFrame.type === "function" ? callFrame.functionName : "");
- this.location = {scriptId: String(callFrame.sourceID), lineNumber: callFrame.line, columnNumber: callFrame.column};
+ this.location = { scriptId: String(callFrame.sourceID), lineNumber: callFrame.line, columnNumber: callFrame.column };
this.scopeChain = this._wrapScopeChain(callFrame);
this.this = injectedScript._wrapObject(callFrame.thisObject, "backtrace");
}
InjectedScript.CallFrameProxy.prototype = {
+ /**
+ * @param {Object} callFrame
+ * @return {!Array.<DebuggerAgent.Scope>}
+ */
_wrapScopeChain: function(callFrame)
{
var scopeChain = callFrame.scopeChain;
var scopeChainProxy = [];
- for (var i = 0; i < scopeChain.length; i++)
- scopeChainProxy[i] = InjectedScript.CallFrameProxy._createScopeJson(callFrame.scopeType(i), scopeChain[i], "backtrace");
+ for (var i = 0; i < scopeChain.length; i++) {
+ var scope = InjectedScript.CallFrameProxy._createScopeJson(callFrame.scopeType(i), scopeChain[i], "backtrace");
+ scopeChainProxy.push(scope);
+ }
return scopeChainProxy;
}
}
-InjectedScript.CallFrameProxy._scopeTypeNames = {
- 0: "global", // GLOBAL_SCOPE
- 1: "local", // LOCAL_SCOPE
- 2: "with", // WITH_SCOPE
- 3: "closure", // CLOSURE_SCOPE
- 4: "catch", // CATCH_SCOPE
- 5: "functionName", // FUNCTION_NAME_SCOPE
-}
+/**
+ * @param {number} scopeTypeCode
+ * @param {*} scopeObject
+ * @param {string} groupId
+ * @return {!DebuggerAgent.Scope}
+ */
+InjectedScript.CallFrameProxy._createScopeJson = function(scopeTypeCode, scopeObject, groupId) {
+ const GLOBAL_SCOPE = 0;
+ const LOCAL_SCOPE = 1;
+ const WITH_SCOPE = 2;
+ const CLOSURE_SCOPE = 3;
+ const CATCH_SCOPE = 4;
+
+ /** @type {!Object.<number, string>} */
+ var scopeTypeNames = {};
+ scopeTypeNames[GLOBAL_SCOPE] = "global";
+ scopeTypeNames[LOCAL_SCOPE] = "local";
+ scopeTypeNames[WITH_SCOPE] = "with";
+ scopeTypeNames[CLOSURE_SCOPE] = "closure";
+ scopeTypeNames[CATCH_SCOPE] = "catch";
-InjectedScript.CallFrameProxy._createScopeJson = function(scopeTypeCode, scopeObject, groupId)
-{
return {
object: injectedScript._wrapObject(scopeObject, groupId),
- type: InjectedScript.CallFrameProxy._scopeTypeNames[scopeTypeCode]
+ type: /** @type {DebuggerAgent.ScopeType} */ (scopeTypeNames[scopeTypeCode])
};
}
-
-function slice(array, index)
-{
- var result = [];
- for (var i = index || 0; i < array.length; ++i)
- result.push(array[i]);
- return result;
-}
-
-function bind(func, thisObject, var_args)
-{
- var args = slice(arguments, 2);
- return function(var_args) {
- return func.apply(thisObject, args.concat(slice(arguments)));
- }
-}
-
function BasicCommandLineAPI()
{
this.$_ = injectedScript._lastResult;
- this.$exception = injectedScript._exceptionValue;
-
- // $1-$99
- for (var i = 1; i <= injectedScript._savedResults.length; ++i) {
- var member = "$" + i;
- if (member in inspectedGlobalObject)
- continue;
- this.__defineGetter__("$" + i, bind(injectedScript._savedResult, injectedScript, i));
- }
}
return injectedScript;