Web Inspector: Logging a native function to the console, such as `alert`, produces...
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Protocol / RemoteObject.js
1 /*
2  * Copyright (C) 2009 Google Inc. All rights reserved.
3  * Copyright (C) 2015 Apple 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 are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 WI.RemoteObject = class RemoteObject
33 {
34     constructor(target, objectId, type, subtype, value, description, size, classPrototype, className, preview)
35     {
36         console.assert(type);
37         console.assert(!preview || preview instanceof WI.ObjectPreview);
38         console.assert(!target || target instanceof WI.Target);
39
40         this._target = target || WI.mainTarget;
41         this._type = type;
42         this._subtype = subtype;
43
44         if (objectId) {
45             // Object, Function, or Symbol.
46             console.assert(!subtype || typeof subtype === "string");
47             console.assert(!description || typeof description === "string");
48             console.assert(!value);
49
50             this._objectId = objectId;
51             this._description = description || "";
52             this._hasChildren = type !== "symbol";
53             this._size = size;
54             this._classPrototype = classPrototype;
55             this._preview = preview;
56
57             if (subtype === "class") {
58                 this._functionDescription = this._description;
59                 this._description = "class " + className;
60             }
61         } else {
62             // Primitive or null.
63             console.assert(type !== "object" || value === null);
64             console.assert(!preview);
65
66             this._description = description || (value + "");
67             this._hasChildren = false;
68             this._value = value;
69         }
70     }
71
72     // Static
73
74     static createFakeRemoteObject()
75     {
76         return new WI.RemoteObject(undefined, WI.RemoteObject.FakeRemoteObjectId, "object");
77     }
78
79     static fromPrimitiveValue(value)
80     {
81         return new WI.RemoteObject(undefined, undefined, typeof value, undefined, value, undefined, undefined, undefined, undefined);
82     }
83
84     static fromPayload(payload, target)
85     {
86         console.assert(typeof payload === "object", "Remote object payload should only be an object");
87
88         if (payload.subtype === "array") {
89             // COMPATIBILITY (iOS 8): Runtime.RemoteObject did not have size property,
90             // instead it was tacked onto the end of the description, like "Array[#]".
91             var match = payload.description.match(/\[(\d+)\]$/);
92             if (match) {
93                 payload.size = parseInt(match[1]);
94                 payload.description = payload.description.replace(/\[\d+\]$/, "");
95             }
96         }
97
98         if (payload.classPrototype)
99             payload.classPrototype = WI.RemoteObject.fromPayload(payload.classPrototype, target);
100
101         if (payload.preview) {
102             // COMPATIBILITY (iOS 8): Did not have type/subtype/description on
103             // Runtime.ObjectPreview. Copy them over from the RemoteObject.
104             if (!payload.preview.type) {
105                 payload.preview.type = payload.type;
106                 payload.preview.subtype = payload.subtype;
107                 payload.preview.description = payload.description;
108                 payload.preview.size = payload.size;
109             }
110
111             payload.preview = WI.ObjectPreview.fromPayload(payload.preview);
112         }
113
114         return new WI.RemoteObject(target, payload.objectId, payload.type, payload.subtype, payload.value, payload.description, payload.size, payload.classPrototype, payload.className, payload.preview);
115     }
116
117     static createCallArgument(valueOrObject)
118     {
119         if (valueOrObject instanceof WI.RemoteObject) {
120             if (valueOrObject.objectId)
121                 return {objectId: valueOrObject.objectId};
122             return {value: valueOrObject.value};
123         }
124
125         return {value: valueOrObject};
126     }
127
128     static resolveNode(node, objectGroup)
129     {
130         return DOMAgent.resolveNode(node.id, objectGroup)
131             .then(({object}) => WI.RemoteObject.fromPayload(object, WI.mainTarget));
132     }
133
134     static resolveWebSocket(webSocketResource, objectGroup, callback)
135     {
136         console.assert(typeof callback === "function");
137
138         NetworkAgent.resolveWebSocket(webSocketResource.requestIdentifier, objectGroup, (error, object) => {
139             if (error || !object)
140                 callback(null);
141             else
142                 callback(WI.RemoteObject.fromPayload(object, webSocketResource.target));
143         });
144     }
145
146     static resolveCanvasContext(canvas, objectGroup, callback)
147     {
148         console.assert(typeof callback === "function");
149
150         CanvasAgent.resolveCanvasContext(canvas.identifier, objectGroup, (error, object) => {
151             if (error || !object)
152                 callback(null);
153             else
154                 callback(WI.RemoteObject.fromPayload(object, WI.mainTarget));
155         });
156     }
157
158     // Public
159
160     get target()
161     {
162         return this._target;
163     }
164
165     get objectId()
166     {
167         return this._objectId;
168     }
169
170     get type()
171     {
172         return this._type;
173     }
174
175     get subtype()
176     {
177         return this._subtype;
178     }
179
180     get description()
181     {
182         return this._description;
183     }
184
185     get functionDescription()
186     {
187         console.assert(this.type === "function");
188
189         return this._functionDescription || this._description;
190     }
191
192     get hasChildren()
193     {
194         return this._hasChildren;
195     }
196
197     get value()
198     {
199         return this._value;
200     }
201
202     get size()
203     {
204         return this._size || 0;
205     }
206
207     get classPrototype()
208     {
209         return this._classPrototype;
210     }
211
212     get preview()
213     {
214         return this._preview;
215     }
216
217     hasSize()
218     {
219         return this.isArray() || this.isCollectionType();
220     }
221
222     hasValue()
223     {
224         return "_value" in this;
225     }
226
227     canLoadPreview()
228     {
229         if (this._failedToLoadPreview)
230             return false;
231
232         if (this._type !== "object")
233             return false;
234
235         if (!this._objectId || this._isSymbol() || this._isFakeObject())
236             return false;
237
238         return true;
239     }
240
241     updatePreview(callback)
242     {
243         if (!this.canLoadPreview()) {
244             callback(null);
245             return;
246         }
247
248         if (!this._target.RuntimeAgent.getPreview) {
249             this._failedToLoadPreview = true;
250             callback(null);
251             return;
252         }
253
254         this._target.RuntimeAgent.getPreview(this._objectId, (error, payload) => {
255             if (error) {
256                 this._failedToLoadPreview = true;
257                 callback(null);
258                 return;
259             }
260
261             this._preview = WI.ObjectPreview.fromPayload(payload);
262             callback(this._preview);
263         });
264     }
265
266     getPropertyDescriptors(callback, options = {})
267     {
268         if (!this._objectId || this._isSymbol() || this._isFakeObject()) {
269             callback([]);
270             return;
271         }
272
273         this._target.RuntimeAgent.getProperties(this._objectId, options.ownProperties, options.generatePreview, this._getPropertyDescriptorsResolver.bind(this, callback));
274     }
275
276     getDisplayablePropertyDescriptors(callback)
277     {
278         if (!this._objectId || this._isSymbol() || this._isFakeObject()) {
279             callback([]);
280             return;
281         }
282
283         // COMPATIBILITY (iOS 8): RuntimeAgent.getDisplayableProperties did not exist.
284         // Here we do our best to reimplement it by getting all properties and reducing them down.
285         if (!this._target.RuntimeAgent.getDisplayableProperties) {
286             this._target.RuntimeAgent.getProperties(this._objectId, function(error, allProperties) {
287                 var ownOrGetterPropertiesList = [];
288                 if (allProperties) {
289                     for (var property of allProperties) {
290                         if (property.isOwn || property.name === "__proto__") {
291                             // Own property or getter property in prototype chain.
292                             ownOrGetterPropertiesList.push(property);
293                         } else if (property.value && property.name !== property.name.toUpperCase()) {
294                             var type = property.value.type;
295                             if (type && type !== "function" && property.name !== "constructor") {
296                                 // Possible native binding getter property converted to a value. Also, no CONSTANT name style and not "constructor".
297                                 // There is no way of knowing if this is native or not, so just go with it.
298                                 ownOrGetterPropertiesList.push(property);
299                             }
300                         }
301                     }
302                 }
303
304                 this._getPropertyDescriptorsResolver(callback, error, ownOrGetterPropertiesList);
305             }.bind(this));
306             return;
307         }
308
309         this._target.RuntimeAgent.getDisplayableProperties(this._objectId, true, this._getPropertyDescriptorsResolver.bind(this, callback));
310     }
311
312     // FIXME: Phase out these deprecated functions. They return DeprecatedRemoteObjectProperty instead of PropertyDescriptors.
313     deprecatedGetOwnProperties(callback)
314     {
315         this._deprecatedGetProperties(true, callback);
316     }
317
318     deprecatedGetAllProperties(callback)
319     {
320         this._deprecatedGetProperties(false, callback);
321     }
322
323     deprecatedGetDisplayableProperties(callback)
324     {
325         if (!this._objectId || this._isSymbol() || this._isFakeObject()) {
326             callback([]);
327             return;
328         }
329
330         // COMPATIBILITY (iOS 8): RuntimeAgent.getProperties did not support ownerAndGetterProperties.
331         // Here we do our best to reimplement it by getting all properties and reducing them down.
332         if (!this._target.RuntimeAgent.getDisplayableProperties) {
333             this._target.RuntimeAgent.getProperties(this._objectId, function(error, allProperties) {
334                 var ownOrGetterPropertiesList = [];
335                 if (allProperties) {
336                     for (var property of allProperties) {
337                         if (property.isOwn || property.get || property.name === "__proto__") {
338                             // Own property or getter property in prototype chain.
339                             ownOrGetterPropertiesList.push(property);
340                         } else if (property.value && property.name !== property.name.toUpperCase()) {
341                             var type = property.value.type;
342                             if (type && type !== "function" && property.name !== "constructor") {
343                                 // Possible native binding getter property converted to a value. Also, no CONSTANT name style and not "constructor".
344                                 ownOrGetterPropertiesList.push(property);
345                             }
346                         }
347                     }
348                 }
349
350                 this._deprecatedGetPropertiesResolver(callback, error, ownOrGetterPropertiesList);
351             }.bind(this));
352             return;
353         }
354
355         this._target.RuntimeAgent.getDisplayableProperties(this._objectId, this._deprecatedGetPropertiesResolver.bind(this, callback));
356     }
357
358     setPropertyValue(name, value, callback)
359     {
360         if (!this._objectId || this._isSymbol() || this._isFakeObject()) {
361             callback("Can't set a property of non-object.");
362             return;
363         }
364
365         // FIXME: It doesn't look like setPropertyValue is used yet. This will need to be tested when it is again (editable ObjectTrees).
366         this._target.RuntimeAgent.evaluate.invoke({expression: appendWebInspectorSourceURL(value), doNotPauseOnExceptionsAndMuteConsole: true}, evaluatedCallback.bind(this), this._target.RuntimeAgent);
367
368         function evaluatedCallback(error, result, wasThrown)
369         {
370             if (error || wasThrown) {
371                 callback(error || result.description);
372                 return;
373             }
374
375             function setPropertyValue(propertyName, propertyValue)
376             {
377                 this[propertyName] = propertyValue;
378             }
379
380             delete result.description; // Optimize on traffic.
381
382             this._target.RuntimeAgent.callFunctionOn(this._objectId, appendWebInspectorSourceURL(setPropertyValue.toString()), [{value: name}, result], true, undefined, propertySetCallback.bind(this));
383
384             if (result._objectId)
385                 this._target.RuntimeAgent.releaseObject(result._objectId);
386         }
387
388         function propertySetCallback(error, result, wasThrown)
389         {
390             if (error || wasThrown) {
391                 callback(error || result.description);
392                 return;
393             }
394
395             callback();
396         }
397     }
398
399     isUndefined()
400     {
401         return this._type === "undefined";
402     }
403
404     isNode()
405     {
406         return this._subtype === "node";
407     }
408
409     isArray()
410     {
411         return this._subtype === "array";
412     }
413
414     isClass()
415     {
416         return this._subtype === "class";
417     }
418
419     isCollectionType()
420     {
421         return this._subtype === "map" || this._subtype === "set" || this._subtype === "weakmap" || this._subtype === "weakset";
422     }
423
424     isWeakCollection()
425     {
426         return this._subtype === "weakmap" || this._subtype === "weakset";
427     }
428
429     getCollectionEntries(start, numberToFetch, callback)
430     {
431         start = typeof start === "number" ? start : 0;
432         numberToFetch = typeof numberToFetch === "number" ? numberToFetch : 100;
433
434         console.assert(start >= 0);
435         console.assert(numberToFetch >= 0);
436         console.assert(this.isCollectionType());
437
438         // WeakMaps and WeakSets are not ordered. We should never send a non-zero start.
439         console.assert((this._subtype === "weakmap" && start === 0) || this._subtype !== "weakmap");
440         console.assert((this._subtype === "weakset" && start === 0) || this._subtype !== "weakset");
441
442         let objectGroup = this.isWeakCollection() ? this._weakCollectionObjectGroup() : "";
443
444         this._target.RuntimeAgent.getCollectionEntries(this._objectId, objectGroup, start, numberToFetch, (error, entries) => {
445             entries = entries.map((x) => WI.CollectionEntry.fromPayload(x, this._target));
446             callback(entries);
447         });
448     }
449
450     releaseWeakCollectionEntries()
451     {
452         console.assert(this.isWeakCollection());
453
454         this._target.RuntimeAgent.releaseObjectGroup(this._weakCollectionObjectGroup());
455     }
456
457     pushNodeToFrontend(callback)
458     {
459         if (this._objectId)
460             WI.domManager.pushNodeToFrontend(this._objectId, callback);
461         else
462             callback(0);
463     }
464
465     async fetchProperties(propertyNames, resultObject={})
466     {
467         let seenPropertyNames = new Set;
468         let requestedValues = [];
469         for (let propertyName of propertyNames) {
470             // Check this here, otherwise things like '{}' would be valid Set keys.
471             if (typeof propertyName !== "string" && typeof propertyName !== "number")
472                 throw new Error(`Tried to get property using key is not a string or number: ${propertyName}`);
473
474             if (seenPropertyNames.has(propertyName))
475                 continue;
476
477             seenPropertyNames.add(propertyName);
478             requestedValues.push(this.getProperty(propertyName));
479         }
480
481         // Return primitive values directly, otherwise return a WI.RemoteObject instance.
482         function maybeUnwrapValue(remoteObject) {
483             return remoteObject.hasValue() ? remoteObject.value : remoteObject;
484         }
485
486         // Request property values one by one, since returning an array of property
487         // values would then be subject to arbitrary object preview size limits.
488         let fetchedKeys = Array.from(seenPropertyNames);
489         let fetchedValues = await Promise.all(requestedValues);
490         for (let i = 0; i < fetchedKeys.length; ++i)
491             resultObject[fetchedKeys[i]] = maybeUnwrapValue(fetchedValues[i]);
492
493         return resultObject;
494     }
495
496     getProperty(propertyName, callback = null)
497     {
498         function inspectedPage_object_getProperty(property) {
499             if (typeof property !== "string" && typeof property !== "number")
500                 throw new Error(`Tried to get property using key is not a string or number: ${property}`);
501
502             return this[property];
503         }
504
505         if (callback && typeof callback === "function")
506             this.callFunction(inspectedPage_object_getProperty, [propertyName], true, callback);
507         else
508             return this.callFunction(inspectedPage_object_getProperty, [propertyName], true);
509     }
510
511     callFunction(functionDeclaration, args, generatePreview, callback = null)
512     {
513         let translateResult = (result) => result ? WI.RemoteObject.fromPayload(result, this._target) : null;
514
515         if (args)
516             args = args.map(WI.RemoteObject.createCallArgument);
517
518         if (callback && typeof callback === "function") {
519             this._target.RuntimeAgent.callFunctionOn(this._objectId, appendWebInspectorSourceURL(functionDeclaration.toString()), args, true, undefined, !!generatePreview, (error, result, wasThrown) => {
520                 callback(error, translateResult(result), wasThrown);
521             });
522         } else {
523             // Protocol errors and results that were thrown should cause promise rejection with the same.
524             return this._target.RuntimeAgent.callFunctionOn(this._objectId, appendWebInspectorSourceURL(functionDeclaration.toString()), args, true, undefined, !!generatePreview)
525                 .then(({result, wasThrown}) => {
526                     result = translateResult(result);
527                     if (result && wasThrown)
528                         return Promise.reject(result);
529                     return Promise.resolve(result);
530                 });
531         }
532     }
533
534     callFunctionJSON(functionDeclaration, args, callback)
535     {
536         function mycallback(error, result, wasThrown)
537         {
538             callback((error || wasThrown) ? null : result.value);
539         }
540
541         this._target.RuntimeAgent.callFunctionOn(this._objectId, appendWebInspectorSourceURL(functionDeclaration.toString()), args, true, true, mycallback);
542     }
543
544     invokeGetter(getterRemoteObject, callback)
545     {
546         console.assert(getterRemoteObject instanceof WI.RemoteObject);
547
548         function backendInvokeGetter(getter)
549         {
550             return getter ? getter.call(this) : undefined;
551         }
552
553         this.callFunction(backendInvokeGetter, [getterRemoteObject], true, callback);
554     }
555
556     getOwnPropertyDescriptor(propertyName, callback)
557     {
558         function backendGetOwnPropertyDescriptor(propertyName)
559         {
560             return this[propertyName];
561         }
562
563         function wrappedCallback(error, result, wasThrown)
564         {
565             if (error || wasThrown || !(result instanceof WI.RemoteObject)) {
566                 callback(null);
567                 return;
568             }
569
570             var fakeDescriptor = {name: propertyName, value: result, writable: true, configurable: true, enumerable: false};
571             var fakePropertyDescriptor = new WI.PropertyDescriptor(fakeDescriptor, null, true, false, false, false);
572             callback(fakePropertyDescriptor);
573         }
574
575         // FIXME: Implement a real RuntimeAgent.getOwnPropertyDescriptor?
576         this.callFunction(backendGetOwnPropertyDescriptor, [propertyName], false, wrappedCallback.bind(this));
577     }
578
579     release()
580     {
581         if (this._objectId && !this._isFakeObject())
582             this._target.RuntimeAgent.releaseObject(this._objectId);
583     }
584
585     arrayLength()
586     {
587         if (this._subtype !== "array")
588             return 0;
589
590         var matches = this._description.match(/\[([0-9]+)\]/);
591         if (!matches)
592             return 0;
593
594         return parseInt(matches[1], 10);
595     }
596
597     asCallArgument()
598     {
599         return WI.RemoteObject.createCallArgument(this);
600     }
601
602     findFunctionSourceCodeLocation()
603     {
604         var result = new WI.WrappedPromise;
605
606         if (!this._isFunction() || !this._objectId) {
607             result.resolve(WI.RemoteObject.SourceCodeLocationPromise.MissingObjectId);
608             return result.promise;
609         }
610
611         this._target.DebuggerAgent.getFunctionDetails(this._objectId, (error, response) => {
612             if (error) {
613                 result.resolve(WI.RemoteObject.SourceCodeLocationPromise.NoSourceFound);
614                 return;
615             }
616
617             var location = response.location;
618             var sourceCode = WI.debuggerManager.scriptForIdentifier(location.scriptId, this._target);
619
620             if (!sourceCode || (!WI.isDebugUIEnabled() && isWebKitInternalScript(sourceCode.sourceURL))) {
621                 result.resolve(WI.RemoteObject.SourceCodeLocationPromise.NoSourceFound);
622                 return;
623             }
624
625             var sourceCodeLocation = sourceCode.createSourceCodeLocation(location.lineNumber, location.columnNumber || 0);
626             result.resolve(sourceCodeLocation);
627         });
628
629         return result.promise;
630     }
631
632     // Private
633
634     _isFakeObject()
635     {
636         return this._objectId === WI.RemoteObject.FakeRemoteObjectId;
637     }
638
639     _isSymbol()
640     {
641         return this._type === "symbol";
642     }
643
644     _isFunction()
645     {
646         return this._type === "function";
647     }
648
649     _weakCollectionObjectGroup()
650     {
651         return JSON.stringify(this._objectId) + "-" + this._subtype;
652     }
653
654     getPropertyDescriptorsAsObject(callback, options = {})
655     {
656         this.getPropertyDescriptors(function(properties) {
657             var propertiesResult = {};
658             var internalPropertiesResult = {};
659             for (var propertyDescriptor of properties) {
660                 var object = propertyDescriptor.isInternalProperty ? internalPropertiesResult : propertiesResult;
661                 object[propertyDescriptor.name] = propertyDescriptor;
662             }
663             callback(propertiesResult, internalPropertiesResult);
664         }, options);
665     }
666
667     _getPropertyDescriptorsResolver(callback, error, properties, internalProperties)
668     {
669         if (error) {
670             callback(null);
671             return;
672         }
673
674         let descriptors = properties.map((payload) => {
675             return WI.PropertyDescriptor.fromPayload(payload, false, this._target);
676         });
677
678         if (internalProperties) {
679             descriptors = descriptors.concat(internalProperties.map((payload) => {
680                 return WI.PropertyDescriptor.fromPayload(payload, true, this._target);
681             }));
682         }
683
684         callback(descriptors);
685     }
686
687     // FIXME: Phase out these deprecated functions. They return DeprecatedRemoteObjectProperty instead of PropertyDescriptors.
688     _deprecatedGetProperties(ownProperties, callback)
689     {
690         if (!this._objectId || this._isSymbol() || this._isFakeObject()) {
691             callback([]);
692             return;
693         }
694
695         this._target.RuntimeAgent.getProperties(this._objectId, ownProperties, this._deprecatedGetPropertiesResolver.bind(this, callback));
696     }
697
698     _deprecatedGetPropertiesResolver(callback, error, properties, internalProperties)
699     {
700         if (error) {
701             callback(null);
702             return;
703         }
704
705         if (internalProperties) {
706             properties = properties.concat(internalProperties.map(function(descriptor) {
707                 descriptor.writable = false;
708                 descriptor.configurable = false;
709                 descriptor.enumerable = false;
710                 descriptor.isOwn = true;
711                 return descriptor;
712             }));
713         }
714
715         var result = [];
716         for (var i = 0; properties && i < properties.length; ++i) {
717             var property = properties[i];
718             if (property.get || property.set) {
719                 if (property.get)
720                     result.push(new WI.DeprecatedRemoteObjectProperty("get " + property.name, WI.RemoteObject.fromPayload(property.get, this._target), property));
721                 if (property.set)
722                     result.push(new WI.DeprecatedRemoteObjectProperty("set " + property.name, WI.RemoteObject.fromPayload(property.set, this._target), property));
723             } else
724                 result.push(new WI.DeprecatedRemoteObjectProperty(property.name, WI.RemoteObject.fromPayload(property.value, this._target), property));
725         }
726
727         callback(result);
728     }
729 };
730
731 WI.RemoteObject.FakeRemoteObjectId = "fake-remote-object";
732
733 WI.RemoteObject.SourceCodeLocationPromise = {
734     NoSourceFound: "remote-object-source-code-location-promise-no-source-found",
735     MissingObjectId: "remote-object-source-code-location-promise-missing-object-id"
736 };
737
738 // FIXME: Phase out this deprecated class.
739 WI.DeprecatedRemoteObjectProperty = class DeprecatedRemoteObjectProperty
740 {
741     constructor(name, value, descriptor)
742     {
743         this.name = name;
744         this.value = value;
745         this.enumerable = descriptor ? !!descriptor.enumerable : true;
746         this.writable = descriptor ? !!descriptor.writable : true;
747         if (descriptor && descriptor.wasThrown)
748             this.wasThrown = true;
749     }
750
751     // Static
752
753     fromPrimitiveValue(name, value)
754     {
755         return new WI.DeprecatedRemoteObjectProperty(name, WI.RemoteObject.fromPrimitiveValue(value));
756     }
757 };