RemoteObject.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. export default class RemoteObject{static fromLocalObject(value){return new LocalJSONObject(value);}
  2. static type(remoteObject){if(remoteObject===null){return'null';}
  3. const type=typeof remoteObject;if(type!=='object'&&type!=='function'){return type;}
  4. return remoteObject.type;}
  5. static arrayNameFromDescription(description){return description.replace(_descriptionLengthParenRegex,'').replace(_descriptionLengthSquareRegex,'');}
  6. static arrayLength(object){if(object.subtype!=='array'&&object.subtype!=='typedarray'){return 0;}
  7. const parenMatches=object.description.match(_descriptionLengthParenRegex);const squareMatches=object.description.match(_descriptionLengthSquareRegex);return parenMatches?parseInt(parenMatches[1],10):(squareMatches?parseInt(squareMatches[1],10):0);}
  8. static unserializableDescription(object){const type=typeof object;if(type==='number'){const description=String(object);if(object===0&&1/object<0){return UnserializableNumber.Negative0;}
  9. if(description===UnserializableNumber.NaN||description===UnserializableNumber.Infinity||description===UnserializableNumber.NegativeInfinity){return description;}}
  10. if(type==='bigint'){return object+'n';}
  11. return null;}
  12. static toCallArgument(object){const type=typeof object;if(type==='undefined'){return{};}
  13. const unserializableDescription=RemoteObject.unserializableDescription(object);if(type==='number'){if(unserializableDescription!==null){return{unserializableValue:unserializableDescription};}
  14. return{value:object};}
  15. if(type==='bigint'){return{unserializableValue:(unserializableDescription)};}
  16. if(type==='string'||type==='boolean'){return{value:object};}
  17. if(!object){return{value:null};}
  18. if(object instanceof RemoteObject){const unserializableValue=object.unserializableValue();if(unserializableValue!==undefined){return{unserializableValue:unserializableValue};}}else if(object.unserializableValue!==undefined){return{unserializableValue:object.unserializableValue};}
  19. if(typeof object.objectId!=='undefined'){return{objectId:object.objectId};}
  20. return{value:object.value};}
  21. static async loadFromObjectPerProto(object,generatePreview){const result=await Promise.all([object.getAllProperties(true,generatePreview),object.getOwnProperties(generatePreview)]);const accessorProperties=result[0].properties;const ownProperties=result[1].properties;const internalProperties=result[1].internalProperties;if(!ownProperties||!accessorProperties){return({properties:null,internalProperties:null});}
  22. const propertiesMap=new Map();const propertySymbols=[];for(let i=0;i<accessorProperties.length;i++){const property=accessorProperties[i];if(property.symbol){propertySymbols.push(property);}else{propertiesMap.set(property.name,property);}}
  23. for(let i=0;i<ownProperties.length;i++){const property=ownProperties[i];if(property.isAccessorProperty()){continue;}
  24. if(property.symbol){propertySymbols.push(property);}else{propertiesMap.set(property.name,property);}}
  25. return{properties:propertiesMap.valuesArray().concat(propertySymbols),internalProperties:internalProperties?internalProperties:null};}
  26. customPreview(){return null;}
  27. get objectId(){return'Not implemented';}
  28. get type(){throw'Not implemented';}
  29. get subtype(){throw'Not implemented';}
  30. get value(){throw'Not implemented';}
  31. unserializableValue(){throw'Not implemented';}
  32. get description(){throw'Not implemented';}
  33. get hasChildren(){throw'Not implemented';}
  34. get preview(){return undefined;}
  35. get className(){return null;}
  36. arrayLength(){throw'Not implemented';}
  37. getOwnProperties(generatePreview){throw'Not implemented';}
  38. getAllProperties(accessorPropertiesOnly,generatePreview){throw'Not implemented';}
  39. async deleteProperty(name){throw'Not implemented';}
  40. async setPropertyValue(name,value){throw'Not implemented';}
  41. callFunction(functionDeclaration,args){throw'Not implemented';}
  42. callFunctionJSON(functionDeclaration,args){throw'Not implemented';}
  43. release(){}
  44. debuggerModel(){throw new Error('DebuggerModel-less object');}
  45. runtimeModel(){throw new Error('RuntimeModel-less object');}
  46. isNode(){return false;}}
  47. export class RemoteObjectImpl extends RemoteObject{constructor(runtimeModel,objectId,type,subtype,value,unserializableValue,description,preview,customPreview,className){super();this._runtimeModel=runtimeModel;this._runtimeAgent=runtimeModel.target().runtimeAgent();this._type=type;this._subtype=subtype;if(objectId){this._objectId=objectId;this._description=description;this._hasChildren=(type!=='symbol');this._preview=preview;}else{this._description=description;if(!this.description&&unserializableValue){this._description=unserializableValue;}
  48. if(!this._description&&(typeof value!=='object'||value===null)){this._description=value+'';}
  49. this._hasChildren=false;if(typeof unserializableValue==='string'){this._unserializableValue=unserializableValue;if(unserializableValue===UnserializableNumber.Infinity||unserializableValue===UnserializableNumber.NegativeInfinity||unserializableValue===UnserializableNumber.Negative0||unserializableValue===UnserializableNumber.NaN){this._value=Number(unserializableValue);}else if(type==='bigint'&&unserializableValue.endsWith('n')){this._value=BigInt(unserializableValue.substring(0,unserializableValue.length-1));}else{this._value=unserializableValue;}}else{this._value=value;}}
  50. this._customPreview=customPreview||null;this._className=typeof className==='string'?className:null;}
  51. customPreview(){return this._customPreview;}
  52. get objectId(){return this._objectId;}
  53. get type(){return this._type;}
  54. get subtype(){return this._subtype;}
  55. get value(){return this._value;}
  56. unserializableValue(){return this._unserializableValue;}
  57. get description(){return this._description;}
  58. get hasChildren(){return this._hasChildren;}
  59. get preview(){return this._preview;}
  60. get className(){return this._className;}
  61. getOwnProperties(generatePreview){return this.doGetProperties(true,false,generatePreview);}
  62. getAllProperties(accessorPropertiesOnly,generatePreview){return this.doGetProperties(false,accessorPropertiesOnly,generatePreview);}
  63. async doGetProperties(ownProperties,accessorPropertiesOnly,generatePreview){if(!this._objectId){return({properties:null,internalProperties:null});}
  64. const response=await this._runtimeAgent.invoke_getProperties({objectId:this._objectId,ownProperties,accessorPropertiesOnly,generatePreview});if(response[Protocol.Error]){return({properties:null,internalProperties:null});}
  65. if(response.exceptionDetails){this._runtimeModel.exceptionThrown(Date.now(),response.exceptionDetails);return({properties:null,internalProperties:null});}
  66. const{result:properties=[],internalProperties=[],privateProperties=[]}=response;const result=[];for(const property of properties){const propertyValue=property.value?this._runtimeModel.createRemoteObject(property.value):null;const propertySymbol=property.symbol?this._runtimeModel.createRemoteObject(property.symbol):null;const remoteProperty=new RemoteObjectProperty(property.name,propertyValue,!!property.enumerable,!!property.writable,!!property.isOwn,!!property.wasThrown,propertySymbol);if(typeof property.value==='undefined'){if(property.get&&property.get.type!=='undefined'){remoteProperty.getter=this._runtimeModel.createRemoteObject(property.get);}
  67. if(property.set&&property.set.type!=='undefined'){remoteProperty.setter=this._runtimeModel.createRemoteObject(property.set);}}
  68. result.push(remoteProperty);}
  69. for(const property of privateProperties){const propertyValue=this._runtimeModel.createRemoteObject(property.value);const remoteProperty=new RemoteObjectProperty(property.name,propertyValue,true,true,true,false,undefined,false,undefined,true);result.push(remoteProperty);}
  70. const internalPropertiesResult=[];for(const property of internalProperties){if(!property.value){continue;}
  71. if(property.name==='[[StableObjectId]]'){continue;}
  72. const propertyValue=this._runtimeModel.createRemoteObject(property.value);internalPropertiesResult.push(new RemoteObjectProperty(property.name,propertyValue,true,false,undefined,undefined,undefined,true));}
  73. return{properties:result,internalProperties:internalPropertiesResult};}
  74. async setPropertyValue(name,value){if(!this._objectId){return`Can't set a property of non-object.`;}
  75. const response=await this._runtimeAgent.invoke_evaluate({expression:value,silent:true});if(response[Protocol.Error]||response.exceptionDetails){return response[Protocol.Error]||(response.result.type!=='string'?response.result.description:(response.result.value));}
  76. if(typeof name==='string'){name=RemoteObject.toCallArgument(name);}
  77. const resultPromise=this.doSetObjectPropertyValue(response.result,name);if(response.result.objectId){this._runtimeAgent.releaseObject(response.result.objectId);}
  78. return resultPromise;}
  79. async doSetObjectPropertyValue(result,name){const setPropertyValueFunction='function(a, b) { this[a] = b; }';const argv=[name,RemoteObject.toCallArgument(result)];const response=await this._runtimeAgent.invoke_callFunctionOn({objectId:this._objectId,functionDeclaration:setPropertyValueFunction,arguments:argv,silent:true});const error=response[Protocol.Error];return error||response.exceptionDetails?error||response.result.description:undefined;}
  80. async deleteProperty(name){if(!this._objectId){return`Can't delete a property of non-object.`;}
  81. const deletePropertyFunction='function(a) { delete this[a]; return !(a in this); }';const response=await this._runtimeAgent.invoke_callFunctionOn({objectId:this._objectId,functionDeclaration:deletePropertyFunction,arguments:[name],silent:true});if(response[Protocol.Error]||response.exceptionDetails){return response[Protocol.Error]||response.result.description;}
  82. if(!response.result.value){return'Failed to delete property.';}}
  83. async callFunction(functionDeclaration,args){const response=await this._runtimeAgent.invoke_callFunctionOn({objectId:this._objectId,functionDeclaration:functionDeclaration.toString(),arguments:args,silent:true});if(response[Protocol.Error]){return{object:null,wasThrown:false};}
  84. return{object:this._runtimeModel.createRemoteObject(response.result),wasThrown:!!response.exceptionDetails};}
  85. async callFunctionJSON(functionDeclaration,args){const response=await this._runtimeAgent.invoke_callFunctionOn({objectId:this._objectId,functionDeclaration:functionDeclaration.toString(),arguments:args,silent:true,returnByValue:true});return response[Protocol.Error]||response.exceptionDetails?null:response.result.value;}
  86. release(){if(!this._objectId){return;}
  87. this._runtimeAgent.releaseObject(this._objectId);}
  88. arrayLength(){return RemoteObject.arrayLength(this);}
  89. debuggerModel(){return this._runtimeModel.debuggerModel();}
  90. runtimeModel(){return this._runtimeModel;}
  91. isNode(){return!!this._objectId&&this.type==='object'&&this.subtype==='node';}}
  92. export class ScopeRemoteObject extends RemoteObjectImpl{constructor(runtimeModel,objectId,scopeRef,type,subtype,value,unserializableValue,description,preview){super(runtimeModel,objectId,type,subtype,value,unserializableValue,description,preview);this._scopeRef=scopeRef;this._savedScopeProperties=undefined;}
  93. async doGetProperties(ownProperties,accessorPropertiesOnly,generatePreview){if(accessorPropertiesOnly){return({properties:[],internalProperties:[]});}
  94. if(this._savedScopeProperties){return{properties:this._savedScopeProperties.slice(),internalProperties:null};}
  95. const allProperties=await super.doGetProperties(ownProperties,accessorPropertiesOnly,true);if(this._scopeRef&&Array.isArray(allProperties.properties)){this._savedScopeProperties=allProperties.properties.slice();if(!this._scopeRef.callFrameId){for(const property of this._savedScopeProperties){property.writable=false;}}}
  96. return allProperties;}
  97. async doSetObjectPropertyValue(result,argumentName){const name=(argumentName.value);const error=await this.debuggerModel().setVariableValue(this._scopeRef.number,name,RemoteObject.toCallArgument(result),this._scopeRef.callFrameId);if(error){return error;}
  98. if(this._savedScopeProperties){for(const property of this._savedScopeProperties){if(property.name===name){property.value=this._runtimeModel.createRemoteObject(result);}}}}}
  99. export class ScopeRef{constructor(number,callFrameId){this.number=number;this.callFrameId=callFrameId;}}
  100. export class RemoteObjectProperty{constructor(name,value,enumerable,writable,isOwn,wasThrown,symbol,synthetic,syntheticSetter,isPrivate){this.name=name;if(value!==null){this.value=value;}
  101. this.enumerable=typeof enumerable!=='undefined'?enumerable:true;const isNonSyntheticOrSyntheticWritable=!synthetic||!!syntheticSetter;this.writable=typeof writable!=='undefined'?writable:isNonSyntheticOrSyntheticWritable;this.isOwn=!!isOwn;this.wasThrown=!!wasThrown;if(symbol){this.symbol=symbol;}
  102. this.synthetic=!!synthetic;if(syntheticSetter){this.syntheticSetter=syntheticSetter;}
  103. this.private=!!isPrivate;}
  104. async setSyntheticValue(expression){if(!this.syntheticSetter){return false;}
  105. const result=await this.syntheticSetter(expression);if(result){this.value=result;}
  106. return!!result;}
  107. isAccessorProperty(){return!!(this.getter||this.setter);}}
  108. export class LocalJSONObject extends RemoteObject{constructor(value){super();this._value=value;this._cachedDescription;this._cachedChildren;}
  109. get objectId(){return undefined;}
  110. get value(){return this._value;}
  111. unserializableValue(){const unserializableDescription=RemoteObject.unserializableDescription(this._value);return unserializableDescription||undefined;}
  112. get description(){if(this._cachedDescription){return this._cachedDescription;}
  113. function formatArrayItem(property){return this._formatValue(property.value);}
  114. function formatObjectItem(property){let name=property.name;if(/^\s|\s$|^$|\n/.test(name)){name='"'+name.replace(/\n/g,'\u21B5')+'"';}
  115. return name+': '+this._formatValue(property.value);}
  116. if(this.type==='object'){switch(this.subtype){case'array':this._cachedDescription=this._concatenate('[',']',formatArrayItem.bind(this));break;case'date':this._cachedDescription=''+this._value;break;case'null':this._cachedDescription='null';break;default:this._cachedDescription=this._concatenate('{','}',formatObjectItem.bind(this));}}else{this._cachedDescription=String(this._value);}
  117. return this._cachedDescription;}
  118. _formatValue(value){if(!value){return'undefined';}
  119. const description=value.description||'';if(value.type==='string'){return'"'+description.replace(/\n/g,'\u21B5')+'"';}
  120. return description;}
  121. _concatenate(prefix,suffix,formatProperty){const previewChars=100;let buffer=prefix;const children=this._children();for(let i=0;i<children.length;++i){const itemDescription=formatProperty(children[i]);if(buffer.length+itemDescription.length>previewChars){buffer+=',\u2026';break;}
  122. if(i){buffer+=', ';}
  123. buffer+=itemDescription;}
  124. buffer+=suffix;return buffer;}
  125. get type(){return typeof this._value;}
  126. get subtype(){if(this._value===null){return'null';}
  127. if(Array.isArray(this._value)){return'array';}
  128. if(this._value instanceof Date){return'date';}
  129. return undefined;}
  130. get hasChildren(){if((typeof this._value!=='object')||(this._value===null)){return false;}
  131. return!!Object.keys((this._value)).length;}
  132. getOwnProperties(generatePreview){return Promise.resolve(({properties:this._children(),internalProperties:null}));}
  133. getAllProperties(accessorPropertiesOnly,generatePreview){if(accessorPropertiesOnly){return Promise.resolve(({properties:[],internalProperties:null}));}else{return Promise.resolve(({properties:this._children(),internalProperties:null}));}}
  134. _children(){if(!this.hasChildren){return[];}
  135. const value=(this._value);function buildProperty(propName){let propValue=value[propName];if(!(propValue instanceof RemoteObject)){propValue=RemoteObject.fromLocalObject(propValue);}
  136. return new RemoteObjectProperty(propName,propValue);}
  137. if(!this._cachedChildren){this._cachedChildren=Object.keys(value).map(buildProperty);}
  138. return this._cachedChildren;}
  139. arrayLength(){return Array.isArray(this._value)?this._value.length:0;}
  140. callFunction(functionDeclaration,args){const target=(this._value);const rawArgs=args?args.map(arg=>arg.value):[];let result;let wasThrown=false;try{result=functionDeclaration.apply(target,rawArgs);}catch(e){wasThrown=true;}
  141. const object=RemoteObject.fromLocalObject(result);return Promise.resolve(({object,wasThrown}));}
  142. callFunctionJSON(functionDeclaration,args){const target=(this._value);const rawArgs=args?args.map(arg=>arg.value):[];let result;try{result=functionDeclaration.apply(target,rawArgs);}catch(e){result=null;}
  143. return Promise.resolve(result);}}
  144. export class RemoteArray{constructor(object){this._object=object;}
  145. static objectAsArray(object){if(!object||object.type!=='object'||(object.subtype!=='array'&&object.subtype!=='typedarray')){throw new Error('Object is empty or not an array');}
  146. return new RemoteArray(object);}
  147. static createFromRemoteObjects(objects){if(!objects.length){throw new Error('Input array is empty');}
  148. const objectArguments=[];for(let i=0;i<objects.length;++i){objectArguments.push(RemoteObject.toCallArgument(objects[i]));}
  149. return objects[0].callFunction(createArray,objectArguments).then(returnRemoteArray);function createArray(){if(arguments.length>1){return new Array(arguments);}
  150. return[arguments[0]];}
  151. function returnRemoteArray(result){if(result.wasThrown||!result.object){throw new Error('Call function throws exceptions or returns empty value');}
  152. return RemoteArray.objectAsArray(result.object);}}
  153. at(index){if(index<0||index>this._object.arrayLength()){throw new Error('Out of range');}
  154. return this._object.callFunction(at,[RemoteObject.toCallArgument(index)]).then(assertCallFunctionResult);function at(index){return this[index];}
  155. function assertCallFunctionResult(result){if(result.wasThrown||!result.object){throw new Error('Exception in callFunction or result value is empty');}
  156. return result.object;}}
  157. length(){return this._object.arrayLength();}
  158. map(func){const promises=[];for(let i=0;i<this.length();++i){promises.push(this.at(i).then(func));}
  159. return Promise.all(promises);}
  160. object(){return this._object;}}
  161. export class RemoteFunction{constructor(object){this._object=object;}
  162. static objectAsFunction(object){if(!object||object.type!=='function'){throw new Error('Object is empty or not a function');}
  163. return new RemoteFunction(object);}
  164. targetFunction(){return this._object.getOwnProperties(false).then(targetFunction.bind(this));function targetFunction(ownProperties){if(!ownProperties.internalProperties){return this._object;}
  165. const internalProperties=ownProperties.internalProperties;for(const property of internalProperties){if(property.name==='[[TargetFunction]]'){return property.value;}}
  166. return this._object;}}
  167. targetFunctionDetails(){return this.targetFunction().then(functionDetails.bind(this));function functionDetails(targetFunction){const boundReleaseFunctionDetails=releaseTargetFunction.bind(null,this._object!==targetFunction?targetFunction:null);return targetFunction.debuggerModel().functionDetailsPromise(targetFunction).then(boundReleaseFunctionDetails);}
  168. function releaseTargetFunction(targetFunction,functionDetails){if(targetFunction){targetFunction.release();}
  169. return functionDetails;}}
  170. object(){return this._object;}}
  171. const _descriptionLengthParenRegex=/\(([0-9]+)\)/;const _descriptionLengthSquareRegex=/\[([0-9]+)\]/;const UnserializableNumber={Negative0:('-0'),NaN:('NaN'),Infinity:('Infinity'),NegativeInfinity:('-Infinity')};self.SDK=self.SDK||{};SDK=SDK||{};SDK.RemoteObject=RemoteObject;SDK.RemoteObjectImpl=RemoteObjectImpl;SDK.ScopeRemoteObject=ScopeRemoteObject;SDK.ScopeRef=ScopeRef;SDK.RemoteObjectProperty=RemoteObjectProperty;SDK.LocalJSONObject=LocalJSONObject;SDK.RemoteArray=RemoteArray;SDK.RemoteFunction=RemoteFunction;SDK.CallFunctionResult;SDK.GetPropertiesResult;