import{Worker,Settings,ResourceType}from'../common/common.js';import{StringUtilities}from'../platform/platform.js';import{ContentProviderBasedProject,DebuggerWorkspaceBinding,NetworkProject,CSSWorkspaceBinding}from'../bindings/bindings.js';import{DebuggerModel,CSSModel}from'../sdk/sdk.js';import{StaticContentProvider,TextRange as TextRange$1}from'../text_utils/text_utils.js';import{Workspace}from'../workspace/workspace.js';const MaxWorkers=2;class FormatterWorkerPool{constructor(){this._taskQueue=[];this._workerTasks=new Map();}
_createWorker(){const worker=new Worker.WorkerWrapper('formatter_worker_entrypoint');worker.onmessage=this._onWorkerMessage.bind(this,worker);worker.onerror=this._onWorkerError.bind(this,worker);return worker;}
_processNextTask(){if(!this._taskQueue.length){return;}
let freeWorker=[...this._workerTasks.keys()].find(worker=>!this._workerTasks.get(worker));if(!freeWorker&&this._workerTasks.size<MaxWorkers){freeWorker=this._createWorker();}
if(!freeWorker){return;}
const task=this._taskQueue.shift();this._workerTasks.set(freeWorker,task);freeWorker.postMessage({method:task.method,params:task.params});}
_onWorkerMessage(worker,event){const task=this._workerTasks.get(worker);if(task.isChunked&&event.data&&!event.data['isLastChunk']){task.callback(event.data);return;}
this._workerTasks.set(worker,null);this._processNextTask();task.callback(event.data?event.data:null);}
_onWorkerError(worker,event){console.error(event);const task=this._workerTasks.get(worker);worker.terminate();this._workerTasks.delete(worker);const newWorker=this._createWorker();this._workerTasks.set(newWorker,null);this._processNextTask();task.callback(null);}
_runChunkedTask(methodName,params,callback){const task=new Task(methodName,params,onData,true);this._taskQueue.push(task);this._processNextTask();function onData(data){if(!data){callback(true,null);return;}
const isLastChunk=!!data['isLastChunk'];const chunk=data['chunk'];callback(isLastChunk,chunk);}}
_runTask(methodName,params){let callback;const promise=new Promise(fulfill=>callback=fulfill);const task=new Task(methodName,params,callback,false);this._taskQueue.push(task);this._processNextTask();return promise;}
parseJSONRelaxed(content){return this._runTask('parseJSONRelaxed',{content:content});}
parseSCSS(content){return this._runTask('parseSCSS',{content:content}).then(rules=>rules||[]);}
format(mimeType,content,indentString){const parameters={mimeType:mimeType,content:content,indentString:indentString};return(this._runTask('format',parameters));}
javaScriptIdentifiers(content){return this._runTask('javaScriptIdentifiers',{content:content}).then(ids=>ids||[]);}
evaluatableJavaScriptSubstring(content){return this._runTask('evaluatableJavaScriptSubstring',{content:content}).then(text=>text||'');}
parseCSS(content,callback){this._runChunkedTask('parseCSS',{content:content},onDataChunk);function onDataChunk(isLastChunk,data){const rules=(data||[]);callback(isLastChunk,rules);}}
javaScriptOutline(content,callback){this._runChunkedTask('javaScriptOutline',{content:content},onDataChunk);function onDataChunk(isLastChunk,data){const items=(data||[]);callback(isLastChunk,items);}}
outlineForMimetype(content,mimeType,callback){switch(mimeType){case'text/html':case'text/javascript':this.javaScriptOutline(content,javaScriptCallback);return true;case'text/css':this.parseCSS(content,cssCallback);return true;}
return false;function javaScriptCallback(isLastChunk,items){callback(isLastChunk,items.map(item=>({line:item.line,column:item.column,title:item.name,subtitle:item.arguments})));}
function cssCallback(isLastChunk,rules){callback(isLastChunk,rules.map(rule=>({line:rule.lineNumber,column:rule.columnNumber,title:rule.selectorText||rule.atRule})));}}
findLastExpression(content){return(this._runTask('findLastExpression',{content}));}
findLastFunctionCall(content){return(this._runTask('findLastFunctionCall',{content}));}
argumentsList(content){return(this._runTask('argumentsList',{content}));}}
class Task{constructor(method,params,callback,isChunked){this.method=method;this.params=params;this.callback=callback;this.isChunked=isChunked;}}
class FormatResult{constructor(){this.content;this.mapping;}}
class JSOutlineItem{constructor(){this.name;this.arguments;this.line;this.column;}}
class CSSProperty{constructor(){this.name;this.nameRange;this.value;this.valueRange;this.range;this.disabled;}}
class CSSStyleRule{constructor(){this.selectorText;this.styleRange;this.lineNumber;this.columnNumber;this.properties;}}
class SCSSProperty{constructor(){this.range;this.name;this.value;this.disabled;}}
class SCSSRule{constructor(){this.selectors;this.properties;this.styleRange;}}
function formatterWorkerPool(){if(!Formatter._formatterWorkerPool){Formatter._formatterWorkerPool=new FormatterWorkerPool();}
return Formatter._formatterWorkerPool;}
let OutlineItem;let FormatMapping;let CSSAtRule;let CSSRule;let TextRange;var FormatterWorkerPool$1=Object.freeze({__proto__:null,FormatterWorkerPool:FormatterWorkerPool,FormatResult:FormatResult,formatterWorkerPool:formatterWorkerPool,OutlineItem:OutlineItem,FormatMapping:FormatMapping,CSSAtRule:CSSAtRule,CSSRule:CSSRule,TextRange:TextRange});class FormatterInterface{}
FormatterInterface.format=function(contentType,mimeType,content,callback){if(contentType.isDocumentOrScriptOrStyleSheet()){new ScriptFormatter(mimeType,content,callback);}else{new ScriptIdentityFormatter(mimeType,content,callback);}};FormatterInterface.locationToPosition=function(lineEndings,lineNumber,columnNumber){const position=lineNumber?lineEndings[lineNumber-1]+1:0;return position+columnNumber;};FormatterInterface.positionToLocation=function(lineEndings,position){const lineNumber=lineEndings.upperBound(position-1);let columnNumber;if(!lineNumber){columnNumber=position;}else{columnNumber=position-lineEndings[lineNumber-1]-1;}
return[lineNumber,columnNumber];};class ScriptFormatter{constructor(mimeType,content,callback){content=content.replace(/\r\n?|[\n\u2028\u2029]/g,'\n').replace(/^\uFEFF/,'');this._callback=callback;this._originalContent=content;formatterWorkerPool().format(mimeType,content,Settings.Settings.instance().moduleSetting('textEditorIndent').get()).then(this._didFormatContent.bind(this));}
_didFormatContent(formatResult){const originalContentLineEndings=StringUtilities.findLineEndingIndexes(this._originalContent);const formattedContentLineEndings=StringUtilities.findLineEndingIndexes(formatResult.content);const sourceMapping=new FormatterSourceMappingImpl(originalContentLineEndings,formattedContentLineEndings,formatResult.mapping);this._callback(formatResult.content,sourceMapping);}}
class ScriptIdentityFormatter{constructor(mimeType,content,callback){callback(content,new IdentityFormatterSourceMapping());}}
class FormatterSourceMapping{originalToFormatted(lineNumber,columnNumber){}
formattedToOriginal(lineNumber,columnNumber){}}
class IdentityFormatterSourceMapping{originalToFormatted(lineNumber,columnNumber){return[lineNumber,columnNumber||0];}
formattedToOriginal(lineNumber,columnNumber){return[lineNumber,columnNumber||0];}}
class FormatterSourceMappingImpl{constructor(originalLineEndings,formattedLineEndings,mapping){this._originalLineEndings=originalLineEndings;this._formattedLineEndings=formattedLineEndings;this._mapping=mapping;}
originalToFormatted(lineNumber,columnNumber){const originalPosition=FormatterInterface.locationToPosition(this._originalLineEndings,lineNumber,columnNumber||0);const formattedPosition=this._convertPosition(this._mapping.original,this._mapping.formatted,originalPosition||0);return FormatterInterface.positionToLocation(this._formattedLineEndings,formattedPosition);}
formattedToOriginal(lineNumber,columnNumber){const formattedPosition=FormatterInterface.locationToPosition(this._formattedLineEndings,lineNumber,columnNumber||0);const originalPosition=this._convertPosition(this._mapping.formatted,this._mapping.original,formattedPosition);return FormatterInterface.positionToLocation(this._originalLineEndings,originalPosition||0);}
_convertPosition(positions1,positions2,position){const index=positions1.upperBound(position)-1;let convertedPosition=positions2[index]+position-positions1[index];if(index<positions2.length-1&&convertedPosition>positions2[index+1]){convertedPosition=positions2[index+1];}
return convertedPosition;}}
var ScriptFormatter$1=Object.freeze({__proto__:null,FormatterInterface:FormatterInterface,ScriptFormatter:ScriptFormatter,FormatterSourceMapping:FormatterSourceMapping});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');class SourceFormatter{constructor(){this._projectId='formatter:';this._project=new ContentProviderBasedProject.ContentProviderBasedProject(Workspace.WorkspaceImpl.instance(),this._projectId,Workspace.projectTypes.Formatter,'formatter',true);this._formattedSourceCodes=new Map();this._scriptMapping=new ScriptMapping();this._styleMapping=new StyleMapping();Workspace.WorkspaceImpl.instance().addEventListener(Workspace.Events.UISourceCodeRemoved,event=>{this._onUISourceCodeRemoved(event);},this);}
async _onUISourceCodeRemoved(event){const uiSourceCode=(event.data);const cacheEntry=this._formattedSourceCodes.get(uiSourceCode);if(cacheEntry&&cacheEntry.formatData){await this._discardFormatData(cacheEntry.formatData);}
this._formattedSourceCodes.delete(uiSourceCode);}
async discardFormattedUISourceCode(formattedUISourceCode){const formatData=SourceFormatData._for(formattedUISourceCode);if(!formatData){return null;}
await this._discardFormatData(formatData);this._formattedSourceCodes.delete(formatData.originalSourceCode);return formatData.originalSourceCode;}
async _discardFormatData(formatData){delete formatData.formattedSourceCode[SourceFormatData._formatDataSymbol];await 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;async 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=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;await this._scriptMapping._setSourceMappingEnabled(formatData,true);await 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 TextRange$1.TextRange(startLocation[0],startLocation[1],endLocation[0],endLocation[1]),(decoration.type()),decoration.data());}
fulfillFormatPromise(formatData);}}}
class ScriptMapping{constructor(){DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().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=DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().uiLocationToRawLocationsForUnformattedJavaScript(formatData.originalSourceCode,originalLine,originalColumn);console.assert(rawLocations.every(l=>l&&!!l.script()));return rawLocations;}
if(formatData.originalSourceCode.contentType()===ResourceType.resourceTypes.Document){const target=NetworkProject.NetworkProject.targetForUISourceCode(formatData.originalSourceCode);const debuggerModel=target&&target.model(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[];}
async _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];}}
const updatePromises=scripts.map(script=>DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().updateLocations(script));await Promise.all(updatePromises);}
_scriptsForUISourceCode(uiSourceCode){if(uiSourceCode.contentType()===ResourceType.resourceTypes.Document){const target=NetworkProject.NetworkProject.targetForUISourceCode(uiSourceCode);const debuggerModel=target&&target.model(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=DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().uiLocationToRawLocationsForUnformattedJavaScript(uiSourceCode,0,0);return rawLocations.map(location=>location.script()).filter(script=>!!script);}
return[];}}
class StyleMapping{constructor(){CSSWorkspaceBinding.CSSWorkspaceBinding.instance().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 CSSModel.CSSLocation(header,originalLine,originalColumn));}
async _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]);}
const updatePromises=headers.map(header=>CSSWorkspaceBinding.CSSWorkspaceBinding.instance().updateLocations(header));await Promise.all(updatePromises);}
_headersForUISourceCode(uiSourceCode){if(uiSourceCode.contentType()===ResourceType.resourceTypes.Document){const target=NetworkProject.NetworkProject.targetForUISourceCode(uiSourceCode);const cssModel=target&&target.model(CSSModel.CSSModel);if(cssModel){return cssModel.headersForSourceURL(uiSourceCode.url()).filter(header=>header.isInline&&!header.hasSourceURL);}}else if(uiSourceCode.contentType().isStyleSheet()){const rawLocations=CSSWorkspaceBinding.CSSWorkspaceBinding.instance().uiLocationToRawLocations(uiSourceCode.uiLocation(0,0));return rawLocations.map(rawLocation=>rawLocation.header()).filter(header=>!!header);}
return[];}}
var SourceFormatter$1=Object.freeze({__proto__:null,SourceFormatData:SourceFormatData,SourceFormatter:SourceFormatter});const sourceFormatter=new SourceFormatter();export{FormatterWorkerPool$1 as FormatterWorkerPool,ScriptFormatter$1 as ScriptFormatter,SourceFormatter$1 as SourceFormatter,sourceFormatter};