import*as Bindings from'../bindings/bindings.js';import*as Common from'../common/common.js';import*as SDK from'../sdk/sdk.js';import*as Workspace from'../workspace/workspace.js';import{FormatterInterface,FormatterSourceMapping}from'./ScriptFormatter.js';export class SourceFormatData{constructor(originalSourceCode,formattedSourceCode,mapping){this.originalSourceCode=originalSourceCode;this.formattedSourceCode=formattedSourceCode;this.mapping=mapping;}
originalPath(){return this.originalSourceCode.project().id()+':'+this.originalSourceCode.url();}
static _for(object){return object[SourceFormatData._formatDataSymbol];}}
SourceFormatData._formatDataSymbol=Symbol('formatData');export class SourceFormatter{constructor(){this._projectId='formatter:';this._project=new Bindings.ContentProviderBasedProject.ContentProviderBasedProject(self.Workspace.workspace,this._projectId,Workspace.Workspace.projectTypes.Formatter,'formatter',true);this._formattedSourceCodes=new Map();this._scriptMapping=new ScriptMapping();this._styleMapping=new StyleMapping();self.Workspace.workspace.addEventListener(Workspace.Workspace.Events.UISourceCodeRemoved,this._onUISourceCodeRemoved,this);}
_onUISourceCodeRemoved(event){const uiSourceCode=(event.data);const cacheEntry=this._formattedSourceCodes.get(uiSourceCode);if(cacheEntry&&cacheEntry.formatData){this._discardFormatData(cacheEntry.formatData);}
this._formattedSourceCodes.remove(uiSourceCode);}
discardFormattedUISourceCode(formattedUISourceCode){const formatData=SourceFormatData._for(formattedUISourceCode);if(!formatData){return null;}
this._discardFormatData(formatData);this._formattedSourceCodes.remove(formatData.originalSourceCode);return formatData.originalSourceCode;}
_discardFormatData(formatData){delete formatData.formattedSourceCode[SourceFormatData._formatDataSymbol];this._scriptMapping._setSourceMappingEnabled(formatData,false);this._styleMapping._setSourceMappingEnabled(formatData,false);this._project.removeFile(formatData.formattedSourceCode.url());}
hasFormatted(uiSourceCode){return this._formattedSourceCodes.has(uiSourceCode);}
getOriginalUISourceCode(uiSourceCode){const formatData=(uiSourceCode[SourceFormatData._formatDataSymbol]);if(!formatData){return uiSourceCode;}
return formatData.originalSourceCode;}
async format(uiSourceCode){const cacheEntry=this._formattedSourceCodes.get(uiSourceCode);if(cacheEntry){return cacheEntry.promise;}
let fulfillFormatPromise;const resultPromise=new Promise(fulfill=>{fulfillFormatPromise=fulfill;});this._formattedSourceCodes.set(uiSourceCode,{promise:resultPromise,formatData:null});const{content}=await uiSourceCode.requestContent();FormatterInterface.format(uiSourceCode.contentType(),uiSourceCode.mimeType(),content||'',formatDone.bind(this));return resultPromise;function formatDone(formattedContent,formatterMapping){const cacheEntry=this._formattedSourceCodes.get(uiSourceCode);if(!cacheEntry||cacheEntry.promise!==resultPromise){return;}
let formattedURL;let count=0;let suffix='';do{formattedURL=`${uiSourceCode.url()}:formatted${suffix}`;suffix=`:${count++}`;}while(this._project.uiSourceCodeForURL(formattedURL));const contentProvider=Common.StaticContentProvider.StaticContentProvider.fromString(formattedURL,uiSourceCode.contentType(),formattedContent);const formattedUISourceCode=this._project.addContentProvider(formattedURL,contentProvider,uiSourceCode.mimeType());const formatData=new SourceFormatData(uiSourceCode,formattedUISourceCode,formatterMapping);formattedUISourceCode[SourceFormatData._formatDataSymbol]=formatData;this._scriptMapping._setSourceMappingEnabled(formatData,true);this._styleMapping._setSourceMappingEnabled(formatData,true);cacheEntry.formatData=formatData;for(const decoration of uiSourceCode.allDecorations()){const range=decoration.range();const startLocation=formatterMapping.originalToFormatted(range.startLine,range.startColumn);const endLocation=formatterMapping.originalToFormatted(range.endLine,range.endColumn);formattedUISourceCode.addDecoration(new TextUtils.TextRange(startLocation[0],startLocation[1],endLocation[0],endLocation[1]),(decoration.type()),decoration.data());}
fulfillFormatPromise(formatData);}}}
class ScriptMapping{constructor(){self.Bindings.debuggerWorkspaceBinding.addSourceMapping(this);}
rawLocationToUILocation(rawLocation){const script=rawLocation.script();const formatData=script&&SourceFormatData._for(script);if(!formatData){return null;}
if(script.isInlineScriptWithSourceURL()){const[relativeLineNumber,relativeColumnNumber]=script.toRelativeLocation(rawLocation);const[formattedLineNumber,formattedColumnNumber]=formatData.mapping.originalToFormatted(relativeLineNumber,relativeColumnNumber);return formatData.formattedSourceCode.uiLocation(formattedLineNumber,formattedColumnNumber);}
const[lineNumber,columnNumber]=formatData.mapping.originalToFormatted(rawLocation.lineNumber,rawLocation.columnNumber||0);return formatData.formattedSourceCode.uiLocation(lineNumber,columnNumber);}
uiLocationToRawLocations(uiSourceCode,lineNumber,columnNumber){const formatData=SourceFormatData._for(uiSourceCode);if(!formatData){return[];}
const[originalLine,originalColumn]=formatData.mapping.formattedToOriginal(lineNumber,columnNumber);if(formatData.originalSourceCode.contentType().isScript()){const rawLocations=self.Bindings.debuggerWorkspaceBinding.uiLocationToRawLocationsForUnformattedJavaScript(formatData.originalSourceCode,originalLine,originalColumn);console.assert(rawLocations.every(l=>l&&!!l.script()));return rawLocations;}
if(formatData.originalSourceCode.contentType()===Common.ResourceType.resourceTypes.Document){const target=Bindings.NetworkProject.NetworkProject.targetForUISourceCode(formatData.originalSourceCode);const debuggerModel=target&&target.model(SDK.DebuggerModel.DebuggerModel);if(debuggerModel){const scripts=debuggerModel.scriptsForSourceURL(formatData.originalSourceCode.url()).filter(script=>script.isInlineScript()&&!script.hasSourceURL);const locations=scripts.map(script=>script.rawLocation(originalLine,originalColumn)).filter(l=>!!l);console.assert(locations.every(l=>l&&!!l.script()));return locations;}}
return[];}
_setSourceMappingEnabled(formatData,enabled){const scripts=this._scriptsForUISourceCode(formatData.originalSourceCode);if(!scripts.length){return;}
if(enabled){for(const script of scripts){script[SourceFormatData._formatDataSymbol]=formatData;}}else{for(const script of scripts){delete script[SourceFormatData._formatDataSymbol];}}
for(const script of scripts){self.Bindings.debuggerWorkspaceBinding.updateLocations(script);}}
_scriptsForUISourceCode(uiSourceCode){if(uiSourceCode.contentType()===Common.ResourceType.resourceTypes.Document){const target=Bindings.NetworkProject.NetworkProject.targetForUISourceCode(uiSourceCode);const debuggerModel=target&&target.model(SDK.DebuggerModel.DebuggerModel);if(debuggerModel){const scripts=debuggerModel.scriptsForSourceURL(uiSourceCode.url()).filter(script=>script.isInlineScript()&&!script.hasSourceURL);return scripts;}}
if(uiSourceCode.contentType().isScript()){console.assert(!uiSourceCode[SourceFormatData._formatDataSymbol]||uiSourceCode[SourceFormatData._formatDataSymbol]===uiSourceCode);const rawLocations=self.Bindings.debuggerWorkspaceBinding.uiLocationToRawLocationsForUnformattedJavaScript(uiSourceCode,0,0);return rawLocations.map(location=>location.script()).filter(script=>!!script);}
return[];}}
class StyleMapping{constructor(){self.Bindings.cssWorkspaceBinding.addSourceMapping(this);this._headersSymbol=Symbol('Formatter.SourceFormatter.StyleMapping._headersSymbol');}
rawLocationToUILocation(rawLocation){const styleHeader=rawLocation.header();const formatData=styleHeader&&SourceFormatData._for(styleHeader);if(!formatData){return null;}
const formattedLocation=formatData.mapping.originalToFormatted(rawLocation.lineNumber,rawLocation.columnNumber||0);return formatData.formattedSourceCode.uiLocation(formattedLocation[0],formattedLocation[1]);}
uiLocationToRawLocations(uiLocation){const formatData=SourceFormatData._for(uiLocation.uiSourceCode);if(!formatData){return[];}
const[originalLine,originalColumn]=formatData.mapping.formattedToOriginal(uiLocation.lineNumber,uiLocation.columnNumber);const headers=formatData.originalSourceCode[this._headersSymbol].filter(header=>header.containsLocation(originalLine,originalColumn));return headers.map(header=>new SDK.CSSModel.CSSLocation(header,originalLine,originalColumn));}
_setSourceMappingEnabled(formatData,enable){const original=formatData.originalSourceCode;const headers=this._headersForUISourceCode(original);if(enable){original[this._headersSymbol]=headers;headers.forEach(header=>header[SourceFormatData._formatDataSymbol]=formatData);}else{original[this._headersSymbol]=null;headers.forEach(header=>delete header[SourceFormatData._formatDataSymbol]);}
headers.forEach(header=>self.Bindings.cssWorkspaceBinding.updateLocations(header));}
_headersForUISourceCode(uiSourceCode){if(uiSourceCode.contentType()===Common.ResourceType.resourceTypes.Document){const target=Bindings.NetworkProject.NetworkProject.targetForUISourceCode(uiSourceCode);const cssModel=target&&target.model(SDK.CSSModel.CSSModel);if(cssModel){return cssModel.headersForSourceURL(uiSourceCode.url()).filter(header=>header.isInline&&!header.hasSourceURL);}}else if(uiSourceCode.contentType().isStyleSheet()){const rawLocations=self.Bindings.cssWorkspaceBinding.uiLocationToRawLocations(uiSourceCode.uiLocation(0,0));return rawLocations.map(rawLocation=>rawLocation.header()).filter(header=>!!header);}
return[];}}