ResourceScriptMapping.js 9.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. export default class ResourceScriptMapping{constructor(debuggerModel,workspace,debuggerWorkspaceBinding){this._debuggerModel=debuggerModel;this._workspace=workspace;this._debuggerWorkspaceBinding=debuggerWorkspaceBinding;this._uiSourceCodeToScriptFile=new Map();this._projects=new Map();this._acceptedScripts=new Set();const runtimeModel=debuggerModel.runtimeModel();this._eventListeners=[this._debuggerModel.addEventListener(SDK.DebuggerModel.Events.ParsedScriptSource,this._parsedScriptSource,this),this._debuggerModel.addEventListener(SDK.DebuggerModel.Events.GlobalObjectCleared,this._globalObjectCleared,this),runtimeModel.addEventListener(SDK.RuntimeModel.Events.ExecutionContextDestroyed,this._executionContextDestroyed,this),];}
  2. _project(script){const frameId=script[_frameIdSymbol];const prefix=script.isContentScript()?'js:extensions:':'js::';const projectId=prefix+this._debuggerModel.target().id()+':'+frameId;let project=this._projects.get(projectId);if(!project){const projectType=script.isContentScript()?Workspace.projectTypes.ContentScripts:Workspace.projectTypes.Network;project=new Bindings.ContentProviderBasedProject(this._workspace,projectId,projectType,'',false);Bindings.NetworkProject.setTargetForProject(project,this._debuggerModel.target());this._projects.set(projectId,project);}
  3. return project;}
  4. rawLocationToUILocation(rawLocation){const script=rawLocation.script();if(!script){return null;}
  5. const project=this._project(script);const uiSourceCode=project.uiSourceCodeForURL(script.sourceURL);if(!uiSourceCode){return null;}
  6. const scriptFile=this._uiSourceCodeToScriptFile.get(uiSourceCode);if(!scriptFile){return null;}
  7. if((scriptFile.hasDivergedFromVM()&&!scriptFile.isMergingToVM())||scriptFile.isDivergingFromVM()){return null;}
  8. if(!scriptFile._hasScripts([script])){return null;}
  9. const lineNumber=rawLocation.lineNumber-(script.isInlineScriptWithSourceURL()?script.lineOffset:0);let columnNumber=rawLocation.columnNumber||0;if(script.isInlineScriptWithSourceURL()&&!lineNumber&&columnNumber){columnNumber-=script.columnOffset;}
  10. return uiSourceCode.uiLocation(lineNumber,columnNumber);}
  11. uiLocationToRawLocations(uiSourceCode,lineNumber,columnNumber){const scriptFile=this._uiSourceCodeToScriptFile.get(uiSourceCode);if(!scriptFile){return[];}
  12. const script=scriptFile._script;if(script.isInlineScriptWithSourceURL()){return[this._debuggerModel.createRawLocation(script,lineNumber+script.lineOffset,lineNumber?columnNumber:columnNumber+script.columnOffset)];}
  13. return[this._debuggerModel.createRawLocation(script,lineNumber,columnNumber)];}
  14. _acceptsScript(script){if(!script.sourceURL||script.isLiveEdit()||(script.isInlineScript()&&!script.hasSourceURL)){return false;}
  15. if(script.isContentScript()&&!script.hasSourceURL){const parsedURL=new Common.ParsedURL(script.sourceURL);if(!parsedURL.isValid){return false;}}
  16. return true;}
  17. _parsedScriptSource(event){const script=(event.data);if(!this._acceptsScript(script)){return;}
  18. this._acceptedScripts.add(script);const originalContentProvider=script.originalContentProvider();const frameId=Bindings.frameIdForScript(script);script[_frameIdSymbol]=frameId;const url=script.sourceURL;const project=this._project(script);const oldUISourceCode=project.uiSourceCodeForURL(url);if(oldUISourceCode){const scriptFile=this._uiSourceCodeToScriptFile.get(oldUISourceCode);this._removeScript(scriptFile._script);}
  19. const uiSourceCode=project.createUISourceCode(url,originalContentProvider.contentType());Bindings.NetworkProject.setInitialFrameAttribution(uiSourceCode,frameId);const metadata=Bindings.metadataForURL(this._debuggerModel.target(),frameId,url);const scriptFile=new ResourceScriptFile(this,uiSourceCode,[script]);this._uiSourceCodeToScriptFile.set(uiSourceCode,scriptFile);project.addUISourceCodeWithProvider(uiSourceCode,originalContentProvider,metadata,'text/javascript');this._debuggerWorkspaceBinding.updateLocations(script);}
  20. scriptFile(uiSourceCode){return this._uiSourceCodeToScriptFile.get(uiSourceCode)||null;}
  21. _removeScript(script){if(!this._acceptedScripts.has(script)){return;}
  22. this._acceptedScripts.delete(script);const project=this._project(script);const uiSourceCode=(project.uiSourceCodeForURL(script.sourceURL));const scriptFile=this._uiSourceCodeToScriptFile.get(uiSourceCode);scriptFile.dispose();this._uiSourceCodeToScriptFile.delete(uiSourceCode);project.removeFile(script.sourceURL);this._debuggerWorkspaceBinding.updateLocations(script);}
  23. _executionContextDestroyed(event){const executionContext=(event.data);const scripts=this._debuggerModel.scriptsForExecutionContext(executionContext);for(const script of scripts){this._removeScript(script);}}
  24. _globalObjectCleared(event){const scripts=Array.from(this._acceptedScripts);for(const script of scripts){this._removeScript(script);}}
  25. resetForTest(){const scripts=Array.from(this._acceptedScripts);for(const script of scripts){this._removeScript(script);}}
  26. dispose(){Common.EventTarget.removeEventListeners(this._eventListeners);const scripts=Array.from(this._acceptedScripts);for(const script of scripts){this._removeScript(script);}
  27. for(const project of this._projects.values()){project.removeProject();}
  28. this._projects.clear();}}
  29. export class ResourceScriptFile extends Common.Object{constructor(resourceScriptMapping,uiSourceCode,scripts){super();console.assert(scripts.length);this._resourceScriptMapping=resourceScriptMapping;this._uiSourceCode=uiSourceCode;if(this._uiSourceCode.contentType().isScript()){this._script=scripts[scripts.length-1];}
  30. this._uiSourceCode.addEventListener(Workspace.UISourceCode.Events.WorkingCopyChanged,this._workingCopyChanged,this);this._uiSourceCode.addEventListener(Workspace.UISourceCode.Events.WorkingCopyCommitted,this._workingCopyCommitted,this);}
  31. _hasScripts(scripts){return this._script&&this._script===scripts[0];}
  32. _isDiverged(){if(this._uiSourceCode.isDirty()){return true;}
  33. if(!this._script){return false;}
  34. if(typeof this._scriptSource==='undefined'){return false;}
  35. const workingCopy=this._uiSourceCode.workingCopy();if(!workingCopy){return false;}
  36. if(!workingCopy.startsWith(this._scriptSource.trimRight())){return true;}
  37. const suffix=this._uiSourceCode.workingCopy().substr(this._scriptSource.length);return!!suffix.length&&!suffix.match(SDK.Script.sourceURLRegex);}
  38. _workingCopyChanged(event){this._update();}
  39. _workingCopyCommitted(event){if(this._uiSourceCode.project().canSetFileContent()){return;}
  40. if(!this._script){return;}
  41. const debuggerModel=this._resourceScriptMapping._debuggerModel;const breakpoints=Bindings.breakpointManager.breakpointLocationsForUISourceCode(this._uiSourceCode).map(breakpointLocation=>breakpointLocation.breakpoint);const source=this._uiSourceCode.workingCopy();debuggerModel.setScriptSource(this._script.scriptId,source,scriptSourceWasSet.bind(this));async function scriptSourceWasSet(error,exceptionDetails){if(!error&&!exceptionDetails){this._scriptSource=source;}
  42. this._update();if(!error&&!exceptionDetails){breakpoints.map(breakpoint=>breakpoint.refreshInDebugger());return;}
  43. if(!exceptionDetails){Common.console.addMessage(Common.UIString('LiveEdit failed: %s',error),Common.Console.MessageLevel.Warning);return;}
  44. const messageText=Common.UIString('LiveEdit compile failed: %s',exceptionDetails.text);this._uiSourceCode.addLineMessage(Workspace.UISourceCode.Message.Level.Error,messageText,exceptionDetails.lineNumber,exceptionDetails.columnNumber);}}
  45. _update(){if(this._isDiverged()&&!this._hasDivergedFromVM){this._divergeFromVM();}else if(!this._isDiverged()&&this._hasDivergedFromVM){this._mergeToVM();}}
  46. _divergeFromVM(){this._isDivergingFromVM=true;this._resourceScriptMapping._debuggerWorkspaceBinding.updateLocations(this._script);delete this._isDivergingFromVM;this._hasDivergedFromVM=true;this.dispatchEventToListeners(ResourceScriptFile.Events.DidDivergeFromVM,this._uiSourceCode);}
  47. _mergeToVM(){delete this._hasDivergedFromVM;this._isMergingToVM=true;this._resourceScriptMapping._debuggerWorkspaceBinding.updateLocations(this._script);delete this._isMergingToVM;this.dispatchEventToListeners(ResourceScriptFile.Events.DidMergeToVM,this._uiSourceCode);}
  48. hasDivergedFromVM(){return this._hasDivergedFromVM;}
  49. isDivergingFromVM(){return this._isDivergingFromVM;}
  50. isMergingToVM(){return this._isMergingToVM;}
  51. checkMapping(){if(!this._script||typeof this._scriptSource!=='undefined'){this._mappingCheckedForTest();return;}
  52. this._script.requestContent().then(deferredContent=>{this._scriptSource=deferredContent.content;this._update();this._mappingCheckedForTest();});}
  53. _mappingCheckedForTest(){}
  54. dispose(){this._uiSourceCode.removeEventListener(Workspace.UISourceCode.Events.WorkingCopyChanged,this._workingCopyChanged,this);this._uiSourceCode.removeEventListener(Workspace.UISourceCode.Events.WorkingCopyCommitted,this._workingCopyCommitted,this);}
  55. addSourceMapURL(sourceMapURL){if(!this._script){return;}
  56. this._script.debuggerModel.setSourceMapURL(this._script,sourceMapURL);}
  57. hasSourceMapURL(){return this._script&&!!this._script.sourceMapURL;}}
  58. const _frameIdSymbol=Symbol('frameid');ResourceScriptFile.Events={DidMergeToVM:Symbol('DidMergeToVM'),DidDivergeFromVM:Symbol('DidDivergeFromVM'),};self.Bindings=self.Bindings||{};Bindings=Bindings||{};Bindings.ResourceScriptMapping=ResourceScriptMapping;Bindings.ResourceScriptFile=ResourceScriptFile;