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

Side by Side Diff: third_party/WebKit/Source/platform/v8_inspector/InjectedScriptSource.js

Issue 2295913003: [DevTools] Switch from platform/v8_inspector to v8/v8-inspector.h. (Closed)
Patch Set: rebase Created 4 years, 3 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 {*} obj
58 * @return {string}
59 * @suppress {uselessCode}
60 */
61 function toString(obj)
62 {
63 // We don't use String(obj) because String could be overridden.
64 // Also the ("" + obj) expression may throw.
65 try {
66 return "" + obj;
67 } catch (e) {
68 var name = InjectedScriptHost.internalConstructorName(obj) || InjectedSc riptHost.subtype(obj) || (typeof obj);
69 return "#<" + name + ">";
70 }
71 }
72
73 /**
74 * @param {*} obj
75 * @return {string}
76 */
77 function toStringDescription(obj)
78 {
79 if (typeof obj === "number" && obj === 0 && 1 / obj < 0)
80 return "-0"; // Negative zero.
81 return toString(obj);
82 }
83
84 /**
85 * @param {T} obj
86 * @return {T}
87 * @template T
88 */
89 function nullifyObjectProto(obj)
90 {
91 if (obj && typeof obj === "object")
92 obj.__proto__ = null;
93 return obj;
94 }
95
96 /**
97 * @param {number|string} obj
98 * @return {boolean}
99 */
100 function isUInt32(obj)
101 {
102 if (typeof obj === "number")
103 return obj >>> 0 === obj && (obj > 0 || 1 / obj > 0);
104 return "" + (obj >>> 0) === obj;
105 }
106
107 /**
108 * FireBug's array detection.
109 * @param {*} obj
110 * @return {boolean}
111 */
112 function isArrayLike(obj)
113 {
114 if (typeof obj !== "object")
115 return false;
116 try {
117 if (typeof obj.splice === "function") {
118 if (!InjectedScriptHost.objectHasOwnProperty(/** @type {!Object} */ (obj), "length"))
119 return false;
120 var len = obj.length;
121 return typeof len === "number" && isUInt32(len);
122 }
123 } catch (e) {
124 }
125 return false;
126 }
127
128 /**
129 * @param {number} a
130 * @param {number} b
131 * @return {number}
132 */
133 function max(a, b)
134 {
135 return a > b ? a : b;
136 }
137
138 /**
139 * FIXME: Remove once ES6 is supported natively by JS compiler.
140 * @param {*} obj
141 * @return {boolean}
142 */
143 function isSymbol(obj)
144 {
145 var type = typeof obj;
146 return (type === "symbol");
147 }
148
149 /**
150 * DOM Attributes which have observable side effect on getter, in the form of
151 * {interfaceName1: {attributeName1: true,
152 * attributeName2: true,
153 * ...},
154 * interfaceName2: {...},
155 * ...}
156 * @type {!Object<string, !Object<string, boolean>>}
157 * @const
158 */
159 var domAttributesWithObservableSideEffectOnGet = nullifyObjectProto({});
160 domAttributesWithObservableSideEffectOnGet["Request"] = nullifyObjectProto({});
161 domAttributesWithObservableSideEffectOnGet["Request"]["body"] = true;
162 domAttributesWithObservableSideEffectOnGet["Response"] = nullifyObjectProto({});
163 domAttributesWithObservableSideEffectOnGet["Response"]["body"] = true;
164
165 /**
166 * @param {!Object} object
167 * @param {string} attribute
168 * @return {boolean}
169 */
170 function doesAttributeHaveObservableSideEffectOnGet(object, attribute)
171 {
172 for (var interfaceName in domAttributesWithObservableSideEffectOnGet) {
173 var interfaceFunction = inspectedGlobalObject[interfaceName];
174 // Call to instanceOf looks safe after typeof check.
175 var isInstance = typeof interfaceFunction === "function" && /* suppressB lacklist */ object instanceof interfaceFunction;
176 if (isInstance)
177 return attribute in domAttributesWithObservableSideEffectOnGet[inter faceName];
178 }
179 return false;
180 }
181
182 /**
183 * @constructor
184 */
185 var InjectedScript = function()
186 {
187 }
188
189 /**
190 * @type {!Object.<string, boolean>}
191 * @const
192 */
193 InjectedScript.primitiveTypes = {
194 "undefined": true,
195 "boolean": true,
196 "number": true,
197 "string": true,
198 __proto__: null
199 }
200
201 /**
202 * @type {!Object<string, string>}
203 * @const
204 */
205 InjectedScript.closureTypes = { __proto__: null };
206 InjectedScript.closureTypes["local"] = "Local";
207 InjectedScript.closureTypes["closure"] = "Closure";
208 InjectedScript.closureTypes["catch"] = "Catch";
209 InjectedScript.closureTypes["block"] = "Block";
210 InjectedScript.closureTypes["script"] = "Script";
211 InjectedScript.closureTypes["with"] = "With Block";
212 InjectedScript.closureTypes["global"] = "Global";
213
214 InjectedScript.prototype = {
215 /**
216 * @param {*} object
217 * @return {boolean}
218 */
219 isPrimitiveValue: function(object)
220 {
221 // FIXME(33716): typeof document.all is always 'undefined'.
222 return InjectedScript.primitiveTypes[typeof object] && !this._isHTMLAllC ollection(object);
223 },
224
225 /**
226 * @param {*} object
227 * @return {boolean}
228 */
229 _shouldPassByValue: function(object)
230 {
231 return typeof object === "object" && InjectedScriptHost.subtype(object) === "internal#location";
232 },
233
234 /**
235 * @param {*} object
236 * @param {string} groupName
237 * @param {boolean} forceValueType
238 * @param {boolean} generatePreview
239 * @return {!RuntimeAgent.RemoteObject}
240 */
241 wrapObject: function(object, groupName, forceValueType, generatePreview)
242 {
243 return this._wrapObject(object, groupName, forceValueType, generatePrevi ew);
244 },
245
246 /**
247 * @param {!Array<!Object>} array
248 * @param {string} property
249 * @param {string} groupName
250 * @param {boolean} forceValueType
251 * @param {boolean} generatePreview
252 */
253 wrapPropertyInArray: function(array, property, groupName, forceValueType, ge neratePreview)
254 {
255 for (var i = 0; i < array.length; ++i) {
256 if (typeof array[i] === "object" && property in array[i])
257 array[i][property] = this.wrapObject(array[i][property], groupNa me, forceValueType, generatePreview);
258 }
259 },
260
261 /**
262 * @param {!Array<*>} array
263 * @param {string} groupName
264 * @param {boolean} forceValueType
265 * @param {boolean} generatePreview
266 */
267 wrapObjectsInArray: function(array, groupName, forceValueType, generatePrevi ew)
268 {
269 for (var i = 0; i < array.length; ++i)
270 array[i] = this.wrapObject(array[i], groupName, forceValueType, gene ratePreview);
271 },
272
273 /**
274 * @param {!Object} table
275 * @param {!Array.<string>|string|boolean} columns
276 * @return {!RuntimeAgent.RemoteObject}
277 */
278 wrapTable: function(table, columns)
279 {
280 var columnNames = null;
281 if (typeof columns === "string")
282 columns = [columns];
283 if (InjectedScriptHost.subtype(columns) === "array") {
284 columnNames = [];
285 for (var i = 0; i < columns.length; ++i)
286 columnNames[i] = toString(columns[i]);
287 }
288 return this._wrapObject(table, "console", false, true, columnNames, true );
289 },
290
291 /**
292 * This method cannot throw.
293 * @param {*} object
294 * @param {string=} objectGroupName
295 * @param {boolean=} forceValueType
296 * @param {boolean=} generatePreview
297 * @param {?Array.<string>=} columnNames
298 * @param {boolean=} isTable
299 * @param {boolean=} doNotBind
300 * @param {*=} customObjectConfig
301 * @return {!RuntimeAgent.RemoteObject}
302 * @suppress {checkTypes}
303 */
304 _wrapObject: function(object, objectGroupName, forceValueType, generatePrevi ew, columnNames, isTable, doNotBind, customObjectConfig)
305 {
306 try {
307 return new InjectedScript.RemoteObject(object, objectGroupName, doNo tBind, forceValueType, generatePreview, columnNames, isTable, undefined, customO bjectConfig);
308 } catch (e) {
309 try {
310 var description = injectedScript._describe(e);
311 } catch (ex) {
312 var description = "<failed to convert exception to string>";
313 }
314 return new InjectedScript.RemoteObject(description);
315 }
316 },
317
318 /**
319 * @param {!Object|symbol} object
320 * @param {string=} objectGroupName
321 * @return {string}
322 */
323 _bind: function(object, objectGroupName)
324 {
325 var id = InjectedScriptHost.bind(object, objectGroupName || "");
326 return "{\"injectedScriptId\":" + injectedScriptId + ",\"id\":" + id + " }";
327 },
328
329 /**
330 * @param {!Object} object
331 * @param {string} objectGroupName
332 * @param {boolean} ownProperties
333 * @param {boolean} accessorPropertiesOnly
334 * @param {boolean} generatePreview
335 * @return {!Array<!RuntimeAgent.PropertyDescriptor>|boolean}
336 */
337 getProperties: function(object, objectGroupName, ownProperties, accessorProp ertiesOnly, generatePreview)
338 {
339 var subtype = this._subtype(object);
340 if (subtype === "internal#scope") {
341 // Internally, scope contains object with scope variables and additi onal information like type,
342 // we use additional information for preview and would like to repor t variables as scope
343 // properties.
344 object = object.object;
345 }
346
347 var descriptors = [];
348 var iter = this._propertyDescriptors(object, ownProperties, accessorProp ertiesOnly, undefined);
349 // Go over properties, wrap object values.
350 for (var descriptor of iter) {
351 if (subtype === "internal#scopeList" && descriptor.name === "length" )
352 continue;
353 if ("get" in descriptor)
354 descriptor.get = this._wrapObject(descriptor.get, objectGroupNam e);
355 if ("set" in descriptor)
356 descriptor.set = this._wrapObject(descriptor.set, objectGroupNam e);
357 if ("value" in descriptor)
358 descriptor.value = this._wrapObject(descriptor.value, objectGrou pName, false, generatePreview);
359 if (!("configurable" in descriptor))
360 descriptor.configurable = false;
361 if (!("enumerable" in descriptor))
362 descriptor.enumerable = false;
363 if ("symbol" in descriptor)
364 descriptor.symbol = this._wrapObject(descriptor.symbol, objectGr oupName);
365 push(descriptors, descriptor);
366 }
367 return descriptors;
368 },
369
370 /**
371 * @param {!Object} object
372 * @return {?Object}
373 */
374 _objectPrototype: function(object)
375 {
376 if (InjectedScriptHost.subtype(object) === "proxy")
377 return null;
378 try {
379 return Object.getPrototypeOf(object);
380 } catch (e) {
381 return null;
382 }
383 },
384
385 /**
386 * @param {!Object} object
387 * @param {boolean=} ownProperties
388 * @param {boolean=} accessorPropertiesOnly
389 * @param {?Array.<string>=} propertyNamesOnly
390 */
391 _propertyDescriptors: function*(object, ownProperties, accessorPropertiesOnl y, propertyNamesOnly)
392 {
393 var propertyProcessed = { __proto__: null };
394
395 /**
396 * @param {?Object} o
397 * @param {!Iterable<string|symbol|number>|!Array<string|number|symbol>} properties
398 */
399 function* process(o, properties)
400 {
401 for (var property of properties) {
402 var name;
403 if (isSymbol(property))
404 name = /** @type {string} */ (injectedScript._describe(prope rty));
405 else
406 name = typeof property === "number" ? ("" + property) : /** @type {string} */(property);
407
408 if (propertyProcessed[property])
409 continue;
410
411 try {
412 propertyProcessed[property] = true;
413 var descriptor = nullifyObjectProto(Object.getOwnPropertyDes criptor(o, property));
414 if (descriptor) {
415 if (accessorPropertiesOnly && !("get" in descriptor || " set" in descriptor))
416 continue;
417 if ("get" in descriptor && "set" in descriptor && name ! = "__proto__" && InjectedScriptHost.formatAccessorsAsProperties(object, descript or.get) && !doesAttributeHaveObservableSideEffectOnGet(object, name)) {
418 descriptor.value = object[property];
419 descriptor.isOwn = true;
420 delete descriptor.get;
421 delete descriptor.set;
422 }
423 } else {
424 // Not all bindings provide proper descriptors. Fall bac k to the writable, configurable property.
425 if (accessorPropertiesOnly)
426 continue;
427 try {
428 descriptor = { name: name, value: o[property], writa ble: false, configurable: false, enumerable: false, __proto__: null };
429 if (o === object)
430 descriptor.isOwn = true;
431 yield descriptor;
432 } catch (e) {
433 // Silent catch.
434 }
435 continue;
436 }
437 } catch (e) {
438 if (accessorPropertiesOnly)
439 continue;
440 var descriptor = { __proto__: null };
441 descriptor.value = e;
442 descriptor.wasThrown = true;
443 }
444
445 descriptor.name = name;
446 if (o === object)
447 descriptor.isOwn = true;
448 if (isSymbol(property))
449 descriptor.symbol = property;
450 yield descriptor;
451 }
452 }
453
454 if (propertyNamesOnly) {
455 for (var i = 0; i < propertyNamesOnly.length; ++i) {
456 var name = propertyNamesOnly[i];
457 for (var o = object; this._isDefined(o); o = this._objectPrototy pe(o)) {
458 if (InjectedScriptHost.objectHasOwnProperty(o, name)) {
459 for (var descriptor of process(o, [name]))
460 yield descriptor;
461 break;
462 }
463 if (ownProperties)
464 break;
465 }
466 }
467 return;
468 }
469
470 /**
471 * @param {number} length
472 */
473 function* arrayIndexNames(length)
474 {
475 for (var i = 0; i < length; ++i)
476 yield "" + i;
477 }
478
479 var skipGetOwnPropertyNames;
480 try {
481 skipGetOwnPropertyNames = InjectedScriptHost.subtype(object) === "ty pedarray" && object.length > 500000;
482 } catch (e) {
483 }
484
485 for (var o = object; this._isDefined(o); o = this._objectPrototype(o)) {
486 if (InjectedScriptHost.subtype(o) === "proxy")
487 continue;
488 if (skipGetOwnPropertyNames && o === object) {
489 // Avoid OOM crashes from getting all own property names of a la rge TypedArray.
490 for (var descriptor of process(o, arrayIndexNames(o.length)))
491 yield descriptor;
492 } else {
493 // First call Object.keys() to enforce ordering of the property descriptors.
494 for (var descriptor of process(o, Object.keys(/** @type {!Object } */ (o))))
495 yield descriptor;
496 for (var descriptor of process(o, Object.getOwnPropertyNames(/** @type {!Object} */ (o))))
497 yield descriptor;
498 }
499 if (Object.getOwnPropertySymbols) {
500 for (var descriptor of process(o, Object.getOwnPropertySymbols(/ ** @type {!Object} */ (o))))
501 yield descriptor;
502 }
503 if (ownProperties) {
504 var proto = this._objectPrototype(o);
505 if (proto && !accessorPropertiesOnly)
506 yield { name: "__proto__", value: proto, writable: true, con figurable: true, enumerable: false, isOwn: true, __proto__: null };
507 break;
508 }
509 }
510 },
511
512 /**
513 * @param {string|undefined} objectGroupName
514 * @param {*} jsonMLObject
515 * @throws {string} error message
516 */
517 _substituteObjectTagsInCustomPreview: function(objectGroupName, jsonMLObject )
518 {
519 var maxCustomPreviewRecursionDepth = 20;
520 this._customPreviewRecursionDepth = (this._customPreviewRecursionDepth | | 0) + 1
521 try {
522 if (this._customPreviewRecursionDepth >= maxCustomPreviewRecursionDe pth)
523 throw new Error("Too deep hierarchy of inlined custom previews") ;
524
525 if (!isArrayLike(jsonMLObject))
526 return;
527
528 if (jsonMLObject[0] === "object") {
529 var attributes = jsonMLObject[1];
530 var originObject = attributes["object"];
531 var config = attributes["config"];
532 if (typeof originObject === "undefined")
533 throw new Error("Illegal format: obligatory attribute \"obje ct\" isn't specified");
534
535 jsonMLObject[1] = this._wrapObject(originObject, objectGroupName , false, false, null, false, false, config);
536 return;
537 }
538
539 for (var i = 0; i < jsonMLObject.length; ++i)
540 this._substituteObjectTagsInCustomPreview(objectGroupName, jsonM LObject[i]);
541 } finally {
542 this._customPreviewRecursionDepth--;
543 }
544 },
545
546 /**
547 * @param {*} object
548 * @return {boolean}
549 */
550 _isDefined: function(object)
551 {
552 return !!object || this._isHTMLAllCollection(object);
553 },
554
555 /**
556 * @param {*} object
557 * @return {boolean}
558 */
559 _isHTMLAllCollection: function(object)
560 {
561 // document.all is reported as undefined, but we still want to process i t.
562 return (typeof object === "undefined") && !!InjectedScriptHost.subtype(o bject);
563 },
564
565 /**
566 * @param {*} obj
567 * @return {?string}
568 */
569 _subtype: function(obj)
570 {
571 if (obj === null)
572 return "null";
573
574 if (this.isPrimitiveValue(obj))
575 return null;
576
577 var subtype = InjectedScriptHost.subtype(obj);
578 if (subtype)
579 return subtype;
580
581 if (isArrayLike(obj))
582 return "array";
583
584 // If owning frame has navigated to somewhere else window properties wil l be undefined.
585 return null;
586 },
587
588 /**
589 * @param {*} obj
590 * @return {?string}
591 */
592 _describe: function(obj)
593 {
594 if (this.isPrimitiveValue(obj))
595 return null;
596
597 var subtype = this._subtype(obj);
598
599 if (subtype === "regexp")
600 return toString(obj);
601
602 if (subtype === "date")
603 return toString(obj);
604
605 if (subtype === "node") {
606 var description = "";
607 if (obj.nodeName)
608 description = obj.nodeName.toLowerCase();
609 else if (obj.constructor)
610 description = obj.constructor.name.toLowerCase();
611
612 switch (obj.nodeType) {
613 case 1 /* Node.ELEMENT_NODE */:
614 description += obj.id ? "#" + obj.id : "";
615 var className = obj.className;
616 description += (className && typeof className === "string") ? ". " + className.trim().replace(/\s+/g, ".") : "";
617 break;
618 case 10 /*Node.DOCUMENT_TYPE_NODE */:
619 description = "<!DOCTYPE " + description + ">";
620 break;
621 }
622 return description;
623 }
624
625 if (subtype === "proxy")
626 return "Proxy";
627
628 var className = InjectedScriptHost.internalConstructorName(obj);
629 if (subtype === "array" || subtype === "typedarray") {
630 if (typeof obj.length === "number")
631 className += "[" + obj.length + "]";
632 return className;
633 }
634
635 if (typeof obj === "function")
636 return toString(obj);
637
638 if (isSymbol(obj)) {
639 try {
640 // It isn't safe, because Symbol.prototype.toString can be overr iden.
641 return /* suppressBlacklist */ obj.toString() || "Symbol";
642 } catch (e) {
643 return "Symbol";
644 }
645 }
646
647 if (InjectedScriptHost.subtype(obj) === "error") {
648 try {
649 var stack = obj.stack;
650 var message = obj.message && obj.message.length ? ": " + obj.mes sage : "";
651 var firstCallFrame = /^\s+at\s/m.exec(stack);
652 var stackMessageEnd = firstCallFrame ? firstCallFrame.index : -1 ;
653 if (stackMessageEnd !== -1) {
654 var stackTrace = stack.substr(stackMessageEnd);
655 return className + message + "\n" + stackTrace;
656 }
657 return className + message;
658 } catch(e) {
659 }
660 }
661
662 if (subtype === "internal#entry") {
663 if ("key" in obj)
664 return "{" + this._describeIncludingPrimitives(obj.key) + " => " + this._describeIncludingPrimitives(obj.value) + "}";
665 return this._describeIncludingPrimitives(obj.value);
666 }
667
668 if (subtype === "internal#scopeList")
669 return "Scopes[" + obj.length + "]";
670
671 if (subtype === "internal#scope")
672 return (InjectedScript.closureTypes[obj.type] || "Unknown") + (obj.n ame ? " (" + obj.name + ")" : "");
673
674 return className;
675 },
676
677 /**
678 * @param {*} value
679 * @return {string}
680 */
681 _describeIncludingPrimitives: function(value)
682 {
683 if (typeof value === "string")
684 return "\"" + value.replace(/\n/g, "\u21B5") + "\"";
685 if (value === null)
686 return "" + value;
687 return this.isPrimitiveValue(value) ? toStringDescription(value) : (this ._describe(value) || "");
688 },
689
690 /**
691 * @param {boolean} enabled
692 */
693 setCustomObjectFormatterEnabled: function(enabled)
694 {
695 this._customObjectFormatterEnabled = enabled;
696 }
697 }
698
699 /**
700 * @type {!InjectedScript}
701 * @const
702 */
703 var injectedScript = new InjectedScript();
704
705 /**
706 * @constructor
707 * @param {*} object
708 * @param {string=} objectGroupName
709 * @param {boolean=} doNotBind
710 * @param {boolean=} forceValueType
711 * @param {boolean=} generatePreview
712 * @param {?Array.<string>=} columnNames
713 * @param {boolean=} isTable
714 * @param {boolean=} skipEntriesPreview
715 * @param {*=} customObjectConfig
716 */
717 InjectedScript.RemoteObject = function(object, objectGroupName, doNotBind, force ValueType, generatePreview, columnNames, isTable, skipEntriesPreview, customObje ctConfig)
718 {
719 this.type = typeof object;
720 if (this.type === "undefined" && injectedScript._isHTMLAllCollection(object) )
721 this.type = "object";
722
723 if (injectedScript.isPrimitiveValue(object) || object === null || forceValue Type) {
724 // We don't send undefined values over JSON.
725 if (this.type !== "undefined")
726 this.value = object;
727
728 // Null object is object with 'null' subtype.
729 if (object === null)
730 this.subtype = "null";
731
732 // Provide user-friendly number values.
733 if (this.type === "number") {
734 this.description = toStringDescription(object);
735 switch (this.description) {
736 case "NaN":
737 case "Infinity":
738 case "-Infinity":
739 case "-0":
740 delete this.value;
741 this.unserializableValue = this.description;
742 break;
743 }
744 }
745
746 return;
747 }
748
749 if (injectedScript._shouldPassByValue(object)) {
750 this.value = object;
751 this.subtype = injectedScript._subtype(object);
752 this.description = injectedScript._describeIncludingPrimitives(object);
753 return;
754 }
755
756 object = /** @type {!Object} */ (object);
757
758 if (!doNotBind)
759 this.objectId = injectedScript._bind(object, objectGroupName);
760 var subtype = injectedScript._subtype(object);
761 if (subtype)
762 this.subtype = subtype;
763 var className = InjectedScriptHost.internalConstructorName(object);
764 if (className)
765 this.className = className;
766 this.description = injectedScript._describe(object);
767
768 if (generatePreview && this.type === "object") {
769 if (this.subtype === "proxy")
770 this.preview = this._generatePreview(InjectedScriptHost.proxyTargetV alue(object), undefined, columnNames, isTable, skipEntriesPreview);
771 else if (this.subtype !== "node")
772 this.preview = this._generatePreview(object, undefined, columnNames, isTable, skipEntriesPreview);
773 }
774
775 if (injectedScript._customObjectFormatterEnabled) {
776 var customPreview = this._customPreview(object, objectGroupName, customO bjectConfig);
777 if (customPreview)
778 this.customPreview = customPreview;
779 }
780 }
781
782 InjectedScript.RemoteObject.prototype = {
783
784 /**
785 * @param {*} object
786 * @param {string=} objectGroupName
787 * @param {*=} customObjectConfig
788 * @return {?RuntimeAgent.CustomPreview}
789 */
790 _customPreview: function(object, objectGroupName, customObjectConfig)
791 {
792 /**
793 * @param {!Error} error
794 */
795 function logError(error)
796 {
797 // We use user code to generate custom output for object, we can use user code for reporting error too.
798 Promise.resolve().then(/* suppressBlacklist */ inspectedGlobalObject .console.error.bind(inspectedGlobalObject.console, "Custom Formatter Failed: " + error.message));
799 }
800
801 /**
802 * @suppressReceiverCheck
803 * @param {*} object
804 * @param {*=} customObjectConfig
805 * @return {*}
806 */
807 function wrap(object, customObjectConfig)
808 {
809 return injectedScript._wrapObject(object, objectGroupName, false, fa lse, null, false, false, customObjectConfig);
810 }
811
812 try {
813 var formatters = inspectedGlobalObject["devtoolsFormatters"];
814 if (!formatters || !isArrayLike(formatters))
815 return null;
816
817 for (var i = 0; i < formatters.length; ++i) {
818 try {
819 var formatted = formatters[i].header(object, customObjectCon fig);
820 if (!formatted)
821 continue;
822
823 var hasBody = formatters[i].hasBody(object, customObjectConf ig);
824 injectedScript._substituteObjectTagsInCustomPreview(objectGr oupName, formatted);
825 var formatterObjectId = injectedScript._bind(formatters[i], objectGroupName);
826 var bindRemoteObjectFunctionId = injectedScript._bind(wrap, objectGroupName);
827 var result = {header: JSON.stringify(formatted), hasBody: !! hasBody, formatterObjectId: formatterObjectId, bindRemoteObjectFunctionId: bindR emoteObjectFunctionId};
828 if (customObjectConfig)
829 result["configObjectId"] = injectedScript._bind(customOb jectConfig, objectGroupName);
830 return result;
831 } catch (e) {
832 logError(e);
833 }
834 }
835 } catch (e) {
836 logError(e);
837 }
838 return null;
839 },
840
841 /**
842 * @return {!RuntimeAgent.ObjectPreview} preview
843 */
844 _createEmptyPreview: function()
845 {
846 var preview = {
847 type: /** @type {!RuntimeAgent.ObjectPreviewType.<string>} */ (this. type),
848 description: this.description || toStringDescription(this.value),
849 overflow: false,
850 properties: [],
851 __proto__: null
852 };
853 if (this.subtype)
854 preview.subtype = /** @type {!RuntimeAgent.ObjectPreviewSubtype.<str ing>} */ (this.subtype);
855 return preview;
856 },
857
858 /**
859 * @param {!Object} object
860 * @param {?Array.<string>=} firstLevelKeys
861 * @param {?Array.<string>=} secondLevelKeys
862 * @param {boolean=} isTable
863 * @param {boolean=} skipEntriesPreview
864 * @return {!RuntimeAgent.ObjectPreview} preview
865 */
866 _generatePreview: function(object, firstLevelKeys, secondLevelKeys, isTable, skipEntriesPreview)
867 {
868 var preview = this._createEmptyPreview();
869 var firstLevelKeysCount = firstLevelKeys ? firstLevelKeys.length : 0;
870
871 var propertiesThreshold = {
872 properties: isTable ? 1000 : max(5, firstLevelKeysCount),
873 indexes: isTable ? 1000 : max(100, firstLevelKeysCount),
874 __proto__: null
875 };
876
877 try {
878 var descriptors = injectedScript._propertyDescriptors(object, undefi ned, undefined, firstLevelKeys);
879
880 this._appendPropertyDescriptors(preview, descriptors, propertiesThre shold, secondLevelKeys, isTable);
881 if (propertiesThreshold.indexes < 0 || propertiesThreshold.propertie s < 0)
882 return preview;
883
884 // Add internal properties to preview.
885 var rawInternalProperties = InjectedScriptHost.getInternalProperties (object) || [];
886 var internalProperties = [];
887 var entries = null;
888 for (var i = 0; i < rawInternalProperties.length; i += 2) {
889 if (rawInternalProperties[i] === "[[Entries]]") {
890 entries = /** @type {!Array<*>} */(rawInternalProperties[i + 1]);
891 continue;
892 }
893 push(internalProperties, {
894 name: rawInternalProperties[i],
895 value: rawInternalProperties[i + 1],
896 isOwn: true,
897 enumerable: true,
898 __proto__: null
899 });
900 }
901 this._appendPropertyDescriptors(preview, internalProperties, propert iesThreshold, secondLevelKeys, isTable);
902
903 if (this.subtype === "map" || this.subtype === "set" || this.subtype === "iterator")
904 this._appendEntriesPreview(entries, preview, skipEntriesPreview) ;
905
906 } catch (e) {}
907
908 return preview;
909 },
910
911 /**
912 * @param {!RuntimeAgent.ObjectPreview} preview
913 * @param {!Array.<*>|!Iterable.<*>} descriptors
914 * @param {!Object} propertiesThreshold
915 * @param {?Array.<string>=} secondLevelKeys
916 * @param {boolean=} isTable
917 */
918 _appendPropertyDescriptors: function(preview, descriptors, propertiesThresho ld, secondLevelKeys, isTable)
919 {
920 for (var descriptor of descriptors) {
921 if (propertiesThreshold.indexes < 0 || propertiesThreshold.propertie s < 0)
922 break;
923 if (!descriptor || descriptor.wasThrown)
924 continue;
925
926 var name = descriptor.name;
927
928 // Ignore __proto__ property.
929 if (name === "__proto__")
930 continue;
931
932 // Ignore length property of array.
933 if ((this.subtype === "array" || this.subtype === "typedarray") && n ame === "length")
934 continue;
935
936 // Ignore size property of map, set.
937 if ((this.subtype === "map" || this.subtype === "set") && name === " size")
938 continue;
939
940 // Never preview prototype properties.
941 if (!descriptor.isOwn)
942 continue;
943
944 // Ignore computed properties.
945 if (!("value" in descriptor))
946 continue;
947
948 var value = descriptor.value;
949 var type = typeof value;
950
951 // Never render functions in object preview.
952 if (type === "function" && (this.subtype !== "array" || !isUInt32(na me)))
953 continue;
954
955 // Special-case HTMLAll.
956 if (type === "undefined" && injectedScript._isHTMLAllCollection(valu e))
957 type = "object";
958
959 // Render own properties.
960 if (value === null) {
961 this._appendPropertyPreview(preview, { name: name, type: "object ", subtype: "null", value: "null", __proto__: null }, propertiesThreshold);
962 continue;
963 }
964
965 var maxLength = 100;
966 if (InjectedScript.primitiveTypes[type]) {
967 if (type === "string" && value.length > maxLength)
968 value = this._abbreviateString(value, maxLength, true);
969 this._appendPropertyPreview(preview, { name: name, type: type, v alue: toStringDescription(value), __proto__: null }, propertiesThreshold);
970 continue;
971 }
972
973 var property = { name: name, type: type, __proto__: null };
974 var subtype = injectedScript._subtype(value);
975 if (subtype)
976 property.subtype = subtype;
977
978 if (secondLevelKeys === null || secondLevelKeys) {
979 var subPreview = this._generatePreview(value, secondLevelKeys || undefined, undefined, isTable);
980 property.valuePreview = subPreview;
981 if (subPreview.overflow)
982 preview.overflow = true;
983 } else {
984 var description = "";
985 if (type !== "function")
986 description = this._abbreviateString(/** @type {string} */ ( injectedScript._describe(value)), maxLength, subtype === "regexp");
987 property.value = description;
988 }
989 this._appendPropertyPreview(preview, property, propertiesThreshold);
990 }
991 },
992
993 /**
994 * @param {!RuntimeAgent.ObjectPreview} preview
995 * @param {!Object} property
996 * @param {!Object} propertiesThreshold
997 */
998 _appendPropertyPreview: function(preview, property, propertiesThreshold)
999 {
1000 if (toString(property.name >>> 0) === property.name)
1001 propertiesThreshold.indexes--;
1002 else
1003 propertiesThreshold.properties--;
1004 if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0) {
1005 preview.overflow = true;
1006 } else {
1007 push(preview.properties, property);
1008 }
1009 },
1010
1011 /**
1012 * @param {?Array<*>} entries
1013 * @param {!RuntimeAgent.ObjectPreview} preview
1014 * @param {boolean=} skipEntriesPreview
1015 */
1016 _appendEntriesPreview: function(entries, preview, skipEntriesPreview)
1017 {
1018 if (!entries)
1019 return;
1020 if (skipEntriesPreview) {
1021 if (entries.length)
1022 preview.overflow = true;
1023 return;
1024 }
1025 preview.entries = [];
1026 var entriesThreshold = 5;
1027 for (var i = 0; i < entries.length; ++i) {
1028 if (preview.entries.length >= entriesThreshold) {
1029 preview.overflow = true;
1030 break;
1031 }
1032 var entry = nullifyObjectProto(entries[i]);
1033 var previewEntry = {
1034 value: generateValuePreview(entry.value),
1035 __proto__: null
1036 };
1037 if ("key" in entry)
1038 previewEntry.key = generateValuePreview(entry.key);
1039 push(preview.entries, previewEntry);
1040 }
1041
1042 /**
1043 * @param {*} value
1044 * @return {!RuntimeAgent.ObjectPreview}
1045 */
1046 function generateValuePreview(value)
1047 {
1048 var remoteObject = new InjectedScript.RemoteObject(value, undefined, true, undefined, true, undefined, undefined, true);
1049 var valuePreview = remoteObject.preview || remoteObject._createEmpty Preview();
1050 return valuePreview;
1051 }
1052 },
1053
1054 /**
1055 * @param {string} string
1056 * @param {number} maxLength
1057 * @param {boolean=} middle
1058 * @return {string}
1059 */
1060 _abbreviateString: function(string, maxLength, middle)
1061 {
1062 if (string.length <= maxLength)
1063 return string;
1064 if (middle) {
1065 var leftHalf = maxLength >> 1;
1066 var rightHalf = maxLength - leftHalf - 1;
1067 return string.substr(0, leftHalf) + "\u2026" + string.substr(string. length - rightHalf, rightHalf);
1068 }
1069 return string.substr(0, maxLength) + "\u2026";
1070 },
1071
1072 __proto__: null
1073 }
1074
1075 return injectedScript;
1076 })
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698