Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(163)

Side by Side Diff: third_party/WebKit/Source/core/inspector/InjectedScriptSource.js

Issue 1648523002: DevTools: move InjectedScript* to inspector/v8. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2013 Google Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 "use strict";
31
32 /**
33 * @param {!InjectedScriptHostClass} InjectedScriptHost
34 * @param {!Window|!WorkerGlobalScope} inspectedGlobalObject
35 * @param {number} injectedScriptId
36 */
37 (function (InjectedScriptHost, inspectedGlobalObject, injectedScriptId) {
38
39 /**
40 * Protect against Object overwritten by the user code.
41 * @suppress {duplicate}
42 */
43 var Object = /** @type {function(new:Object, *=)} */ ({}.constructor);
44
45 /**
46 * @param {!Array.<T>} array
47 * @param {...} var_args
48 * @template T
49 */
50 function push(array, var_args)
51 {
52 for (var i = 1; i < arguments.length; ++i)
53 array[array.length] = arguments[i];
54 }
55
56 /**
57 * @param {(!Arguments.<T>|!NodeList)} array
58 * @param {number=} index
59 * @return {!Array.<T>}
60 * @template T
61 */
62 function slice(array, index)
63 {
64 var result = [];
65 for (var i = index || 0, j = 0; i < array.length; ++i, ++j)
66 result[j] = array[i];
67 return result;
68 }
69
70 /**
71 * @param {!Array.<T>} array1
72 * @param {!Array.<T>} array2
73 * @return {!Array.<T>}
74 * @template T
75 */
76 function concat(array1, array2)
77 {
78 var result = [];
79 for (var i = 0; i < array1.length; ++i)
80 push(result, array1[i]);
81 for (var i = 0; i < array2.length; ++i)
82 push(result, array2[i]);
83 return result;
84 }
85
86 /**
87 * @param {*} obj
88 * @return {string}
89 * @suppress {uselessCode}
90 */
91 function toString(obj)
92 {
93 // We don't use String(obj) because String could be overridden.
94 // Also the ("" + obj) expression may throw.
95 try {
96 return "" + obj;
97 } catch (e) {
98 var name = InjectedScriptHost.internalConstructorName(obj) || InjectedSc riptHost.subtype(obj) || (typeof obj);
99 return "#<" + name + ">";
100 }
101 }
102
103 /**
104 * @param {*} obj
105 * @return {string}
106 */
107 function toStringDescription(obj)
108 {
109 if (typeof obj === "number" && obj === 0 && 1 / obj < 0)
110 return "-0"; // Negative zero.
111 return toString(obj);
112 }
113
114 /**
115 * Please use this bind, not the one from Function.prototype
116 * @param {function(...)} func
117 * @param {?Object} thisObject
118 * @param {...} var_args
119 * @return {function(...)}
120 */
121 function bind(func, thisObject, var_args)
122 {
123 var args = slice(arguments, 2);
124
125 /**
126 * @param {...} var_args
127 */
128 function bound(var_args)
129 {
130 return InjectedScriptHost.callFunction(func, thisObject, concat(args, sl ice(arguments)));
131 }
132 bound.toString = function()
133 {
134 return "bound: " + toString(func);
135 };
136 return bound;
137 }
138
139 /**
140 * @param {T} obj
141 * @return {T}
142 * @template T
143 */
144 function nullifyObjectProto(obj)
145 {
146 if (obj && typeof obj === "object")
147 obj.__proto__ = null;
148 return obj;
149 }
150
151 /**
152 * @param {number|string} obj
153 * @return {boolean}
154 */
155 function isUInt32(obj)
156 {
157 if (typeof obj === "number")
158 return obj >>> 0 === obj && (obj > 0 || 1 / obj > 0);
159 return "" + (obj >>> 0) === obj;
160 }
161
162 /**
163 * FireBug's array detection.
164 * @param {*} obj
165 * @return {boolean}
166 */
167 function isArrayLike(obj)
168 {
169 if (typeof obj !== "object")
170 return false;
171 try {
172 if (typeof obj.splice === "function") {
173 if (!InjectedScriptHost.suppressWarningsAndCallFunction(Object.proto type.hasOwnProperty, obj, ["length"]))
174 return false;
175 var len = obj.length;
176 return typeof len === "number" && isUInt32(len);
177 }
178 } catch (e) {
179 }
180 return false;
181 }
182
183 /**
184 * @param {number} a
185 * @param {number} b
186 * @return {number}
187 */
188 function max(a, b)
189 {
190 return a > b ? a : b;
191 }
192
193 /**
194 * FIXME: Remove once ES6 is supported natively by JS compiler.
195 * @param {*} obj
196 * @return {boolean}
197 */
198 function isSymbol(obj)
199 {
200 var type = typeof obj;
201 return (type === "symbol");
202 }
203
204 /**
205 * @param {string} str
206 * @param {string} searchElement
207 * @param {number=} fromIndex
208 * @return {number}
209 */
210 function indexOf(str, searchElement, fromIndex)
211 {
212 var len = str.length;
213 var n = fromIndex || 0;
214 var k = max(n >= 0 ? n : len + n, 0);
215
216 while (k < len) {
217 if (str[k] === searchElement)
218 return k;
219 ++k;
220 }
221 return -1;
222 }
223
224 /**
225 * DOM Attributes which have observable side effect on getter, in the form of
226 * {interfaceName1: {attributeName1: true,
227 * attributeName2: true,
228 * ...},
229 * interfaceName2: {...},
230 * ...}
231 * @type {!Object<string, !Object<string, boolean>>}
232 * @const
233 */
234 var domAttributesWithObservableSideEffectOnGet = nullifyObjectProto({});
235 domAttributesWithObservableSideEffectOnGet["Request"] = nullifyObjectProto({});
236 domAttributesWithObservableSideEffectOnGet["Request"]["body"] = true;
237 domAttributesWithObservableSideEffectOnGet["Response"] = nullifyObjectProto({});
238 domAttributesWithObservableSideEffectOnGet["Response"]["body"] = true;
239
240 /**
241 * @param {!Object} object
242 * @param {string} attribute
243 * @return {boolean}
244 */
245 function doesAttributeHaveObservableSideEffectOnGet(object, attribute)
246 {
247 for (var interfaceName in domAttributesWithObservableSideEffectOnGet) {
248 var isInstance = InjectedScriptHost.suppressWarningsAndCallFunction(func tion(object, interfaceName) {
249 return /* suppressBlacklist */ typeof inspectedGlobalObject[interfac eName] === "function" && object instanceof inspectedGlobalObject[interfaceName];
250 }, null, [object, interfaceName]);
251 if (isInstance) {
252 return attribute in domAttributesWithObservableSideEffectOnGet[inter faceName];
253 }
254 }
255 return false;
256 }
257
258 /**
259 * @constructor
260 */
261 var InjectedScript = function()
262 {
263 }
264
265 /**
266 * @type {!Object.<string, boolean>}
267 * @const
268 */
269 InjectedScript.primitiveTypes = {
270 "undefined": true,
271 "boolean": true,
272 "number": true,
273 "string": true,
274 __proto__: null
275 }
276
277 InjectedScript.prototype = {
278 /**
279 * @param {*} object
280 * @return {boolean}
281 */
282 isPrimitiveValue: function(object)
283 {
284 // FIXME(33716): typeof document.all is always 'undefined'.
285 return InjectedScript.primitiveTypes[typeof object] && !this._isHTMLAllC ollection(object);
286 },
287
288 /**
289 * @param {*} object
290 * @param {string} groupName
291 * @param {boolean} canAccessInspectedGlobalObject
292 * @param {boolean} generatePreview
293 * @return {!RuntimeAgent.RemoteObject}
294 */
295 wrapObject: function(object, groupName, canAccessInspectedGlobalObject, gene ratePreview)
296 {
297 if (canAccessInspectedGlobalObject)
298 return this._wrapObject(object, groupName, false, generatePreview);
299 return this._fallbackWrapper(object);
300 },
301
302 /**
303 * @param {*} object
304 * @return {!RuntimeAgent.RemoteObject}
305 */
306 _fallbackWrapper: function(object)
307 {
308 var result = { __proto__: null };
309 result.type = typeof object;
310 if (this.isPrimitiveValue(object))
311 result.value = object;
312 else
313 result.description = toString(object);
314 return /** @type {!RuntimeAgent.RemoteObject} */ (result);
315 },
316
317 /**
318 * @param {boolean} canAccessInspectedGlobalObject
319 * @param {!Object} table
320 * @param {!Array.<string>|string|boolean} columns
321 * @return {!RuntimeAgent.RemoteObject}
322 */
323 wrapTable: function(canAccessInspectedGlobalObject, table, columns)
324 {
325 if (!canAccessInspectedGlobalObject)
326 return this._fallbackWrapper(table);
327 var columnNames = null;
328 if (typeof columns === "string")
329 columns = [columns];
330 if (InjectedScriptHost.subtype(columns) === "array") {
331 columnNames = [];
332 for (var i = 0; i < columns.length; ++i)
333 columnNames[i] = toString(columns[i]);
334 }
335 return this._wrapObject(table, "console", false, true, columnNames, true );
336 },
337
338 /**
339 * @param {*} object
340 * @return {*}
341 */
342 _inspect: function(object)
343 {
344 if (arguments.length === 0)
345 return;
346
347 var objectId = this._wrapObject(object, "");
348 var hints = { __proto__: null };
349
350 InjectedScriptHost.inspect(objectId, hints);
351 return object;
352 },
353
354 /**
355 * This method cannot throw.
356 * @param {*} object
357 * @param {string=} objectGroupName
358 * @param {boolean=} forceValueType
359 * @param {boolean=} generatePreview
360 * @param {?Array.<string>=} columnNames
361 * @param {boolean=} isTable
362 * @param {boolean=} doNotBind
363 * @param {*=} customObjectConfig
364 * @return {!RuntimeAgent.RemoteObject}
365 * @suppress {checkTypes}
366 */
367 _wrapObject: function(object, objectGroupName, forceValueType, generatePrevi ew, columnNames, isTable, doNotBind, customObjectConfig)
368 {
369 try {
370 return new InjectedScript.RemoteObject(object, objectGroupName, doNo tBind, forceValueType, generatePreview, columnNames, isTable, undefined, customO bjectConfig);
371 } catch (e) {
372 try {
373 var description = injectedScript._describe(e);
374 } catch (ex) {
375 var description = "<failed to convert exception to string>";
376 }
377 return new InjectedScript.RemoteObject(description);
378 }
379 },
380
381 /**
382 * @param {!Object|symbol} object
383 * @param {string=} objectGroupName
384 * @return {string}
385 */
386 _bind: function(object, objectGroupName)
387 {
388 var id = InjectedScriptHost.bind(object, objectGroupName || "");
389 return "{\"injectedScriptId\":" + injectedScriptId + ",\"id\":" + id + " }";
390 },
391
392 /**
393 * @param {string} objectId
394 * @return {!Object}
395 */
396 _parseObjectId: function(objectId)
397 {
398 return nullifyObjectProto(/** @type {!Object} */ (InjectedScriptHost.eva l("(" + objectId + ")")));
399 },
400
401 clearLastEvaluationResult: function()
402 {
403 delete this._lastResult;
404 },
405
406 /**
407 * @param {string} objectId
408 * @param {boolean} ownProperties
409 * @param {boolean} accessorPropertiesOnly
410 * @param {boolean} generatePreview
411 * @return {!Array.<!RuntimeAgent.PropertyDescriptor>|boolean}
412 */
413 getProperties: function(objectId, ownProperties, accessorPropertiesOnly, gen eratePreview)
414 {
415 var parsedObjectId = this._parseObjectId(objectId);
416 var object = this._objectForId(parsedObjectId);
417 var objectGroupName = InjectedScriptHost.idToObjectGroupName(parsedObjec tId.id);
418
419 if (!this._isDefined(object) || isSymbol(object))
420 return false;
421 object = /** @type {!Object} */ (object);
422 var descriptors = [];
423 var iter = this._propertyDescriptors(object, ownProperties, accessorProp ertiesOnly, undefined);
424 // Go over properties, wrap object values.
425 for (var descriptor of iter) {
426 if ("get" in descriptor)
427 descriptor.get = this._wrapObject(descriptor.get, objectGroupNam e);
428 if ("set" in descriptor)
429 descriptor.set = this._wrapObject(descriptor.set, objectGroupNam e);
430 if ("value" in descriptor)
431 descriptor.value = this._wrapObject(descriptor.value, objectGrou pName, false, generatePreview);
432 if (!("configurable" in descriptor))
433 descriptor.configurable = false;
434 if (!("enumerable" in descriptor))
435 descriptor.enumerable = false;
436 if ("symbol" in descriptor)
437 descriptor.symbol = this._wrapObject(descriptor.symbol, objectGr oupName);
438 push(descriptors, descriptor);
439 }
440 return descriptors;
441 },
442
443 /**
444 * @param {string} objectId
445 * @return {!Array.<!Object>|boolean}
446 */
447 getInternalProperties: function(objectId)
448 {
449 var parsedObjectId = this._parseObjectId(objectId);
450 var object = this._objectForId(parsedObjectId);
451 var objectGroupName = InjectedScriptHost.idToObjectGroupName(parsedObjec tId.id);
452 if (!this._isDefined(object) || isSymbol(object))
453 return false;
454 object = /** @type {!Object} */ (object);
455 var descriptors = [];
456 var internalProperties = InjectedScriptHost.getInternalProperties(object );
457 if (internalProperties) {
458 for (var i = 0; i < internalProperties.length; i += 2) {
459 var descriptor = {
460 name: internalProperties[i],
461 value: this._wrapObject(internalProperties[i + 1], objectGro upName),
462 __proto__: null
463 };
464 push(descriptors, descriptor);
465 }
466 }
467 return descriptors;
468 },
469
470 /**
471 * @param {string} functionId
472 * @return {!DebuggerAgent.FunctionDetails|string}
473 */
474 getFunctionDetails: function(functionId)
475 {
476 var parsedFunctionId = this._parseObjectId(functionId);
477 var func = this._objectForId(parsedFunctionId);
478 if (typeof func !== "function")
479 return "Cannot resolve function by id.";
480 var details = nullifyObjectProto(/** @type {!DebuggerAgent.FunctionDetai ls} */ (InjectedScriptHost.functionDetails(func)));
481 if ("rawScopes" in details) {
482 var objectGroupName = InjectedScriptHost.idToObjectGroupName(parsedF unctionId.id);
483 var rawScopes = details["rawScopes"];
484 delete details["rawScopes"];
485 var scopes = [];
486 for (var i = 0; i < rawScopes.length; ++i)
487 scopes[i] = InjectedScript.CallFrameProxy._createScopeJson(rawSc opes[i].type, rawScopes[i].name, rawScopes[i].object, objectGroupName);
488 details.scopeChain = scopes;
489 }
490 return details;
491 },
492
493 /**
494 * @param {string} objectId
495 * @return {!DebuggerAgent.GeneratorObjectDetails|string}
496 */
497 getGeneratorObjectDetails: function(objectId)
498 {
499 var parsedObjectId = this._parseObjectId(objectId);
500 var object = this._objectForId(parsedObjectId);
501 if (!object || typeof object !== "object")
502 return "Could not find object with given id";
503 var details = nullifyObjectProto(/** @type {?DebuggerAgent.GeneratorObje ctDetails} */ (InjectedScriptHost.generatorObjectDetails(object)));
504 if (!details)
505 return "Object is not a generator";
506 var objectGroupName = InjectedScriptHost.idToObjectGroupName(parsedObjec tId.id);
507 details["function"] = this._wrapObject(details["function"], objectGroupN ame);
508 return details;
509 },
510
511 /**
512 * @param {string} objectId
513 * @return {!Array.<!Object>|string}
514 */
515 getCollectionEntries: function(objectId)
516 {
517 var parsedObjectId = this._parseObjectId(objectId);
518 var object = this._objectForId(parsedObjectId);
519 if (!object || typeof object !== "object")
520 return "Could not find object with given id";
521 var entries = InjectedScriptHost.collectionEntries(object);
522 if (!entries)
523 return "Object with given id is not a collection";
524 var objectGroupName = InjectedScriptHost.idToObjectGroupName(parsedObjec tId.id);
525 for (var i = 0; i < entries.length; ++i) {
526 var entry = nullifyObjectProto(entries[i]);
527 if ("key" in entry)
528 entry.key = this._wrapObject(entry.key, objectGroupName);
529 entry.value = this._wrapObject(entry.value, objectGroupName);
530 entries[i] = entry;
531 }
532 return entries;
533 },
534
535 /**
536 * @param {!Object} object
537 * @param {boolean=} ownProperties
538 * @param {boolean=} accessorPropertiesOnly
539 * @param {?Array.<string>=} propertyNamesOnly
540 */
541 _propertyDescriptors: function*(object, ownProperties, accessorPropertiesOnl y, propertyNamesOnly)
542 {
543 var propertyProcessed = { __proto__: null };
544
545 /**
546 * @param {?Object} o
547 * @param {!Iterable.<string|symbol>|!Array.<string|symbol>} properties
548 */
549 function* process(o, properties)
550 {
551 for (var property of properties) {
552 if (propertyProcessed[property])
553 continue;
554
555 var name = property;
556 if (isSymbol(property))
557 name = /** @type {string} */ (injectedScript._describe(prope rty));
558
559 try {
560 propertyProcessed[property] = true;
561 var descriptor = nullifyObjectProto(InjectedScriptHost.suppr essWarningsAndCallFunction(Object.getOwnPropertyDescriptor, Object, [o, property ]));
562 if (descriptor) {
563 if (accessorPropertiesOnly && !("get" in descriptor || " set" in descriptor))
564 continue;
565 if ("get" in descriptor && "set" in descriptor && name ! = "__proto__" && InjectedScriptHost.isDOMWrapper(object) && !doesAttributeHaveOb servableSideEffectOnGet(object, name)) {
566 descriptor.value = InjectedScriptHost.suppressWarnin gsAndCallFunction(function(attribute) { return this[attribute]; }, object, [name ]);
567 descriptor.isOwn = true;
568 delete descriptor.get;
569 delete descriptor.set;
570 }
571 } else {
572 // Not all bindings provide proper descriptors. Fall bac k to the writable, configurable property.
573 if (accessorPropertiesOnly)
574 continue;
575 try {
576 descriptor = { name: name, value: o[property], writa ble: false, configurable: false, enumerable: false, __proto__: null };
577 if (o === object)
578 descriptor.isOwn = true;
579 yield descriptor;
580 } catch (e) {
581 // Silent catch.
582 }
583 continue;
584 }
585 } catch (e) {
586 if (accessorPropertiesOnly)
587 continue;
588 var descriptor = { __proto__: null };
589 descriptor.value = e;
590 descriptor.wasThrown = true;
591 }
592
593 descriptor.name = name;
594 if (o === object)
595 descriptor.isOwn = true;
596 if (isSymbol(property))
597 descriptor.symbol = property;
598 yield descriptor;
599 }
600 }
601
602 /**
603 * @param {number} length
604 */
605 function* arrayIndexNames(length)
606 {
607 for (var i = 0; i < length; ++i)
608 yield "" + i;
609 }
610
611 if (propertyNamesOnly) {
612 for (var i = 0; i < propertyNamesOnly.length; ++i) {
613 var name = propertyNamesOnly[i];
614 for (var o = object; this._isDefined(o); o = o.__proto__) {
615 if (InjectedScriptHost.suppressWarningsAndCallFunction(Objec t.prototype.hasOwnProperty, o, [name])) {
616 for (var descriptor of process(o, [name]))
617 yield descriptor;
618 break;
619 }
620 if (ownProperties)
621 break;
622 }
623 }
624 return;
625 }
626
627 var skipGetOwnPropertyNames;
628 try {
629 skipGetOwnPropertyNames = InjectedScriptHost.isTypedArray(object) && object.length > 500000;
630 } catch (e) {
631 }
632
633 for (var o = object; this._isDefined(o); o = o.__proto__) {
634 if (skipGetOwnPropertyNames && o === object) {
635 // Avoid OOM crashes from getting all own property names of a la rge TypedArray.
636 for (var descriptor of process(o, arrayIndexNames(o.length)))
637 yield descriptor;
638 } else {
639 // First call Object.keys() to enforce ordering of the property descriptors.
640 for (var descriptor of process(o, Object.keys(/** @type {!Object } */ (o))))
641 yield descriptor;
642 for (var descriptor of process(o, Object.getOwnPropertyNames(/** @type {!Object} */ (o))))
643 yield descriptor;
644 }
645 if (Object.getOwnPropertySymbols) {
646 for (var descriptor of process(o, Object.getOwnPropertySymbols(/ ** @type {!Object} */ (o))))
647 yield descriptor;
648 }
649 if (ownProperties) {
650 if (object.__proto__ && !accessorPropertiesOnly)
651 yield { name: "__proto__", value: object.__proto__, writable : true, configurable: true, enumerable: false, isOwn: true, __proto__: null };
652 break;
653 }
654 }
655 },
656
657 /**
658 * @param {string} expression
659 * @param {string} objectGroup
660 * @param {boolean} injectCommandLineAPI
661 * @param {boolean} returnByValue
662 * @param {boolean} generatePreview
663 * @return {*}
664 */
665 evaluate: function(expression, objectGroup, injectCommandLineAPI, returnByVa lue, generatePreview)
666 {
667 return this._evaluateAndWrap(null, expression, objectGroup, injectComman dLineAPI, returnByValue, generatePreview);
668 },
669
670 /**
671 * @param {string} objectId
672 * @param {string} expression
673 * @param {string} args
674 * @param {boolean} returnByValue
675 * @return {!Object|string}
676 */
677 callFunctionOn: function(objectId, expression, args, returnByValue)
678 {
679 var parsedObjectId = this._parseObjectId(objectId);
680 var object = this._objectForId(parsedObjectId);
681 if (!this._isDefined(object))
682 return "Could not find object with given id";
683
684 if (args) {
685 var resolvedArgs = [];
686 var callArgs = /** @type {!Array.<!RuntimeAgent.CallArgument>} */ (I njectedScriptHost.eval(args));
687 for (var i = 0; i < callArgs.length; ++i) {
688 try {
689 resolvedArgs[i] = this._resolveCallArgument(callArgs[i]);
690 } catch (e) {
691 return toString(e);
692 }
693 }
694 }
695
696 var objectGroup = InjectedScriptHost.idToObjectGroupName(parsedObjectId. id);
697
698 /**
699 * @suppressReceiverCheck
700 * @param {*} object
701 * @param {boolean=} forceValueType
702 * @param {boolean=} generatePreview
703 * @param {?Array.<string>=} columnNames
704 * @param {boolean=} isTable
705 * @param {*=} customObjectConfig
706 * @return {!RuntimeAgent.RemoteObject}
707 * @this {InjectedScript}
708 */
709 function wrap(object, forceValueType, generatePreview, columnNames, isTa ble, customObjectConfig)
710 {
711 return this._wrapObject(object, objectGroup, forceValueType, generat ePreview, columnNames, isTable, false, customObjectConfig);
712 }
713
714 try {
715
716 var remoteObjectAPI = { bindRemoteObject: bind(wrap, this), __proto_ _: null};
717 InjectedScriptHost.setNonEnumProperty(inspectedGlobalObject, "__remo teObjectAPI", remoteObjectAPI);
718
719 var func = InjectedScriptHost.eval("with (typeof __remoteObjectAPI ! == 'undefined' ? __remoteObjectAPI : { __proto__: null }) {(" + expression + ")} ");
720 if (typeof func !== "function")
721 return "Given expression does not evaluate to a function";
722
723 return { wasThrown: false,
724 result: this._wrapObject(InjectedScriptHost.callFunction(fu nc, object, resolvedArgs), objectGroup, returnByValue),
725 __proto__: null };
726 } catch (e) {
727 return this._createThrownValue(e, objectGroup, false);
728 } finally {
729 try {
730 delete inspectedGlobalObject["__remoteObjectAPI"];
731 } catch(e) {
732 }
733 }
734 },
735
736 /**
737 * @param {string|undefined} objectGroupName
738 * @param {*} jsonMLObject
739 * @throws {string} error message
740 */
741 _substituteObjectTagsInCustomPreview: function(objectGroupName, jsonMLObject )
742 {
743 var maxCustomPreviewRecursionDepth = 20;
744 this._customPreviewRecursionDepth = (this._customPreviewRecursionDepth | | 0) + 1
745 try {
746 if (this._customPreviewRecursionDepth >= maxCustomPreviewRecursionDe pth)
747 throw new Error("Too deep hierarchy of inlined custom previews") ;
748
749 if (!isArrayLike(jsonMLObject))
750 return;
751
752 if (jsonMLObject[0] === "object") {
753 var attributes = jsonMLObject[1];
754 var originObject = attributes["object"];
755 var config = attributes["config"];
756 if (typeof originObject === "undefined")
757 throw new Error("Illegal format: obligatory attribute \"obje ct\" isn't specified");
758
759 jsonMLObject[1] = this._wrapObject(originObject, objectGroupName , false, false, null, false, false, config);
760 return;
761 }
762
763 for (var i = 0; i < jsonMLObject.length; ++i)
764 this._substituteObjectTagsInCustomPreview(objectGroupName, jsonM LObject[i]);
765 } finally {
766 this._customPreviewRecursionDepth--;
767 }
768 },
769
770 /**
771 * Resolves a value from CallArgument description.
772 * @param {!RuntimeAgent.CallArgument} callArgumentJson
773 * @return {*} resolved value
774 * @throws {string} error message
775 */
776 _resolveCallArgument: function(callArgumentJson)
777 {
778 callArgumentJson = nullifyObjectProto(callArgumentJson);
779 var objectId = callArgumentJson.objectId;
780 if (objectId) {
781 var parsedArgId = this._parseObjectId(objectId);
782 if (!parsedArgId || parsedArgId["injectedScriptId"] !== injectedScri ptId)
783 throw "Arguments should belong to the same JavaScript world as t he target object.";
784
785 var resolvedArg = this._objectForId(parsedArgId);
786 if (!this._isDefined(resolvedArg))
787 throw "Could not find object with given id";
788
789 return resolvedArg;
790 } else if ("value" in callArgumentJson) {
791 var value = callArgumentJson.value;
792 if (callArgumentJson.type === "number" && typeof value !== "number")
793 value = Number(value);
794 return value;
795 }
796 return undefined;
797 },
798
799 /**
800 * @param {?JavaScriptCallFrame} callFrame
801 * @param {string} expression
802 * @param {string} objectGroup
803 * @param {boolean} injectCommandLineAPI
804 * @param {boolean} returnByValue
805 * @param {boolean} generatePreview
806 * @param {!Array.<!Object>=} scopeChain
807 * @return {!Object}
808 */
809 _evaluateAndWrap: function(callFrame, expression, objectGroup, injectCommand LineAPI, returnByValue, generatePreview, scopeChain)
810 {
811 var wrappedResult = this._evaluateOn(callFrame, objectGroup, expression, injectCommandLineAPI, scopeChain);
812 if (!wrappedResult.exceptionDetails) {
813 return { wasThrown: false,
814 result: this._wrapObject(wrappedResult.result, objectGroup, returnByValue, generatePreview),
815 __proto__: null };
816 }
817 return this._createThrownValue(wrappedResult.result, objectGroup, genera tePreview, wrappedResult.exceptionDetails);
818 },
819
820 /**
821 * @param {*} value
822 * @param {string|undefined} objectGroup
823 * @param {boolean} generatePreview
824 * @param {!DebuggerAgent.ExceptionDetails=} exceptionDetails
825 * @return {!Object}
826 */
827 _createThrownValue: function(value, objectGroup, generatePreview, exceptionD etails)
828 {
829 var remoteObject = this._wrapObject(value, objectGroup, false, generateP review && InjectedScriptHost.subtype(value) !== "error");
830 if (!remoteObject.description){
831 try {
832 remoteObject.description = toStringDescription(value);
833 } catch (e) {}
834 }
835 return { wasThrown: true, result: remoteObject, exceptionDetails: except ionDetails, __proto__: null };
836 },
837
838 /**
839 * @param {?JavaScriptCallFrame} callFrame
840 * @param {string} objectGroup
841 * @param {string} expression
842 * @param {boolean} injectCommandLineAPI
843 * @param {!Array.<!Object>=} scopeChain
844 * @return {*}
845 */
846 _evaluateOn: function(callFrame, objectGroup, expression, injectCommandLineA PI, scopeChain)
847 {
848 // Only install command line api object for the time of evaluation.
849 // Surround the expression in with statements to inject our command line API so that
850 // the window object properties still take more precedent than our API f unctions.
851
852 var scopeExtensionForEval = (callFrame && injectCommandLineAPI) ? new Co mmandLineAPI(this._commandLineAPIImpl, callFrame) : undefined;
853 var injectScopeChain = scopeChain && scopeChain.length && !("__scopeChai nForEval" in inspectedGlobalObject);
854
855 try {
856 var prefix = "";
857 var suffix = "";
858 if (injectScopeChain) {
859 InjectedScriptHost.setNonEnumProperty(inspectedGlobalObject, "__ scopeChainForEval", scopeChain);
860 for (var i = 0; i < scopeChain.length; ++i) {
861 prefix = "with (typeof __scopeChainForEval !== 'undefined' ? __scopeChainForEval[" + i + "] : { __proto__: null }) {" + (suffix ? " " : "") + prefix;
862 if (suffix)
863 suffix += " }";
864 else
865 suffix = "}";
866 }
867 }
868
869 if (prefix)
870 expression = prefix + "\n" + expression + "\n" + suffix;
871 var wrappedResult = callFrame ? callFrame.evaluateWithExceptionDetai ls(expression, scopeExtensionForEval) : InjectedScriptHost.evaluateWithException Details(expression, injectCommandLineAPI ? new CommandLineAPI(this._commandLineA PIImpl, callFrame) : undefined);
872 if (objectGroup === "console" && !wrappedResult.exceptionDetails)
873 this._lastResult = wrappedResult.result;
874 return wrappedResult;
875 } finally {
876 if (injectScopeChain) {
877 try {
878 delete inspectedGlobalObject["__scopeChainForEval"];
879 } catch(e) {
880 }
881 }
882 }
883 },
884
885 /**
886 * @param {?Object} callFrame
887 * @param {number} asyncOrdinal
888 * @return {!Array.<!InjectedScript.CallFrameProxy>|boolean}
889 */
890 wrapCallFrames: function(callFrame, asyncOrdinal)
891 {
892 if (!callFrame)
893 return false;
894
895 var result = [];
896 var depth = 0;
897 do {
898 result[depth] = new InjectedScript.CallFrameProxy(depth, callFrame, asyncOrdinal);
899 callFrame = callFrame.caller;
900 ++depth;
901 } while (callFrame);
902 return result;
903 },
904
905 /**
906 * @param {!JavaScriptCallFrame} topCallFrame
907 * @param {boolean} isAsyncStack
908 * @param {string} callFrameId
909 * @param {string} expression
910 * @param {string} objectGroup
911 * @param {boolean} injectCommandLineAPI
912 * @param {boolean} returnByValue
913 * @param {boolean} generatePreview
914 * @return {*}
915 */
916 evaluateOnCallFrame: function(topCallFrame, isAsyncStack, callFrameId, expre ssion, objectGroup, injectCommandLineAPI, returnByValue, generatePreview)
917 {
918 var callFrame = this._callFrameForId(topCallFrame, callFrameId);
919 if (!callFrame)
920 return "Could not find call frame with given id";
921 if (isAsyncStack)
922 return this._evaluateAndWrap(null, expression, objectGroup, injectCo mmandLineAPI, returnByValue, generatePreview, callFrame.scopeChain);
923 return this._evaluateAndWrap(callFrame, expression, objectGroup, injectC ommandLineAPI, returnByValue, generatePreview);
924 },
925
926 /**
927 * @param {!JavaScriptCallFrame} topCallFrame
928 * @param {string} callFrameId
929 * @return {*}
930 */
931 restartFrame: function(topCallFrame, callFrameId)
932 {
933 var callFrame = this._callFrameForId(topCallFrame, callFrameId);
934 if (!callFrame)
935 return "Could not find call frame with given id";
936 return callFrame.restart();
937 },
938
939 /**
940 * @param {!JavaScriptCallFrame} topCallFrame
941 * @param {string} callFrameId
942 * @return {*} a stepIn position array ready for protocol JSON or a string e rror
943 */
944 getStepInPositions: function(topCallFrame, callFrameId)
945 {
946 var callFrame = this._callFrameForId(topCallFrame, callFrameId);
947 if (!callFrame)
948 return "Could not find call frame with given id";
949 var stepInPositionsUnpacked = JSON.parse(callFrame.stepInPositions);
950 if (typeof stepInPositionsUnpacked !== "object")
951 return "Step in positions not available";
952 return stepInPositionsUnpacked;
953 },
954
955 /**
956 * Either callFrameId or functionObjectId must be specified.
957 * @param {!JavaScriptCallFrame} topCallFrame
958 * @param {string|boolean} callFrameId or false
959 * @param {string|boolean} functionObjectId or false
960 * @param {number} scopeNumber
961 * @param {string} variableName
962 * @param {string} newValueJsonString RuntimeAgent.CallArgument structure se rialized as string
963 * @return {string|undefined} undefined if success or an error message
964 */
965 setVariableValue: function(topCallFrame, callFrameId, functionObjectId, scop eNumber, variableName, newValueJsonString)
966 {
967 try {
968 var newValueJson = /** @type {!RuntimeAgent.CallArgument} */ (Inject edScriptHost.eval("(" + newValueJsonString + ")"));
969 var resolvedValue = this._resolveCallArgument(newValueJson);
970 if (typeof callFrameId === "string") {
971 var callFrame = this._callFrameForId(topCallFrame, callFrameId);
972 if (!callFrame)
973 return "Could not find call frame with given id";
974 callFrame.setVariableValue(scopeNumber, variableName, resolvedVa lue)
975 } else {
976 var parsedFunctionId = this._parseObjectId(/** @type {string} */ (functionObjectId));
977 var func = this._objectForId(parsedFunctionId);
978 if (typeof func !== "function")
979 return "Could not resolve function by id";
980 InjectedScriptHost.setFunctionVariableValue(func, scopeNumber, v ariableName, resolvedValue);
981 }
982 } catch (e) {
983 return toString(e);
984 }
985 return undefined;
986 },
987
988 /**
989 * @param {!JavaScriptCallFrame} topCallFrame
990 * @param {string} callFrameId
991 * @return {?JavaScriptCallFrame}
992 */
993 _callFrameForId: function(topCallFrame, callFrameId)
994 {
995 var parsedCallFrameId = nullifyObjectProto(/** @type {!Object} */ (Injec tedScriptHost.eval("(" + callFrameId + ")")));
996 var ordinal = parsedCallFrameId["ordinal"];
997 var callFrame = topCallFrame;
998 while (--ordinal >= 0 && callFrame)
999 callFrame = callFrame.caller;
1000 return callFrame;
1001 },
1002
1003 /**
1004 * @param {!Object} objectId
1005 * @return {!Object|symbol|undefined}
1006 */
1007 _objectForId: function(objectId)
1008 {
1009 return objectId.injectedScriptId === injectedScriptId ? /** @type{!Objec t|symbol|undefined} */ (InjectedScriptHost.objectForId(objectId.id)) : void 0;
1010 },
1011
1012 /**
1013 * @param {*} object
1014 * @return {boolean}
1015 */
1016 _isDefined: function(object)
1017 {
1018 return !!object || this._isHTMLAllCollection(object);
1019 },
1020
1021 /**
1022 * @param {*} object
1023 * @return {boolean}
1024 */
1025 _isHTMLAllCollection: function(object)
1026 {
1027 // document.all is reported as undefined, but we still want to process i t.
1028 return (typeof object === "undefined") && InjectedScriptHost.isHTMLAllCo llection(object);
1029 },
1030
1031 /**
1032 * @param {*} obj
1033 * @return {?string}
1034 */
1035 _subtype: function(obj)
1036 {
1037 if (obj === null)
1038 return "null";
1039
1040 if (this.isPrimitiveValue(obj))
1041 return null;
1042
1043 var subtype = InjectedScriptHost.subtype(obj);
1044 if (subtype)
1045 return subtype;
1046
1047 if (isArrayLike(obj))
1048 return "array";
1049
1050 // If owning frame has navigated to somewhere else window properties wil l be undefined.
1051 return null;
1052 },
1053
1054 /**
1055 * @param {*} obj
1056 * @return {?string}
1057 */
1058 _describe: function(obj)
1059 {
1060 if (this.isPrimitiveValue(obj))
1061 return null;
1062
1063 var subtype = this._subtype(obj);
1064
1065 if (subtype === "regexp")
1066 return toString(obj);
1067
1068 if (subtype === "date")
1069 return toString(obj);
1070
1071 if (subtype === "node") {
1072 var description = obj.nodeName.toLowerCase();
1073 switch (obj.nodeType) {
1074 case 1 /* Node.ELEMENT_NODE */:
1075 description += obj.id ? "#" + obj.id : "";
1076 var className = obj.className;
1077 description += (className && typeof className === "string") ? ". " + className.trim().replace(/\s+/g, ".") : "";
1078 break;
1079 case 10 /*Node.DOCUMENT_TYPE_NODE */:
1080 description = "<!DOCTYPE " + description + ">";
1081 break;
1082 }
1083 return description;
1084 }
1085
1086 var className = InjectedScriptHost.internalConstructorName(obj);
1087 if (subtype === "array") {
1088 if (typeof obj.length === "number")
1089 className += "[" + obj.length + "]";
1090 return className;
1091 }
1092
1093 // NodeList in JSC is a function, check for array prior to this.
1094 if (typeof obj === "function")
1095 return toString(obj);
1096
1097 if (isSymbol(obj)) {
1098 try {
1099 return /** @type {string} */ (InjectedScriptHost.callFunction(Sy mbol.prototype.toString, obj)) || "Symbol";
1100 } catch (e) {
1101 return "Symbol";
1102 }
1103 }
1104
1105 if (InjectedScriptHost.subtype(obj) === "error") {
1106 try {
1107 var stack = obj.stack;
1108 var message = obj.message && obj.message.length ? ": " + obj.mes sage : "";
1109 var firstCallFrame = /^\s+at\s/m.exec(stack);
1110 var stackMessageEnd = firstCallFrame ? firstCallFrame.index : -1 ;
1111 if (stackMessageEnd !== -1) {
1112 var stackTrace = stack.substr(stackMessageEnd);
1113 return className + message + "\n" + stackTrace;
1114 }
1115 return className + message;
1116 } catch(e) {
1117 }
1118 }
1119
1120 return className;
1121 },
1122
1123 /**
1124 * @param {boolean} enabled
1125 */
1126 setCustomObjectFormatterEnabled: function(enabled)
1127 {
1128 this._customObjectFormatterEnabled = enabled;
1129 }
1130 }
1131
1132 /**
1133 * @type {!InjectedScript}
1134 * @const
1135 */
1136 var injectedScript = new InjectedScript();
1137
1138 /**
1139 * @constructor
1140 * @param {*} object
1141 * @param {string=} objectGroupName
1142 * @param {boolean=} doNotBind
1143 * @param {boolean=} forceValueType
1144 * @param {boolean=} generatePreview
1145 * @param {?Array.<string>=} columnNames
1146 * @param {boolean=} isTable
1147 * @param {boolean=} skipEntriesPreview
1148 * @param {*=} customObjectConfig
1149 */
1150 InjectedScript.RemoteObject = function(object, objectGroupName, doNotBind, force ValueType, generatePreview, columnNames, isTable, skipEntriesPreview, customObje ctConfig)
1151 {
1152 this.type = typeof object;
1153 if (this.type === "undefined" && injectedScript._isHTMLAllCollection(object) )
1154 this.type = "object";
1155
1156 if (injectedScript.isPrimitiveValue(object) || object === null || forceValue Type) {
1157 // We don't send undefined values over JSON.
1158 if (this.type !== "undefined")
1159 this.value = object;
1160
1161 // Null object is object with 'null' subtype.
1162 if (object === null)
1163 this.subtype = "null";
1164
1165 // Provide user-friendly number values.
1166 if (this.type === "number") {
1167 this.description = toStringDescription(object);
1168 // Override "value" property for values that can not be JSON-stringi fied.
1169 switch (this.description) {
1170 case "NaN":
1171 case "Infinity":
1172 case "-Infinity":
1173 case "-0":
1174 this.value = this.description;
1175 break;
1176 }
1177 }
1178
1179 return;
1180 }
1181
1182 object = /** @type {!Object} */ (object);
1183
1184 if (!doNotBind)
1185 this.objectId = injectedScript._bind(object, objectGroupName);
1186 var subtype = injectedScript._subtype(object);
1187 if (subtype)
1188 this.subtype = subtype;
1189 var className = InjectedScriptHost.internalConstructorName(object);
1190 if (className)
1191 this.className = className;
1192 this.description = injectedScript._describe(object);
1193
1194 if (generatePreview && this.type === "object" && this.subtype !== "node")
1195 this.preview = this._generatePreview(object, undefined, columnNames, isT able, skipEntriesPreview);
1196
1197 if (injectedScript._customObjectFormatterEnabled) {
1198 var customPreview = this._customPreview(object, objectGroupName, customO bjectConfig);
1199 if (customPreview)
1200 this.customPreview = customPreview;
1201 }
1202 }
1203
1204 InjectedScript.RemoteObject.prototype = {
1205
1206 /**
1207 * @param {*} object
1208 * @param {string=} objectGroupName
1209 * @param {*=} customObjectConfig
1210 * @return {?RuntimeAgent.CustomPreview}
1211 */
1212 _customPreview: function(object, objectGroupName, customObjectConfig)
1213 {
1214 /**
1215 * @param {!Error} error
1216 */
1217 function logError(error)
1218 {
1219 Promise.resolve().then(inspectedGlobalObject.console.error.bind(insp ectedGlobalObject.console, "Custom Formatter Failed: " + error.message));
1220 }
1221
1222 try {
1223 var formatters = inspectedGlobalObject["devtoolsFormatters"];
1224 if (!formatters || !isArrayLike(formatters))
1225 return null;
1226
1227 for (var i = 0; i < formatters.length; ++i) {
1228 try {
1229 var formatted = formatters[i].header(object, customObjectCon fig);
1230 if (!formatted)
1231 continue;
1232
1233 var hasBody = formatters[i].hasBody(object, customObjectConf ig);
1234 injectedScript._substituteObjectTagsInCustomPreview(objectGr oupName, formatted);
1235 var formatterObjectId = injectedScript._bind(formatters[i], objectGroupName);
1236 var result = {header: JSON.stringify(formatted), hasBody: !! hasBody, formatterObjectId: formatterObjectId};
1237 if (customObjectConfig)
1238 result["configObjectId"] = injectedScript._bind(customOb jectConfig, objectGroupName);
1239 return result;
1240 } catch (e) {
1241 logError(e);
1242 }
1243 }
1244 } catch (e) {
1245 logError(e);
1246 }
1247 return null;
1248 },
1249
1250 /**
1251 * @return {!RuntimeAgent.ObjectPreview} preview
1252 */
1253 _createEmptyPreview: function()
1254 {
1255 var preview = {
1256 type: /** @type {!RuntimeAgent.ObjectPreviewType.<string>} */ (this. type),
1257 description: this.description || toStringDescription(this.value),
1258 lossless: true,
1259 overflow: false,
1260 properties: [],
1261 __proto__: null
1262 };
1263 if (this.subtype)
1264 preview.subtype = /** @type {!RuntimeAgent.ObjectPreviewSubtype.<str ing>} */ (this.subtype);
1265 return preview;
1266 },
1267
1268 /**
1269 * @param {!Object} object
1270 * @param {?Array.<string>=} firstLevelKeys
1271 * @param {?Array.<string>=} secondLevelKeys
1272 * @param {boolean=} isTable
1273 * @param {boolean=} skipEntriesPreview
1274 * @return {!RuntimeAgent.ObjectPreview} preview
1275 */
1276 _generatePreview: function(object, firstLevelKeys, secondLevelKeys, isTable, skipEntriesPreview)
1277 {
1278 var preview = this._createEmptyPreview();
1279 var firstLevelKeysCount = firstLevelKeys ? firstLevelKeys.length : 0;
1280
1281 var propertiesThreshold = {
1282 properties: isTable ? 1000 : max(5, firstLevelKeysCount),
1283 indexes: isTable ? 1000 : max(100, firstLevelKeysCount),
1284 __proto__: null
1285 };
1286
1287 try {
1288 var descriptors = injectedScript._propertyDescriptors(object, undefi ned, undefined, firstLevelKeys);
1289
1290 this._appendPropertyDescriptors(preview, descriptors, propertiesThre shold, secondLevelKeys, isTable);
1291 if (propertiesThreshold.indexes < 0 || propertiesThreshold.propertie s < 0)
1292 return preview;
1293
1294 // Add internal properties to preview.
1295 var rawInternalProperties = InjectedScriptHost.getInternalProperties (object) || [];
1296 var internalProperties = [];
1297 for (var i = 0; i < rawInternalProperties.length; i += 2) {
1298 push(internalProperties, {
1299 name: rawInternalProperties[i],
1300 value: rawInternalProperties[i + 1],
1301 isOwn: true,
1302 enumerable: true,
1303 __proto__: null
1304 });
1305 }
1306 this._appendPropertyDescriptors(preview, internalProperties, propert iesThreshold, secondLevelKeys, isTable);
1307
1308 if (this.subtype === "map" || this.subtype === "set" || this.subtype === "iterator")
1309 this._appendEntriesPreview(object, preview, skipEntriesPreview);
1310
1311 } catch (e) {
1312 preview.lossless = false;
1313 }
1314
1315 return preview;
1316 },
1317
1318 /**
1319 * @param {!RuntimeAgent.ObjectPreview} preview
1320 * @param {!Array.<*>|!Iterable.<*>} descriptors
1321 * @param {!Object} propertiesThreshold
1322 * @param {?Array.<string>=} secondLevelKeys
1323 * @param {boolean=} isTable
1324 */
1325 _appendPropertyDescriptors: function(preview, descriptors, propertiesThresho ld, secondLevelKeys, isTable)
1326 {
1327 for (var descriptor of descriptors) {
1328 if (propertiesThreshold.indexes < 0 || propertiesThreshold.propertie s < 0)
1329 break;
1330 if (!descriptor)
1331 continue;
1332 if (descriptor.wasThrown) {
1333 preview.lossless = false;
1334 continue;
1335 }
1336
1337 var name = descriptor.name;
1338
1339 // Ignore __proto__ property, stay lossless.
1340 if (name === "__proto__")
1341 continue;
1342
1343 // Ignore non-enumerable members on prototype, stay lossless.
1344 if (!descriptor.isOwn && !descriptor.enumerable)
1345 continue;
1346
1347 // Ignore length property of array, stay lossless.
1348 if (this.subtype === "array" && name === "length")
1349 continue;
1350
1351 // Ignore size property of map, set, stay lossless.
1352 if ((this.subtype === "map" || this.subtype === "set") && name === " size")
1353 continue;
1354
1355 // Never preview prototype properties, turn lossy.
1356 if (!descriptor.isOwn) {
1357 preview.lossless = false;
1358 continue;
1359 }
1360
1361 // Ignore computed properties, turn lossy.
1362 if (!("value" in descriptor)) {
1363 preview.lossless = false;
1364 continue;
1365 }
1366
1367 var value = descriptor.value;
1368 var type = typeof value;
1369
1370 // Never render functions in object preview, turn lossy
1371 if (type === "function" && (this.subtype !== "array" || !isUInt32(na me))) {
1372 preview.lossless = false;
1373 continue;
1374 }
1375
1376 // Special-case HTMLAll.
1377 if (type === "undefined" && injectedScript._isHTMLAllCollection(valu e))
1378 type = "object";
1379
1380 // Render own properties.
1381 if (value === null) {
1382 this._appendPropertyPreview(preview, { name: name, type: "object ", subtype: "null", value: "null", __proto__: null }, propertiesThreshold);
1383 continue;
1384 }
1385
1386 var maxLength = 100;
1387 if (InjectedScript.primitiveTypes[type]) {
1388 if (type === "string" && value.length > maxLength) {
1389 value = this._abbreviateString(value, maxLength, true);
1390 preview.lossless = false;
1391 }
1392 this._appendPropertyPreview(preview, { name: name, type: type, v alue: toStringDescription(value), __proto__: null }, propertiesThreshold);
1393 continue;
1394 }
1395
1396 var property = { name: name, type: type, __proto__: null };
1397 var subtype = injectedScript._subtype(value);
1398 if (subtype)
1399 property.subtype = subtype;
1400
1401 if (secondLevelKeys === null || secondLevelKeys) {
1402 var subPreview = this._generatePreview(value, secondLevelKeys || undefined, undefined, isTable);
1403 property.valuePreview = subPreview;
1404 if (!subPreview.lossless)
1405 preview.lossless = false;
1406 if (subPreview.overflow)
1407 preview.overflow = true;
1408 } else {
1409 var description = "";
1410 if (type !== "function")
1411 description = this._abbreviateString(/** @type {string} */ ( injectedScript._describe(value)), maxLength, subtype === "regexp");
1412 property.value = description;
1413 preview.lossless = false;
1414 }
1415 this._appendPropertyPreview(preview, property, propertiesThreshold);
1416 }
1417 },
1418
1419 /**
1420 * @param {!RuntimeAgent.ObjectPreview} preview
1421 * @param {!Object} property
1422 * @param {!Object} propertiesThreshold
1423 */
1424 _appendPropertyPreview: function(preview, property, propertiesThreshold)
1425 {
1426 if (toString(property.name >>> 0) === property.name)
1427 propertiesThreshold.indexes--;
1428 else
1429 propertiesThreshold.properties--;
1430 if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0) {
1431 preview.overflow = true;
1432 preview.lossless = false;
1433 } else {
1434 push(preview.properties, property);
1435 }
1436 },
1437
1438 /**
1439 * @param {!Object} object
1440 * @param {!RuntimeAgent.ObjectPreview} preview
1441 * @param {boolean=} skipEntriesPreview
1442 */
1443 _appendEntriesPreview: function(object, preview, skipEntriesPreview)
1444 {
1445 var entries = InjectedScriptHost.collectionEntries(object);
1446 if (!entries)
1447 return;
1448 if (skipEntriesPreview) {
1449 if (entries.length) {
1450 preview.overflow = true;
1451 preview.lossless = false;
1452 }
1453 return;
1454 }
1455 preview.entries = [];
1456 var entriesThreshold = 5;
1457 for (var i = 0; i < entries.length; ++i) {
1458 if (preview.entries.length >= entriesThreshold) {
1459 preview.overflow = true;
1460 preview.lossless = false;
1461 break;
1462 }
1463 var entry = nullifyObjectProto(entries[i]);
1464 var previewEntry = {
1465 value: generateValuePreview(entry.value),
1466 __proto__: null
1467 };
1468 if ("key" in entry)
1469 previewEntry.key = generateValuePreview(entry.key);
1470 push(preview.entries, previewEntry);
1471 }
1472
1473 /**
1474 * @param {*} value
1475 * @return {!RuntimeAgent.ObjectPreview}
1476 */
1477 function generateValuePreview(value)
1478 {
1479 var remoteObject = new InjectedScript.RemoteObject(value, undefined, true, undefined, true, undefined, undefined, true);
1480 var valuePreview = remoteObject.preview || remoteObject._createEmpty Preview();
1481 if (!valuePreview.lossless)
1482 preview.lossless = false;
1483 return valuePreview;
1484 }
1485 },
1486
1487 /**
1488 * @param {string} string
1489 * @param {number} maxLength
1490 * @param {boolean=} middle
1491 * @return {string}
1492 */
1493 _abbreviateString: function(string, maxLength, middle)
1494 {
1495 if (string.length <= maxLength)
1496 return string;
1497 if (middle) {
1498 var leftHalf = maxLength >> 1;
1499 var rightHalf = maxLength - leftHalf - 1;
1500 return string.substr(0, leftHalf) + "\u2026" + string.substr(string. length - rightHalf, rightHalf);
1501 }
1502 return string.substr(0, maxLength) + "\u2026";
1503 },
1504
1505 __proto__: null
1506 }
1507
1508 /**
1509 * @constructor
1510 * @param {number} ordinal
1511 * @param {!JavaScriptCallFrame} callFrame
1512 * @param {number} asyncOrdinal
1513 */
1514 InjectedScript.CallFrameProxy = function(ordinal, callFrame, asyncOrdinal)
1515 {
1516 this.callFrameId = "{\"ordinal\":" + ordinal + ",\"injectedScriptId\":" + in jectedScriptId + (asyncOrdinal ? ",\"asyncOrdinal\":" + asyncOrdinal : "") + "}" ;
1517 this.functionName = callFrame.functionName;
1518 this.functionLocation = { scriptId: toString(callFrame.sourceID), lineNumber : callFrame.functionLine, columnNumber: callFrame.functionColumn, __proto__: nul l };
1519 this.location = { scriptId: toString(callFrame.sourceID), lineNumber: callFr ame.line, columnNumber: callFrame.column, __proto__: null };
1520 this.scopeChain = this._wrapScopeChain(callFrame);
1521 this.this = injectedScript._wrapObject(callFrame.thisObject, "backtrace");
1522 if (callFrame.isAtReturn)
1523 this.returnValue = injectedScript._wrapObject(callFrame.returnValue, "ba cktrace");
1524 }
1525
1526 InjectedScript.CallFrameProxy.prototype = {
1527 /**
1528 * @param {!JavaScriptCallFrame} callFrame
1529 * @return {!Array.<!DebuggerAgent.Scope>}
1530 */
1531 _wrapScopeChain: function(callFrame)
1532 {
1533 var scopeChain = callFrame.scopeChain;
1534 var scopeChainProxy = [];
1535 for (var i = 0; i < scopeChain.length; ++i)
1536 scopeChainProxy[i] = InjectedScript.CallFrameProxy._createScopeJson( callFrame.scopeType(i), callFrame.scopeName(i), scopeChain[i], "backtrace");
1537 return scopeChainProxy;
1538 },
1539
1540 __proto__: null
1541 }
1542
1543 /**
1544 * @const
1545 * @type {!Object.<number, !DebuggerAgent.ScopeType>}
1546 */
1547 InjectedScript.CallFrameProxy._scopeTypeNames = {
1548 0: "global",
1549 1: "local",
1550 2: "with",
1551 3: "closure",
1552 4: "catch",
1553 5: "block",
1554 6: "script",
1555 __proto__: null
1556 };
1557
1558 /**
1559 * @param {number} scopeTypeCode
1560 * @param {string} scopeName
1561 * @param {*} scopeObject
1562 * @param {string} groupId
1563 * @return {!DebuggerAgent.Scope}
1564 */
1565 InjectedScript.CallFrameProxy._createScopeJson = function(scopeTypeCode, scopeNa me, scopeObject, groupId)
1566 {
1567 var scope = {
1568 object: injectedScript._wrapObject(scopeObject, groupId),
1569 type: InjectedScript.CallFrameProxy._scopeTypeNames[scopeTypeCode],
1570 __proto__: null
1571 };
1572 if (scopeName)
1573 scope.name = scopeName;
1574 return scope;
1575 }
1576
1577 /**
1578 * @constructor
1579 * @param {!CommandLineAPIImpl} commandLineAPIImpl
1580 * @param {?JavaScriptCallFrame} callFrame
1581 */
1582 function CommandLineAPI(commandLineAPIImpl, callFrame)
1583 {
1584 /**
1585 * @param {string} member
1586 * @return {boolean}
1587 */
1588 function inScopeVariables(member)
1589 {
1590 if (!callFrame)
1591 return (member in inspectedGlobalObject);
1592
1593 var scopeChain = callFrame.scopeChain;
1594 for (var i = 0; i < scopeChain.length; ++i) {
1595 if (member in scopeChain[i])
1596 return true;
1597 }
1598 return false;
1599 }
1600
1601 /**
1602 * @param {string} name The name of the method for which a toString method s hould be generated.
1603 * @return {function():string}
1604 */
1605 function customToStringMethod(name)
1606 {
1607 return function()
1608 {
1609 var funcArgsSyntax = "";
1610 try {
1611 var funcSyntax = "" + commandLineAPIImpl[name];
1612 funcSyntax = funcSyntax.replace(/\n/g, " ");
1613 funcSyntax = funcSyntax.replace(/^function[^\(]*\(([^\)]*)\).*$/ , "$1");
1614 funcSyntax = funcSyntax.replace(/\s*,\s*/g, ", ");
1615 funcSyntax = funcSyntax.replace(/\bopt_(\w+)\b/g, "[$1]");
1616 funcArgsSyntax = funcSyntax.trim();
1617 } catch (e) {
1618 }
1619 return "function " + name + "(" + funcArgsSyntax + ") { [Command Lin e API] }";
1620 };
1621 }
1622
1623 for (var i = 0; i < CommandLineAPI.members_.length; ++i) {
1624 var member = CommandLineAPI.members_[i];
1625 if (inScopeVariables(member))
1626 continue;
1627
1628 this[member] = bind(commandLineAPIImpl[member], commandLineAPIImpl);
1629 this[member].toString = customToStringMethod(member);
1630 }
1631
1632 for (var i = 0; i < 5; ++i) {
1633 var member = "$" + i;
1634 if (inScopeVariables(member))
1635 continue;
1636
1637 this.__defineGetter__("$" + i, bind(commandLineAPIImpl._inspectedObject, commandLineAPIImpl, i));
1638 }
1639
1640 this.$_ = injectedScript._lastResult;
1641
1642 this.__proto__ = null;
1643 }
1644
1645 // NOTE: Please keep the list of API methods below synchronized to that in WebIn spector.RuntimeModel
1646 // and V8InjectedScriptHost!
1647 // NOTE: Argument names of these methods will be printed in the console, so use pretty names!
1648 /**
1649 * @type {!Array.<string>}
1650 * @const
1651 */
1652 CommandLineAPI.members_ = [
1653 "$", "$$", "$x", "dir", "dirxml", "keys", "values", "profile", "profileEnd",
1654 "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear", "getEventLis teners",
1655 "debug", "undebug", "monitor", "unmonitor", "table"
1656 ];
1657
1658 /**
1659 * @constructor
1660 */
1661 function CommandLineAPIImpl()
1662 {
1663 }
1664
1665 CommandLineAPIImpl.prototype = {
1666 /**
1667 * @param {string} selector
1668 * @param {!Node=} opt_startNode
1669 * @return {*}
1670 */
1671 $: function (selector, opt_startNode)
1672 {
1673 if (this._canQuerySelectorOnNode(opt_startNode))
1674 return opt_startNode.querySelector(selector);
1675
1676 return inspectedGlobalObject.document.querySelector(selector);
1677 },
1678
1679 /**
1680 * @param {string} selector
1681 * @param {!Node=} opt_startNode
1682 * @return {*}
1683 */
1684 $$: function (selector, opt_startNode)
1685 {
1686 if (this._canQuerySelectorOnNode(opt_startNode))
1687 return slice(opt_startNode.querySelectorAll(selector));
1688 return slice(inspectedGlobalObject.document.querySelectorAll(selector));
1689 },
1690
1691 /**
1692 * @param {!Node=} node
1693 * @return {boolean}
1694 */
1695 _canQuerySelectorOnNode: function(node)
1696 {
1697 return !!node && InjectedScriptHost.subtype(node) === "node" && (node.no deType === Node.ELEMENT_NODE || node.nodeType === Node.DOCUMENT_NODE || node.nod eType === Node.DOCUMENT_FRAGMENT_NODE);
1698 },
1699
1700 /**
1701 * @param {string} xpath
1702 * @param {!Node=} opt_startNode
1703 * @return {*}
1704 */
1705 $x: function(xpath, opt_startNode)
1706 {
1707 var doc = (opt_startNode && opt_startNode.ownerDocument) || inspectedGlo balObject.document;
1708 var result = doc.evaluate(xpath, opt_startNode || doc, null, XPathResult .ANY_TYPE, null);
1709 switch (result.resultType) {
1710 case XPathResult.NUMBER_TYPE:
1711 return result.numberValue;
1712 case XPathResult.STRING_TYPE:
1713 return result.stringValue;
1714 case XPathResult.BOOLEAN_TYPE:
1715 return result.booleanValue;
1716 default:
1717 var nodes = [];
1718 var node;
1719 while (node = result.iterateNext())
1720 push(nodes, node);
1721 return nodes;
1722 }
1723 },
1724
1725 /**
1726 * @return {*}
1727 */
1728 dir: function(var_args)
1729 {
1730 return InjectedScriptHost.callFunction(inspectedGlobalObject.console.dir , inspectedGlobalObject.console, slice(arguments));
1731 },
1732
1733 /**
1734 * @return {*}
1735 */
1736 dirxml: function(var_args)
1737 {
1738 return InjectedScriptHost.callFunction(inspectedGlobalObject.console.dir xml, inspectedGlobalObject.console, slice(arguments));
1739 },
1740
1741 /**
1742 * @return {!Array.<string>}
1743 */
1744 keys: function(object)
1745 {
1746 return Object.keys(object);
1747 },
1748
1749 /**
1750 * @return {!Array.<*>}
1751 */
1752 values: function(object)
1753 {
1754 var result = [];
1755 for (var key in object)
1756 push(result, object[key]);
1757 return result;
1758 },
1759
1760 /**
1761 * @return {*}
1762 */
1763 profile: function(opt_title)
1764 {
1765 return InjectedScriptHost.callFunction(inspectedGlobalObject.console.pro file, inspectedGlobalObject.console, slice(arguments));
1766 },
1767
1768 /**
1769 * @return {*}
1770 */
1771 profileEnd: function(opt_title)
1772 {
1773 return InjectedScriptHost.callFunction(inspectedGlobalObject.console.pro fileEnd, inspectedGlobalObject.console, slice(arguments));
1774 },
1775
1776 /**
1777 * @param {!Object} object
1778 * @param {!Array.<string>|string=} opt_types
1779 */
1780 monitorEvents: function(object, opt_types)
1781 {
1782 if (!object || !object.addEventListener || !object.removeEventListener)
1783 return;
1784 var types = this._normalizeEventTypes(opt_types);
1785 for (var i = 0; i < types.length; ++i) {
1786 object.removeEventListener(types[i], this._logEvent, false);
1787 object.addEventListener(types[i], this._logEvent, false);
1788 }
1789 },
1790
1791 /**
1792 * @param {!Object} object
1793 * @param {!Array.<string>|string=} opt_types
1794 */
1795 unmonitorEvents: function(object, opt_types)
1796 {
1797 if (!object || !object.addEventListener || !object.removeEventListener)
1798 return;
1799 var types = this._normalizeEventTypes(opt_types);
1800 for (var i = 0; i < types.length; ++i)
1801 object.removeEventListener(types[i], this._logEvent, false);
1802 },
1803
1804 /**
1805 * @param {*} object
1806 * @return {*}
1807 */
1808 inspect: function(object)
1809 {
1810 return injectedScript._inspect(object);
1811 },
1812
1813 copy: function(object)
1814 {
1815 var string;
1816 if (injectedScript._subtype(object) === "node") {
1817 string = object.outerHTML;
1818 } else if (injectedScript.isPrimitiveValue(object)) {
1819 string = toString(object);
1820 } else {
1821 try {
1822 string = JSON.stringify(object, null, " ");
1823 } catch (e) {
1824 string = toString(object);
1825 }
1826 }
1827
1828 var hints = { copyToClipboard: true, __proto__: null };
1829 var remoteObject = injectedScript._wrapObject(string, "")
1830 InjectedScriptHost.inspect(remoteObject, hints);
1831 },
1832
1833 clear: function()
1834 {
1835 InjectedScriptHost.clearConsoleMessages();
1836 },
1837
1838 /**
1839 * @param {!Node} node
1840 * @return {!Array.<!{type: string, listener: function(), useCapture: boolea n, remove: function()}>|undefined}
1841 */
1842 getEventListeners: function(node)
1843 {
1844 var result = nullifyObjectProto(InjectedScriptHost.getEventListeners(nod e));
1845 if (!result)
1846 return result;
1847 /** @this {{type: string, listener: function(), useCapture: boolean}} */
1848 var removeFunc = function()
1849 {
1850 node.removeEventListener(this.type, this.listener, this.useCapture);
1851 }
1852 for (var type in result) {
1853 var listeners = result[type];
1854 for (var i = 0, listener; listener = listeners[i]; ++i) {
1855 listener["type"] = type;
1856 listener["remove"] = removeFunc;
1857 }
1858 }
1859 return result;
1860 },
1861
1862 debug: function(fn)
1863 {
1864 InjectedScriptHost.debugFunction(fn);
1865 },
1866
1867 undebug: function(fn)
1868 {
1869 InjectedScriptHost.undebugFunction(fn);
1870 },
1871
1872 monitor: function(fn)
1873 {
1874 InjectedScriptHost.monitorFunction(fn);
1875 },
1876
1877 unmonitor: function(fn)
1878 {
1879 InjectedScriptHost.unmonitorFunction(fn);
1880 },
1881
1882 table: function(data, opt_columns)
1883 {
1884 InjectedScriptHost.callFunction(inspectedGlobalObject.console.table, ins pectedGlobalObject.console, slice(arguments));
1885 },
1886
1887 /**
1888 * @param {number} num
1889 */
1890 _inspectedObject: function(num)
1891 {
1892 return InjectedScriptHost.inspectedObject(num);
1893 },
1894
1895 /**
1896 * @param {!Array.<string>|string=} types
1897 * @return {!Array.<string>}
1898 */
1899 _normalizeEventTypes: function(types)
1900 {
1901 if (typeof types === "undefined")
1902 types = ["mouse", "key", "touch", "pointer", "control", "load", "unl oad", "abort", "error", "select", "input", "change", "submit", "reset", "focus", "blur", "resize", "scroll", "search", "devicemotion", "deviceorientation"];
1903 else if (typeof types === "string")
1904 types = [types];
1905
1906 var result = [];
1907 for (var i = 0; i < types.length; ++i) {
1908 if (types[i] === "mouse")
1909 push(result, "click", "dblclick", "mousedown", "mouseeenter", "m ouseleave", "mousemove", "mouseout", "mouseover", "mouseup", "mouseleave", "mous ewheel");
1910 else if (types[i] === "key")
1911 push(result, "keydown", "keyup", "keypress", "textInput");
1912 else if (types[i] === "touch")
1913 push(result, "touchstart", "touchmove", "touchend", "touchcancel ");
1914 else if (types[i] === "pointer")
1915 push(result, "pointerover", "pointerout", "pointerenter", "point erleave", "pointerdown", "pointerup", "pointermove", "pointercancel", "gotpointe rcapture", "lostpointercapture");
1916 else if (types[i] === "control")
1917 push(result, "resize", "scroll", "zoom", "focus", "blur", "selec t", "input", "change", "submit", "reset");
1918 else
1919 push(result, types[i]);
1920 }
1921 return result;
1922 },
1923
1924 /**
1925 * @param {!Event} event
1926 */
1927 _logEvent: function(event)
1928 {
1929 inspectedGlobalObject.console.log(event.type, event);
1930 }
1931 }
1932
1933 injectedScript._commandLineAPIImpl = new CommandLineAPIImpl();
1934 return injectedScript;
1935 })
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698