2 * Copyright (C) 2007 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //# sourceURL=__WebInspectorInjectedScript__
32 * @param {InjectedScriptHost} InjectedScriptHost
33 * @param {GlobalObject} inspectedGlobalObject
34 * @param {number} injectedScriptId
36 (function (InjectedScriptHost
, inspectedGlobalObject
, injectedScriptId
) {
38 // Protect against Object overwritten by the user code.
39 var Object
= {}.constructor;
44 var InjectedScript = function()
46 this._lastBoundObjectId
= 1;
47 this._idToWrappedObject
= {};
48 this._idToObjectGroupName
= {};
49 this._objectGroups
= {};
54 * @type {Object.<string, boolean>}
57 InjectedScript
.primitiveTypes
= {
64 InjectedScript
.prototype = {
69 isPrimitiveValue: function(object
)
71 // FIXME(33716): typeof document.all is always 'undefined'.
72 return InjectedScript
.primitiveTypes
[typeof object
] && !this._isHTMLAllCollection(object
);
77 * @param {string} groupName
78 * @param {boolean} canAccessInspectedGlobalObject
79 * @param {boolean} generatePreview
80 * @return {!RuntimeAgent.RemoteObject}
82 wrapObject: function(object
, groupName
, canAccessInspectedGlobalObject
, generatePreview
)
84 if (canAccessInspectedGlobalObject
)
85 return this._wrapObject(object
, groupName
, false, generatePreview
);
86 return this._fallbackWrapper(object
);
91 * @return {!RuntimeAgent.RemoteObject}
93 _fallbackWrapper: function(object
)
96 result
.type
= typeof object
;
97 if (this.isPrimitiveValue(object
))
98 result
.value
= object
;
100 result
.description
= this._toString(object
);
101 return /** @type {!RuntimeAgent.RemoteObject} */ (result
);
105 * @param {boolean} canAccessInspectedGlobalObject
106 * @param {Object} table
107 * @param {Array.<string>|string|boolean} columns
108 * @return {!RuntimeAgent.RemoteObject}
110 wrapTable: function(canAccessInspectedGlobalObject
, table
, columns
)
112 if (!canAccessInspectedGlobalObject
)
113 return this._fallbackWrapper(table
);
114 var columnNames
= null;
115 if (typeof columns
=== "string")
117 if (InjectedScriptHost
.type(columns
) == "array") {
119 for (var i
= 0; i
< columns
.length
; ++i
)
120 columnNames
.push(String(columns
[i
]));
122 return this._wrapObject(table
, "console", false, true, columnNames
);
128 inspectObject: function(object
)
130 if (this._commandLineAPIImpl
)
131 this._commandLineAPIImpl
.inspect(object
);
135 * This method cannot throw.
137 * @param {string=} objectGroupName
138 * @param {boolean=} forceValueType
139 * @param {boolean=} generatePreview
140 * @param {?Array.<string>=} columnNames
141 * @return {!RuntimeAgent.RemoteObject}
142 * @suppress {checkTypes}
144 _wrapObject: function(object
, objectGroupName
, forceValueType
, generatePreview
, columnNames
)
147 return new InjectedScript
.RemoteObject(object
, objectGroupName
, forceValueType
, generatePreview
, columnNames
);
150 var description
= injectedScript
._describe(e
);
152 var description
= "<failed to convert exception to string>";
154 return new InjectedScript
.RemoteObject(description
);
160 * @param {string=} objectGroupName
163 _bind: function(object
, objectGroupName
)
165 var id
= this._lastBoundObjectId
++;
166 this._idToWrappedObject
[id
] = object
;
167 var objectId
= "{\"injectedScriptId\":" + injectedScriptId
+ ",\"id\":" + id
+ "}";
168 if (objectGroupName
) {
169 var group
= this._objectGroups
[objectGroupName
];
172 this._objectGroups
[objectGroupName
] = group
;
175 this._idToObjectGroupName
[id
] = objectGroupName
;
181 * @param {string} objectId
184 _parseObjectId: function(objectId
)
186 return InjectedScriptHost
.evaluate("(" + objectId
+ ")");
190 * @param {string} objectGroupName
192 releaseObjectGroup: function(objectGroupName
)
194 var group
= this._objectGroups
[objectGroupName
];
197 for (var i
= 0; i
< group
.length
; i
++)
198 this._releaseObject(group
[i
]);
199 delete this._objectGroups
[objectGroupName
];
203 * @param {string} methodName
204 * @param {string} args
207 dispatch: function(methodName
, args
)
209 var argsArray
= InjectedScriptHost
.evaluate("(" + args
+ ")");
210 var result
= this[methodName
].apply(this, argsArray
);
211 if (typeof result
=== "undefined") {
212 if (inspectedGlobalObject
.console
)
213 inspectedGlobalObject
.console
.error("Web Inspector error: InjectedScript.%s returns undefined", methodName
);
220 * @param {string} objectId
221 * @param {boolean} ownProperties
222 * @return {Array.<RuntimeAgent.PropertyDescriptor>|boolean}
224 getProperties: function(objectId
, ownProperties
)
226 var parsedObjectId
= this._parseObjectId(objectId
);
227 var object
= this._objectForId(parsedObjectId
);
228 var objectGroupName
= this._idToObjectGroupName
[parsedObjectId
.id
];
230 if (!this._isDefined(object
))
232 var descriptors
= this._propertyDescriptors(object
, ownProperties
);
234 // Go over properties, wrap object values.
235 for (var i
= 0; i
< descriptors
.length
; ++i
) {
236 var descriptor
= descriptors
[i
];
237 if ("get" in descriptor
)
238 descriptor
.get = this._wrapObject(descriptor
.get, objectGroupName
);
239 if ("set" in descriptor
)
240 descriptor
.set = this._wrapObject(descriptor
.set, objectGroupName
);
241 if ("value" in descriptor
)
242 descriptor
.value
= this._wrapObject(descriptor
.value
, objectGroupName
);
243 if (!("configurable" in descriptor
))
244 descriptor
.configurable
= false;
245 if (!("enumerable" in descriptor
))
246 descriptor
.enumerable
= false;
252 * @param {string} objectId
253 * @return {Array.<Object>|boolean}
255 getInternalProperties: function(objectId
, ownProperties
)
257 var parsedObjectId
= this._parseObjectId(objectId
);
258 var object
= this._objectForId(parsedObjectId
);
259 var objectGroupName
= this._idToObjectGroupName
[parsedObjectId
.id
];
260 if (!this._isDefined(object
))
262 var descriptors
= [];
263 var internalProperties
= InjectedScriptHost
.getInternalProperties(object
);
264 if (internalProperties
) {
265 for (var i
= 0; i
< internalProperties
.length
; i
++) {
266 var property
= internalProperties
[i
];
269 value: this._wrapObject(property
.value
, objectGroupName
)
271 descriptors
.push(descriptor
);
278 * @param {string} functionId
279 * @return {!DebuggerAgent.FunctionDetails|string}
281 getFunctionDetails: function(functionId
)
283 var parsedFunctionId
= this._parseObjectId(functionId
);
284 var func
= this._objectForId(parsedFunctionId
);
285 if (typeof func
!== "function")
286 return "Cannot resolve function by id.";
287 var details
= InjectedScriptHost
.functionDetails(func
);
289 return "Cannot resolve function details.";
290 if ("rawScopes" in details
) {
291 var objectGroupName
= this._idToObjectGroupName
[parsedFunctionId
.id
];
292 var rawScopes
= details
.rawScopes
;
294 delete details
.rawScopes
;
295 for (var i
= 0; i
< rawScopes
.length
; i
++)
296 scopes
.push(InjectedScript
.CallFrameProxy
._createScopeJson(rawScopes
[i
].type
, rawScopes
[i
].object
, objectGroupName
));
297 details
.scopeChain
= scopes
;
303 * @param {string} objectId
305 releaseObject: function(objectId
)
307 var parsedObjectId
= this._parseObjectId(objectId
);
308 this._releaseObject(parsedObjectId
.id
);
314 _releaseObject: function(id
)
316 delete this._idToWrappedObject
[id
];
317 delete this._idToObjectGroupName
[id
];
321 * @param {Object} object
322 * @param {boolean} ownProperties
323 * @return {Array.<Object>}
325 _propertyDescriptors: function(object
, ownProperties
)
327 var descriptors
= [];
328 var nameProcessed
= {};
329 nameProcessed
["__proto__"] = null;
330 for (var o
= object
; this._isDefined(o
); o
= o
.__proto__
) {
331 var names
= Object
.getOwnPropertyNames(/** @type {!Object} */ (o
));
332 for (var i
= 0; i
< names
.length
; ++i
) {
334 if (nameProcessed
[name
])
338 nameProcessed
[name
] = true;
339 var descriptor
= Object
.getOwnPropertyDescriptor(/** @type {!Object} */ (object
), name
);
341 // Not all bindings provide proper descriptors. Fall back to the writable, configurable property.
343 descriptor
= { name: name
, value: object
[name
], writable: false, configurable: false, enumerable: false};
345 descriptor
.isOwn
= true;
346 descriptors
.push(descriptor
);
352 if (descriptor
.hasOwnProperty("get") && descriptor
.hasOwnProperty("set") && !descriptor
.get && !descriptor
.set) {
353 // Not all bindings provide proper descriptors. Fall back to the writable, configurable property.
355 descriptor
= { name: name
, value: object
[name
], writable: false, configurable: false, enumerable: false};
357 descriptor
.isOwn
= true;
358 descriptors
.push(descriptor
);
366 descriptor
.value
= e
;
367 descriptor
.wasThrown
= true;
370 descriptor
.name
= name
;
372 descriptor
.isOwn
= true;
373 descriptors
.push(descriptor
);
376 if (object
.__proto__
)
377 descriptors
.push({ name: "__proto__", value: object
.__proto__
, writable: true, configurable: true, enumerable: false, isOwn: true});
385 * @param {string} expression
386 * @param {string} objectGroup
387 * @param {boolean} injectCommandLineAPI
388 * @param {boolean} returnByValue
389 * @param {boolean} generatePreview
392 evaluate: function(expression
, objectGroup
, injectCommandLineAPI
, returnByValue
, generatePreview
)
394 return this._evaluateAndWrap(InjectedScriptHost
.evaluate
, InjectedScriptHost
, expression
, objectGroup
, false, injectCommandLineAPI
, returnByValue
, generatePreview
);
398 * @param {string} objectId
399 * @param {string} expression
400 * @param {boolean} returnByValue
401 * @return {Object|string}
403 callFunctionOn: function(objectId
, expression
, args
, returnByValue
)
405 var parsedObjectId
= this._parseObjectId(objectId
);
406 var object
= this._objectForId(parsedObjectId
);
407 if (!this._isDefined(object
))
408 return "Could not find object with given id";
411 var resolvedArgs
= [];
412 args
= InjectedScriptHost
.evaluate(args
);
413 for (var i
= 0; i
< args
.length
; ++i
) {
414 var resolvedCallArgument
;
416 resolvedCallArgument
= this._resolveCallArgument(args
[i
]);
420 resolvedArgs
.push(resolvedCallArgument
)
425 var objectGroup
= this._idToObjectGroupName
[parsedObjectId
.id
];
426 var func
= InjectedScriptHost
.evaluate("(" + expression
+ ")");
427 if (typeof func
!== "function")
428 return "Given expression does not evaluate to a function";
430 return { wasThrown: false,
431 result: this._wrapObject(func
.apply(object
, resolvedArgs
), objectGroup
, returnByValue
) };
433 return this._createThrownValue(e
, objectGroup
);
438 * Resolves a value from CallArgument description.
439 * @param {RuntimeAgent.CallArgument} callArgumentJson
440 * @return {*} resolved value
441 * @throws {string} error message
443 _resolveCallArgument: function(callArgumentJson
) {
444 var objectId
= callArgumentJson
.objectId
;
446 var parsedArgId
= this._parseObjectId(objectId
);
447 if (!parsedArgId
|| parsedArgId
["injectedScriptId"] !== injectedScriptId
)
448 throw "Arguments should belong to the same JavaScript world as the target object.";
450 var resolvedArg
= this._objectForId(parsedArgId
);
451 if (!this._isDefined(resolvedArg
))
452 throw "Could not find object with given id";
455 } else if ("value" in callArgumentJson
)
456 return callArgumentJson
.value
;
462 * @param {Function} evalFunction
463 * @param {Object} object
464 * @param {string} objectGroup
465 * @param {boolean} isEvalOnCallFrame
466 * @param {boolean} injectCommandLineAPI
467 * @param {boolean} returnByValue
468 * @param {boolean} generatePreview
471 _evaluateAndWrap: function(evalFunction
, object
, expression
, objectGroup
, isEvalOnCallFrame
, injectCommandLineAPI
, returnByValue
, generatePreview
)
474 return { wasThrown: false,
475 result: this._wrapObject(this._evaluateOn(evalFunction
, object
, objectGroup
, expression
, isEvalOnCallFrame
, injectCommandLineAPI
), objectGroup
, returnByValue
, generatePreview
) };
477 return this._createThrownValue(e
, objectGroup
);
483 * @param {string} objectGroup
486 _createThrownValue: function(value
, objectGroup
)
488 var remoteObject
= this._wrapObject(value
, objectGroup
);
490 remoteObject
.description
= this._toString(value
);
492 return { wasThrown: true,
493 result: remoteObject
};
497 * @param {Function} evalFunction
498 * @param {Object} object
499 * @param {string} objectGroup
500 * @param {string} expression
501 * @param {boolean} isEvalOnCallFrame
502 * @param {boolean} injectCommandLineAPI
505 _evaluateOn: function(evalFunction
, object
, objectGroup
, expression
, isEvalOnCallFrame
, injectCommandLineAPI
)
507 var commandLineAPI
= null;
508 if (injectCommandLineAPI
) {
509 if (this.CommandLineAPI
)
510 commandLineAPI
= new this.CommandLineAPI(this._commandLineAPIImpl
, isEvalOnCallFrame
? object : null);
512 commandLineAPI
= new BasicCommandLineAPI
;
515 if (isEvalOnCallFrame
) {
516 // We can only use this approach if the evaluate function is the true 'eval'. That allows us to use it with
517 // the 'eval' identifier when calling it. Using 'eval' grants access to the local scope of the closure we
518 // create that provides the command line APIs.
520 var parameters
= [InjectedScriptHost
.evaluate
, expression
];
521 var expressionFunctionBody
= "" +
522 "var global = Function('return this')() || (1, eval)('this');" +
523 "var __originalEval = global.eval; global.eval = __eval;" +
524 "try { return eval(__currentExpression); }" +
525 "finally { global.eval = __originalEval; }";
527 if (commandLineAPI
) {
528 // To avoid using a 'with' statement (which fails in strict mode and requires injecting the API object)
529 // we instead create a closure where we evaluate the expression. The command line APIs are passed as
530 // parameters to the closure so they are in scope but not injected. This allows the code evaluated in
531 // the console to stay in strict mode (if is was already set), or to get strict mode by prefixing
532 // expressions with 'use strict';.
534 var parameterNames
= Object
.getOwnPropertyNames(commandLineAPI
);
535 for (var i
= 0; i
< parameterNames
.length
; ++i
)
536 parameters
.push(commandLineAPI
[parameterNames
[i
]]);
538 var expressionFunctionString
= "(function(__eval, __currentExpression, " + parameterNames
.join(", ") + ") { " + expressionFunctionBody
+ " })";
540 // Use a closure in this case too to keep the same behavior of 'var' being captured by the closure instead
541 // of leaking out into the calling scope.
542 var expressionFunctionString
= "(function(__eval, __currentExpression) { " + expressionFunctionBody
+ " })";
545 // Bind 'this' to the function expression using another closure instead of Function.prototype.bind. This ensures things will work if the page replaces bind.
546 var boundExpressionFunctionString
= "(function(__function, __thisObject) { return function() { return __function.apply(__thisObject, arguments) }; })(" + expressionFunctionString
+ ", this)";
547 var expressionFunction
= evalFunction
.call(object
, boundExpressionFunctionString
);
548 var result
= expressionFunction
.apply(null, parameters
);
550 if (objectGroup
=== "console")
551 this._lastResult
= result
;
556 // When not evaluating on a call frame we use a 'with' statement to allow var and function statements to leak
557 // into the global scope. This allow them to stick around between evaluations.
560 if (commandLineAPI
) {
561 if (inspectedGlobalObject
.console
)
562 inspectedGlobalObject
.console
.__commandLineAPI
= commandLineAPI
;
564 inspectedGlobalObject
.__commandLineAPI
= commandLineAPI
;
565 expression
= "with ((this && (this.console ? this.console.__commandLineAPI : this.__commandLineAPI)) || {}) { " + expression
+ "\n}";
568 var result
= evalFunction
.call(inspectedGlobalObject
, expression
);
570 if (objectGroup
=== "console")
571 this._lastResult
= result
;
575 if (commandLineAPI
) {
576 if (inspectedGlobalObject
.console
)
577 delete inspectedGlobalObject
.console
.__commandLineAPI
;
579 delete inspectedGlobalObject
.__commandLineAPI
;
585 * @param {Object} callFrame
586 * @return {Array.<InjectedScript.CallFrameProxy>|boolean}
588 wrapCallFrames: function(callFrame
)
596 result
.push(new InjectedScript
.CallFrameProxy(depth
++, callFrame
));
597 callFrame
= callFrame
.caller
;
603 * @param {Object} topCallFrame
604 * @param {string} callFrameId
605 * @param {string} expression
606 * @param {string} objectGroup
607 * @param {boolean} injectCommandLineAPI
608 * @param {boolean} returnByValue
609 * @param {boolean} generatePreview
612 evaluateOnCallFrame: function(topCallFrame
, callFrameId
, expression
, objectGroup
, injectCommandLineAPI
, returnByValue
, generatePreview
)
614 var callFrame
= this._callFrameForId(topCallFrame
, callFrameId
);
616 return "Could not find call frame with given id";
617 return this._evaluateAndWrap(callFrame
.evaluate
, callFrame
, expression
, objectGroup
, true, injectCommandLineAPI
, returnByValue
, generatePreview
);
621 * @param {Object} topCallFrame
622 * @param {string} callFrameId
625 _callFrameForId: function(topCallFrame
, callFrameId
)
627 var parsedCallFrameId
= InjectedScriptHost
.evaluate("(" + callFrameId
+ ")");
628 var ordinal
= parsedCallFrameId
["ordinal"];
629 var callFrame
= topCallFrame
;
630 while (--ordinal
>= 0 && callFrame
)
631 callFrame
= callFrame
.caller
;
636 * @param {Object} objectId
639 _objectForId: function(objectId
)
641 return this._idToWrappedObject
[objectId
.id
];
645 * @param {string} objectId
648 findObjectById: function(objectId
)
650 var parsedObjectId
= this._parseObjectId(objectId
);
651 return this._objectForId(parsedObjectId
);
655 * @param {string} name
658 module: function(name
)
660 return this._modules
[name
];
664 * @param {string} name
665 * @param {string} source
668 injectModule: function(name
, source
, host
)
670 delete this._modules
[name
];
671 var moduleFunction
= InjectedScriptHost
.evaluate("(" + source
+ ")");
672 if (typeof moduleFunction
!== "function") {
673 if (inspectedGlobalObject
.console
)
674 inspectedGlobalObject
.console
.error("Web Inspector error: A function was expected for module %s evaluation", name
);
677 var module
= moduleFunction
.call(inspectedGlobalObject
, InjectedScriptHost
, inspectedGlobalObject
, injectedScriptId
, this, host
);
678 this._modules
[name
] = module
;
686 _isDefined: function(object
)
688 return !!object
|| this._isHTMLAllCollection(object
);
695 _isHTMLAllCollection: function(object
)
697 // document.all is reported as undefined, but we still want to process it.
698 return (typeof object
=== "undefined") && InjectedScriptHost
.isHTMLAllCollection(object
);
702 * @param {Object=} obj
705 _subtype: function(obj
)
710 if (this.isPrimitiveValue(obj
))
713 if (this._isHTMLAllCollection(obj
))
716 var preciseType
= InjectedScriptHost
.type(obj
);
720 // FireBug's array detection.
722 if (typeof obj
.splice
=== "function" && isFinite(obj
.length
))
724 if (Object
.prototype.toString
.call(obj
) === "[object Arguments]" && isFinite(obj
.length
)) // arguments.
729 // If owning frame has navigated to somewhere else window properties will be undefined.
737 _describe: function(obj
)
739 if (this.isPrimitiveValue(obj
))
742 obj
= /** @type {Object} */ (obj
);
744 // Type is object, get subtype.
745 var subtype
= this._subtype(obj
);
747 if (subtype
=== "regexp")
748 return this._toString(obj
);
750 if (subtype
=== "date")
751 return this._toString(obj
);
753 if (subtype
=== "node") {
754 var description
= obj
.nodeName
.toLowerCase();
755 switch (obj
.nodeType
) {
756 case 1 /* Node.ELEMENT_NODE */:
757 description
+= obj
.id
? "#" + obj
.id : "";
758 var className
= obj
.className
;
759 description
+= className
? "." + className : "";
761 case 10 /*Node.DOCUMENT_TYPE_NODE */:
762 description
= "<!DOCTYPE " + description
+ ">";
768 var className
= InjectedScriptHost
.internalConstructorName(obj
);
769 if (subtype
=== "array") {
770 if (typeof obj
.length
=== "number")
771 className
+= "[" + obj
.length
+ "]";
775 // NodeList in JSC is a function, check for array prior to this.
776 if (typeof obj
=== "function")
777 return this._toString(obj
);
779 if (className
=== "Object") {
780 // In Chromium DOM wrapper prototypes will have Object as their constructor name,
781 // get the real DOM wrapper name from the constructor property.
782 var constructorName
= obj
.constructor && obj
.constructor.name
;
784 return constructorName
;
793 _toString: function(obj
)
795 // We don't use String(obj) because inspectedGlobalObject.String is undefined if owning frame navigated to another page.
801 * @type {InjectedScript}
804 var injectedScript
= new InjectedScript();
809 * @param {string=} objectGroupName
810 * @param {boolean=} forceValueType
811 * @param {boolean=} generatePreview
812 * @param {?Array.<string>=} columnNames
814 InjectedScript
.RemoteObject = function(object
, objectGroupName
, forceValueType
, generatePreview
, columnNames
)
816 this.type
= typeof object
;
817 if (injectedScript
.isPrimitiveValue(object
) || object
=== null || forceValueType
) {
818 // We don't send undefined values over JSON.
819 if (typeof object
!== "undefined")
822 // Null object is object with 'null' subtype'
824 this.subtype
= "null";
826 // Provide user-friendly number values.
827 if (typeof object
=== "number")
828 this.description
= object
+ "";
832 object
= /** @type {Object} */ (object
);
834 this.objectId
= injectedScript
._bind(object
, objectGroupName
);
835 var subtype
= injectedScript
._subtype(object
);
837 this.subtype
= subtype
;
838 this.className
= InjectedScriptHost
.internalConstructorName(object
);
839 this.description
= injectedScript
._describe(object
);
841 if (generatePreview
&& (this.type
=== "object" || injectedScript
._isHTMLAllCollection(object
)))
842 this.preview
= this._generatePreview(object
, undefined, columnNames
);
845 InjectedScript
.RemoteObject
.prototype = {
847 * @param {Object} object
848 * @param {Array.<string>=} firstLevelKeys
849 * @param {?Array.<string>=} secondLevelKeys
850 * @return {Object} preview
852 _generatePreview: function(object
, firstLevelKeys
, secondLevelKeys
)
855 preview
.lossless
= true;
856 preview
.overflow
= false;
857 preview
.properties
= [];
859 var isTableRowsRequest
= secondLevelKeys
=== null || secondLevelKeys
;
860 var firstLevelKeysCount
= firstLevelKeys
? firstLevelKeys
.length : 0;
862 var propertiesThreshold
= {
863 properties: isTableRowsRequest
? 1000 : Math
.max(5, firstLevelKeysCount
),
864 indexes: isTableRowsRequest
? 1000 : Math
.max(100, firstLevelKeysCount
)
866 for (var o
= object
; injectedScript
._isDefined(o
); o
= o
.__proto__
)
867 this._generateProtoPreview(o
, preview
, propertiesThreshold
, firstLevelKeys
, secondLevelKeys
);
872 * @param {Object} object
873 * @param {Object} preview
874 * @param {Object} propertiesThreshold
875 * @param {Array.<string>=} firstLevelKeys
876 * @param {Array.<string>=} secondLevelKeys
878 _generateProtoPreview: function(object
, preview
, propertiesThreshold
, firstLevelKeys
, secondLevelKeys
)
880 var propertyNames
= firstLevelKeys
? firstLevelKeys : Object
.keys(/** @type {!Object} */(object
));
882 for (var i
= 0; i
< propertyNames
.length
; ++i
) {
883 if (!propertiesThreshold
.properties
|| !propertiesThreshold
.indexes
) {
884 preview
.overflow
= true;
885 preview
.lossless
= false;
888 var name
= propertyNames
[i
];
889 if (this.subtype
=== "array" && name
=== "length")
892 var descriptor
= Object
.getOwnPropertyDescriptor(/** @type {!Object} */(object
), name
);
893 if (!("value" in descriptor
) || !descriptor
.enumerable
) {
894 preview
.lossless
= false;
898 var value
= descriptor
.value
;
899 if (value
=== null) {
900 this._appendPropertyPreview(preview
, { name: name
, type: "object", value: "null" }, propertiesThreshold
);
904 const maxLength
= 100;
905 var type
= typeof value
;
907 if (InjectedScript
.primitiveTypes
[type
]) {
908 if (type
=== "string") {
909 if (value
.length
> maxLength
) {
910 value
= this._abbreviateString(value
, maxLength
, true);
911 preview
.lossless
= false;
913 value
= value
.replace(/\n/g, "\u21B5");
915 this._appendPropertyPreview(preview
, { name: name
, type: type
, value: value
+ "" }, propertiesThreshold
);
919 if (secondLevelKeys
=== null || secondLevelKeys
) {
920 var subPreview
= this._generatePreview(value
, secondLevelKeys
|| undefined);
921 var property
= { name: name
, type: type
, valuePreview: subPreview
};
922 this._appendPropertyPreview(preview
, property
, propertiesThreshold
);
923 if (!subPreview
.lossless
)
924 preview
.lossless
= false;
925 if (subPreview
.overflow
)
926 preview
.overflow
= true;
930 preview
.lossless
= false;
932 var subtype
= injectedScript
._subtype(value
);
933 var description
= "";
934 if (type
!== "function")
935 description
= this._abbreviateString(/** @type {string} */ (injectedScript
._describe(value
)), maxLength
, subtype
=== "regexp");
937 var property
= { name: name
, type: type
, value: description
};
939 property
.subtype
= subtype
;
940 this._appendPropertyPreview(preview
, property
, propertiesThreshold
);
947 * @param {Object} preview
948 * @param {Object} property
949 * @param {Object} propertiesThreshold
951 _appendPropertyPreview: function(preview
, property
, propertiesThreshold
)
953 if (isNaN(property
.name
))
954 propertiesThreshold
.properties
--;
956 propertiesThreshold
.indexes
--;
957 preview
.properties
.push(property
);
961 * @param {string} string
962 * @param {number} maxLength
963 * @param {boolean=} middle
966 _abbreviateString: function(string
, maxLength
, middle
)
968 if (string
.length
<= maxLength
)
971 var leftHalf
= maxLength
>> 1;
972 var rightHalf
= maxLength
- leftHalf
- 1;
973 return string
.substr(0, leftHalf
) + "\u2026" + string
.substr(string
.length
- rightHalf
, rightHalf
);
975 return string
.substr(0, maxLength
) + "\u2026";
980 * @param {number} ordinal
981 * @param {Object} callFrame
983 InjectedScript
.CallFrameProxy = function(ordinal
, callFrame
)
985 this.callFrameId
= "{\"ordinal\":" + ordinal
+ ",\"injectedScriptId\":" + injectedScriptId
+ "}";
986 this.functionName
= (callFrame
.type
=== "function" ? callFrame
.functionName : "");
987 this.location
= { scriptId: String(callFrame
.sourceID
), lineNumber: callFrame
.line
, columnNumber: callFrame
.column
};
988 this.scopeChain
= this._wrapScopeChain(callFrame
);
989 this.this = injectedScript
._wrapObject(callFrame
.thisObject
, "backtrace");
992 InjectedScript
.CallFrameProxy
.prototype = {
994 * @param {Object} callFrame
995 * @return {!Array.<DebuggerAgent.Scope>}
997 _wrapScopeChain: function(callFrame
)
999 var scopeChain
= callFrame
.scopeChain
;
1000 var scopeChainProxy
= [];
1001 for (var i
= 0; i
< scopeChain
.length
; i
++) {
1002 var scope
= InjectedScript
.CallFrameProxy
._createScopeJson(callFrame
.scopeType(i
), scopeChain
[i
], "backtrace");
1003 scopeChainProxy
.push(scope
);
1005 return scopeChainProxy
;
1010 * @param {number} scopeTypeCode
1011 * @param {*} scopeObject
1012 * @param {string} groupId
1013 * @return {!DebuggerAgent.Scope}
1015 InjectedScript
.CallFrameProxy
._createScopeJson = function(scopeTypeCode
, scopeObject
, groupId
) {
1016 const GLOBAL_SCOPE
= 0;
1017 const LOCAL_SCOPE
= 1;
1018 const WITH_SCOPE
= 2;
1019 const CLOSURE_SCOPE
= 3;
1020 const CATCH_SCOPE
= 4;
1022 /** @type {!Object.<number, string>} */
1023 var scopeTypeNames
= {};
1024 scopeTypeNames
[GLOBAL_SCOPE
] = "global";
1025 scopeTypeNames
[LOCAL_SCOPE
] = "local";
1026 scopeTypeNames
[WITH_SCOPE
] = "with";
1027 scopeTypeNames
[CLOSURE_SCOPE
] = "closure";
1028 scopeTypeNames
[CATCH_SCOPE
] = "catch";
1031 object: injectedScript
._wrapObject(scopeObject
, groupId
),
1032 type: /** @type {DebuggerAgent.ScopeType} */ (scopeTypeNames
[scopeTypeCode
])
1036 function BasicCommandLineAPI()
1038 this.$_
= injectedScript
._lastResult
;
1041 return injectedScript
;