diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-05-20 09:56:07 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-05-20 09:56:07 +0000 |
commit | 41386e9cb918eed93b3f13648cbef387e371e451 (patch) | |
tree | a97f9d7bd1d9d091833286085f72da9d83fd0606 /Source/JavaScriptCore/inspector/InjectedScriptSource.js | |
parent | e15dd966d523731101f70ccf768bba12435a0208 (diff) | |
download | WebKitGtk-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.js | 1314 |
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; |