forked from phcode-dev/staging.phcode.dev
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathCSSUtils.js
More file actions
1 lines (1 loc) · 32.7 KB
/
CSSUtils.js
File metadata and controls
1 lines (1 loc) · 32.7 KB
1
define(function(require,exports,module){var CodeMirror=require("thirdparty/CodeMirror/lib/codemirror"),Async=require("utils/Async"),DocumentManager=require("document/DocumentManager"),AppInit=require("utils/AppInit"),EditorManager=require("editor/EditorManager"),HTMLUtils=require("language/HTMLUtils"),LanguageManager=require("language/LanguageManager"),ProjectManager=require("project/ProjectManager"),TokenUtils=require("utils/TokenUtils"),IndexingWorker=require("worker/IndexingWorker"),_=require("thirdparty/lodash");const MAX_CONTENT_LENGTH=10485760,SELECTOR="selector",PROP_NAME="prop.name",PROP_VALUE="prop.value",IMPORT_URL="import.url";var _bracketPairs={"{":"}","[":"]","(":")"},_invertedBracketPairs=_.invert(_bracketPairs);function isCSSPreprocessorFile(filePath){var languageId=LanguageManager.getLanguageForPath(filePath).getId();return"less"===languageId||"scss"===languageId}function _hasNonWhitespace(text){return/\S/.test(text)}function _getContextState(ctx){if(!ctx||!ctx.token)return null;var state=ctx.token.state.localState||ctx.token.state;return state.htmlState?state=ctx.token.state.htmlState:!state.context&&ctx.token.state.html&&ctx.token.state.html.localState&&(state=ctx.token.state.html.localState),state}function _isInPropName(ctx){var state=_getContextState(ctx),lastToken;return!(!state||!state.context||"comment"===ctx.token.type)&&("{"===(lastToken=state.context.type)||"rule"===lastToken||"block"===lastToken)}function _isInPropValue(ctx){function isInsideParens(context){return!("parens"!==context.type||!context.prev)&&("prop"===context.prev.type||isInsideParens(context.prev))}var state=_getContextState(ctx);return!!(state&&state.context&&state.context.prev&&"comment"!==ctx.token.type)&&("prop"===state.context.type&&("rule"===state.context.prev.type||"block"===state.context.prev.type)||isInsideParens(state.context))}function _isInAtRule(ctx){var state=_getContextState(ctx);return!(!state||!state.context)&&"atBlock_parens"===state.context.type}function createInfo(context,offset,name,index,values,isNewItem,range){var ruleInfo={context:context||"",offset:offset||0,name:name||"",index:-1,values:[],isNewItem:!0===isNewItem,range:range};return context!==PROP_VALUE&&context!==SELECTOR&&context!==IMPORT_URL||(ruleInfo.index=index,ruleInfo.values=values),ruleInfo}function _getPropNameInfo(ctx){var propName="",offset=TokenUtils.offsetInToken(ctx),tokenString=ctx.token.string,excludedCharacters=[";","{","}"];if("property"===ctx.token.type||"property error"===ctx.token.type||"tag"===ctx.token.type)propName=tokenString,TokenUtils.movePrevToken(ctx)&&_hasNonWhitespace(ctx.token.string)&&-1===excludedCharacters.indexOf(ctx.token.string)&&(propName=ctx.token.string+tokenString,offset+=ctx.token.string.length);else if("meta"===ctx.token.type||"-"===tokenString)propName=tokenString,!TokenUtils.moveNextToken(ctx)||"property"!==ctx.token.type&&"property error"!==ctx.token.type&&"tag"!==ctx.token.type||(propName+=ctx.token.string);else{if(_hasNonWhitespace(tokenString)&&-1===excludedCharacters.indexOf(tokenString))return createInfo();var testPos={ch:ctx.pos.ch+1,line:ctx.pos.line},testToken=ctx.editor.getTokenAt(testPos,!0);if("property"===testToken.type||"property error"===testToken.type||"tag"===testToken.type)propName=testToken.string,offset=0;else if("meta"===testToken.type||"-"===testToken.string)return ctx.pos=testPos,ctx.token=testToken,_getPropNameInfo(ctx)}return""===propName&&(offset=0),createInfo(PROP_NAME,offset,propName)}function _getPropNameStartingFromPropValue(ctx){var ctxClone=$.extend({},ctx),propName="";do{if(":"!==ctxClone.token.string&&!_isInPropValue(ctxClone))return""}while(":"!==ctxClone.token.string&&TokenUtils.moveSkippingWhitespace(TokenUtils.movePrevToken,ctxClone));return":"!==ctxClone.token.string||!TokenUtils.moveSkippingWhitespace(TokenUtils.movePrevToken,ctxClone)||"property"!==ctxClone.token.type&&"property error"!==ctxClone.token.type||(propName=ctxClone.token.string,TokenUtils.movePrevToken(ctxClone)&&"meta"===ctxClone.token.type&&(propName=ctxClone.token.string+propName)),propName}function _getPrecedingPropValues(ctx){for(var lastValue="",curValue,propValues=[];":"!==ctx.token.string&&TokenUtils.movePrevToken(ctx)&&":"!==ctx.token.string&&_isInPropValue(ctx);)curValue=ctx.token.string,""!==lastValue&&(curValue+=lastValue),ctx.token.string.length>0&&!ctx.token.string.match(/\S/)||","===ctx.token.string?lastValue=curValue:(lastValue="",0===propValues.length||curValue.match(/,\s*$/)?propValues.push(curValue):propValues[propValues.length-1]=curValue+propValues[propValues.length-1]);return propValues.length>0&&propValues.reverse(),propValues}function _getSucceedingPropValues(ctx,currentValue){for(var lastValue=currentValue,propValues=[];";"!==ctx.token.string&&"}"!==ctx.token.string&&TokenUtils.moveNextToken(ctx)&&";"!==ctx.token.string&&"}"!==ctx.token.string;){if(!_isInPropValue(ctx)){lastValue="";break}""===lastValue?lastValue=ctx.token.string.trim():lastValue.length>0&&(ctx.token.string.length>0&&!ctx.token.string.match(/\S/)?(lastValue+=ctx.token.string,propValues.push(lastValue),lastValue=""):","===ctx.token.string?lastValue+=ctx.token.string:lastValue&&lastValue.match(/,$/)?(propValues.push(lastValue),lastValue=ctx.token.string.length>0?ctx.token.string:""):lastValue+=ctx.token.string)}return lastValue.length>0&&propValues.push(lastValue),propValues}function _getRangeForPropValue(startCtx,endCtx){for(var range={start:{},end:{}};TokenUtils.moveNextToken(startCtx)&&!_hasNonWhitespace(startCtx.token.string););for(;";"===endCtx.token.string||"}"===endCtx.token.string||!_hasNonWhitespace(endCtx.token.string);)TokenUtils.movePrevToken(endCtx);return range.start=_.clone(startCtx.pos),range.start.ch=startCtx.token.start,range.end=_.clone(endCtx.pos),range.end.ch=endCtx.token.end,range}function _getRuleInfoStartingFromPropValue(ctx,editorParam){var editor=editorParam._codeMirror||editorParam,contextDoc=editor.document||editor.doc,propNamePos=$.extend({},ctx.pos),backwardPos=$.extend({},ctx.pos),forwardPos=$.extend({},ctx.pos),propNameCtx=TokenUtils.getInitialContext(editor,propNamePos),backwardCtx,forwardCtx,lastValue="",propValues=[],index=-1,offset=TokenUtils.offsetInToken(ctx),canAddNewOne=!1,testPos={ch:ctx.pos.ch+1,line:ctx.pos.line},testToken=editor.getTokenAt(testPos,!0),propName,range;return(propName=_getPropNameStartingFromPropValue(propNameCtx))?(propValues=_getPrecedingPropValues(backwardCtx=TokenUtils.getInitialContext(editor,backwardPos)),lastValue="",":"===ctx.token.string?(index=0,canAddNewOne=!0):(index=propValues.length-1,","===ctx.token.string?(propValues[index]+=ctx.token.string,index++,canAddNewOne=!0):(index=index<0?0:index+1,ctx.token.string.match(/\S/)?lastValue=ctx.token.string:(canAddNewOne=!0,index>0&&(propValues[index-1]+=ctx.token.string.substr(0,offset))))),canAddNewOne&&(offset=0,contextDoc.getLine(ctx.pos.line).length>ctx.pos.ch&&(0===testToken.string.length||testToken.string.match(/\S/))&&(canAddNewOne=!1)),forwardCtx=TokenUtils.getInitialContext(editor,forwardPos),range=(propValues=propValues.concat(_getSucceedingPropValues(forwardCtx,lastValue))).length?_getRangeForPropValue(backwardCtx,forwardCtx):{start:_.clone(ctx.pos),end:_.clone(ctx.pos)},index===propValues.length&&(canAddNewOne=!0),createInfo(PROP_VALUE,offset,propName,index,propValues,canAddNewOne,range)):createInfo()}function _getImportUrlInfo(ctx,editor){var backwardPos=$.extend({},ctx.pos),forwardPos=$.extend({},ctx.pos),backwardCtx,forwardCtx,index=0,propValues=[],offset=TokenUtils.offsetInToken(ctx);if(ctx.token.type&&"string"!==ctx.token.type)return createInfo();for(backwardCtx=TokenUtils.getInitialContext(editor._codeMirror,backwardPos),propValues[0]=backwardCtx.token.string;TokenUtils.movePrevToken(backwardCtx)&&("def"!==backwardCtx.token.type||"@import"!==backwardCtx.token.string)&&(!backwardCtx.token.type||"atom"===backwardCtx.token.type||"url"===backwardCtx.token.string);)propValues[0]=backwardCtx.token.string+propValues[0],offset+=backwardCtx.token.string.length;if("def"!==backwardCtx.token.type||"@import"!==backwardCtx.token.string)return createInfo();forwardCtx=TokenUtils.getInitialContext(editor._codeMirror,forwardPos);do{if(!TokenUtils.moveNextToken(forwardCtx)){if("("===forwardCtx.token.string)break;return createInfo()}propValues[0]+=forwardCtx.token.string}while(")"!==forwardCtx.token.string&&""!==forwardCtx.token.string);return createInfo(IMPORT_URL,offset,"",0,propValues,!1)}function getInfoAtPos(editor,constPos){var pos=$.extend({},constPos),ctx=TokenUtils.getInitialContext(editor._codeMirror,pos),mode=editor.getModeForSelection();if("css"!==mode&&"text/x-scss"!==mode&&"text/x-less"!==mode)return createInfo();if(ctx.token.state.htmlState&&(!ctx.token.state.localMode||"css"!==ctx.token.state.localMode.name)){var tagInfo=HTMLUtils.getTagInfo(editor,pos,!0),offset=tagInfo.position.offset,_contextCM=new CodeMirror(function(){},{value:"{"+tagInfo.attr.value.replace(/(^")|("$)/g,""),mode:"css"});ctx=TokenUtils.getInitialContext(_contextCM,{line:0,ch:offset+1})}return _isInPropName(ctx)?_getPropNameInfo(ctx):_isInPropValue(ctx)?_getRuleInfoStartingFromPropValue(ctx,ctx.editor):_isInAtRule(ctx)?_getImportUrlInfo(ctx,editor):createInfo()}function getCompleteSelectors(info,useGroup){if(info.parentSelectors){var completeSelectors=info.parentSelectors+" / ";return useGroup&&info.selectorGroup?completeSelectors+=info.selectorGroup:completeSelectors+=info.selector,completeSelectors}return useGroup&&info.selectorGroup?info.selectorGroup:info.selector}function extractAllSelectors(text,documentMode){var state,lines,lineCount,token,style,stream,line,selectors=[],mode=CodeMirror.getMode({indentUnit:2},documentMode||"css"),currentSelector="",currentLevel=0,ruleStartChar=-1,ruleStartLine=-1,selectorStartChar=-1,selectorStartLine=-1,selectorGroupStartLine=-1,selectorGroupStartChar=-1,declListStartLine=-1,declListStartChar=-1,escapePattern=new RegExp("\\\\[^\\\\]+","g"),validationPattern=new RegExp("\\\\([a-f0-9]{6}|[a-f0-9]{4}(\\s|\\\\|$)|[a-f0-9]{2}(\\s|\\\\|$)|.)","i"),_parseRuleList;function _hasStream(){for(;stream.eol();){if(++line>=lineCount)return!1;_hasNonWhitespace(currentSelector)&&(currentSelector+=" "),stream=new CodeMirror.StringStream(lines[line])}return!0}function _firstToken(){return state=CodeMirror.startState(mode),lines=CodeMirror.splitLines(text),0!==(lineCount=lines.length)&&(line=0,stream=new CodeMirror.StringStream(lines[line]),!!_hasStream()&&(style=mode.token(stream,state),token=stream.current(),!0))}function _nextToken(){return stream.start=stream.pos,!!_hasStream()&&(style=mode.token(stream,state),token=stream.current(),!0)}function _firstTokenSkippingWhitespace(){if(!_firstToken())return!1;for(;!_hasNonWhitespace(token);)if(!_nextToken())return!1;return!0}function _nextTokenSkippingWhitespace(){if(!_nextToken())return!1;for(;!_hasNonWhitespace(token);)if(!_nextToken())return!1;return!0}function _isStartComment(){return/^\/[\/\*]/.test(token)}function _parseComment(){if(!/^\/\//.test(token))for(;!/\*\/$/.test(token)&&_nextToken(););}function _nextTokenSkippingComments(){if(!_nextToken())return!1;for(;_isStartComment();)if(_parseComment(),!_nextToken())return!1;return!0}function _skipToClosingBracket(startChar){var skippedText="",unmatchedBraces=0;for(startChar||(startChar="{");;){if(-1!==token.indexOf(startChar)&&-1===token.indexOf(_bracketPairs[startChar]))unmatchedBraces++;else if(token===_bracketPairs[startChar]&&--unmatchedBraces<=0)return skippedText+=token;if(skippedText+=token,!_nextTokenSkippingComments())return skippedText}}function _maybeProperty(){return/^-(moz|ms|o|webkit)-$/.test(token)||"top"!==state.state&&"block"!==state.state&&"pseudo"!==state.state&&-1!==stream.string.indexOf(";")&&!/\([^)]+;/.test(stream.string)}function _skipProperty(){for(var prevToken="";";"!==token&&(!(/[#@]\{$/.test(token)||"{"===token&&/[#@]$/.test(prevToken))||(_skipToClosingBracket("{"),"}"===token&&_nextToken(),";"!==token));){if("{"===token||"}"===token)return!1;if(prevToken=token,!_nextTokenSkippingComments())break}return!0}function _getParentSelectors(){var j;for(j=selectors.length-1;j>=0;j--)if(-1===selectors[j].declListEndLine&&selectors[j].level<currentLevel)return getCompleteSelectors(selectors[j],!0);return""}function _parseSelector(start,level){for(currentSelector="",selectorStartChar=start,selectorStartLine=line;","!==token&&"{"!==token||"{"===token&&/[#@]$/.test(currentSelector)||","===token&&!_hasNonWhitespace(currentSelector);){if("{"===token)currentSelector+=_skipToClosingBracket("{"),_nextToken();else if("}"===token&&(!currentSelector||/:\s*\S/.test(currentSelector)||!/[#@]\{.+/.test(currentSelector)))return!1;if(";"===token&&"parens"!==state.state||"prop"===state.state&&!/\{/.test(stream.string)?currentSelector="":"("===token?_hasNonWhitespace(currentSelector)?currentSelector+=_skipToClosingBracket("("):_skipToClosingBracket("("):(_hasNonWhitespace(token)||_hasNonWhitespace(currentSelector))&&(currentSelector+=token),!_nextTokenSkippingComments())return!1}if(!currentSelector)return!1;/\\/.test(currentSelector)&&(currentSelector=currentSelector.replace(escapePattern,function(escapedToken){return escapedToken.replace(validationPattern,function(unicodeChar){return 1===(unicodeChar=unicodeChar.substr(1)).length?unicodeChar:parseInt(unicodeChar,16)<1114111?String.fromCharCode(parseInt(unicodeChar,16)):String.fromCharCode(65533)})})),currentSelector=currentSelector.trim();var startChar=-1===selectorGroupStartLine?selectorStartChar:selectorStartChar+1,selectorStart=-1!==stream.string.indexOf(currentSelector,selectorStartChar)?stream.string.indexOf(currentSelector,selectorStartChar-currentSelector.length):startChar;if(""!==currentSelector){currentLevel<level&¤tLevel++,-1===ruleStartLine&&(ruleStartLine=line,ruleStartChar=stream.start-currentSelector.length);var parentSelectors=_getParentSelectors();selectors.push({selector:currentSelector,ruleStartLine:ruleStartLine,ruleStartChar:ruleStartChar,selectorStartLine:selectorStartLine,selectorStartChar:selectorStart,declListEndLine:-1,selectorEndLine:line,selectorEndChar:selectorStart+currentSelector.length,selectorGroupStartLine:selectorGroupStartLine,selectorGroupStartChar:selectorGroupStartChar,level:currentLevel,parentSelectors:parentSelectors}),currentSelector=""}return selectorStartChar=-1,!0}function _parseSelectorList(level){if(selectorGroupStartLine=-1!==stream.string.indexOf(",")?line:-1,selectorGroupStartChar=stream.start,!_parseSelector(stream.start,level))return!1;for(;","===token;){if(!_nextTokenSkippingComments())return!1;if(!_parseSelector(stream.start,level))return!1}return!0}function _parseDeclarationList(level){var j,selectorGroup,sgLine;if(declListStartLine=Math.min(line,lineCount-1),declListStartChar=stream.start,-1!==selectorGroupStartLine){for(selectorGroup="",sgLine=selectorGroupStartLine;sgLine<=declListStartLine;sgLine++){var startChar=0,endChar=lines[sgLine].length;sgLine===selectorGroupStartLine?startChar=selectorGroupStartChar:selectorGroup+=" ",sgLine===declListStartLine&&(endChar=declListStartChar),selectorGroup+=lines[sgLine].substring(startChar,endChar).trim()}selectorGroup=selectorGroup.trim()}for(j=selectors.length-1;j>=0;j--)if(selectors[j].level===level){if(-1!==selectors[j].declListEndLine)break;selectors[j].declListStartLine=declListStartLine,selectors[j].declListStartChar=declListStartChar,selectorGroup&&(selectors[j].selectorGroup=selectorGroup)}var nested=!0;do{for(selectorGroupStartLine=-1,selectorGroupStartChar=-1,ruleStartLine=-1,ruleStartChar=-1,nested||currentLevel>0&¤tLevel===level&&(currentLevel--,"}"===token&&_nextTokenSkippingWhitespace()),"{"===token&&_nextTokenSkippingWhitespace(),nested=_parseRuleList(void 0,currentLevel+1),j=selectors.length-1;j>=0&&!(selectors[j].level<currentLevel);j--)-1===selectors[j].declListEndLine&&(selectors[j].declListEndLine=line,selectors[j].declListEndChar=stream.pos-1)}while(currentLevel>0&¤tLevel===level)}function includeCommentInNextRule(){return-1===ruleStartChar&&!(stream.start>0&&-1!==lines[line].substr(0,stream.start).indexOf("}"))}function _isStartAtRule(){return/^@/.test(token)&&!/^@mixin/i.test(token)&&"@"!==token}function _followedByPseudoSelector(){return/\}:(enabled|disabled|checked|indeterminate|link|visited|hover|active|focus|target|lang|root|nth-|first-|last-|only-|empty|not)/.test(stream.string)}function _isVariableInterpolatedProperty(){return/[@#]\{\S+\}(\s*:|.*;)/.test(stream.string)&&!_followedByPseudoSelector()}function _parseAtRule(level){if(ruleStartLine=-1,ruleStartChar=-1,selectorStartLine=-1,selectorStartChar=-1,selectorGroupStartLine=-1,selectorGroupStartChar=-1,/@media/i.test(token)){for(;"{"!==token;)if(!_nextTokenSkippingComments())return;if(!_nextTokenSkippingWhitespace())return;currentLevel<=level&¤tLevel++,_parseRuleList("}",currentLevel+1),currentLevel>0&¤tLevel--}else for(;";"!==token;){if("{"===token)return void _skipToClosingBracket("{");if(!_nextTokenSkippingComments())return}}function _parseRule(level){return!!_parseSelectorList(level)&&(_parseDeclarationList(level),!0)}return _parseRuleList=function(escapeToken,level){for(;!escapeToken||token!==escapeToken;){if(_isVariableInterpolatedProperty()){if(!_skipProperty())return!1}else if(_isStartAtRule())_parseAtRule(level);else if(_isStartComment())includeCommentInNextRule()&&(ruleStartChar=stream.start,ruleStartLine=line),_parseComment();else if(_maybeProperty()){if(!_skipProperty())return!1}else{if(!_parseRule(void 0===level?0:level)&&level>0)return!1;if(level>0)return!0;ruleStartChar=-1,ruleStartLine=-1}if(!_nextTokenSkippingWhitespace())break}return!0},_firstTokenSkippingWhitespace()&&_parseRuleList(),selectors}function _stripAtRules(selector){return 0===(selector=selector.trim()).indexOf("@")?"":selector}function _getSelectorInFinalCSSForm(selectorArray){var finalSelectorArray=[""],parentSelectorArray=[],group=[];return _.forEach(selectorArray,function(selector){selector=_stripAtRules(selector),group=selector.split(","),parentSelectorArray=[],_.forEach(group,function(cs){var ampersandIndex=cs.indexOf("&");_.forEach(finalSelectorArray,function(ps){-1===ampersandIndex?(cs=_stripAtRules(cs),ps.length&&cs.length&&(ps+=" "),ps+=cs):ps=_stripAtRules(cs.replace(/&/g,ps)),parentSelectorArray.push(ps)})}),finalSelectorArray=parentSelectorArray}),finalSelectorArray.join(", ")}function _findAllMatchingSelectorsInText(text,selector,mode){var allSelectors=extractAllSelectors(text,mode),result=[],classOrIdSelector="."===selector[0]||"#"===selector[0];"."===selector[0]&&(selector="\\"+selector),classOrIdSelector||(selector="(^|[\\s>+~])"+selector);var re=new RegExp(selector+"(\\[[^\\]]*\\]|:{1,2}[\\w-()]+|\\.[\\w-]+|#[\\w-]+)*\\s*$",classOrIdSelector?"":"i");return allSelectors.forEach(function(entry){var actualSelector=entry.selector;if(-1!==entry.selector.indexOf("&")&&entry.parentSelectors){var selectorArray=entry.parentSelectors.split(" / ");selectorArray.push(entry.selector),actualSelector=_getSelectorInFinalCSSForm(selectorArray)}-1!==actualSelector.search(re)?result.push(entry):classOrIdSelector||/\*\s*$/.test(actualSelector)&&result.push(entry)}),result}function _addSelectorsToResults(resultSelectors,selectorsToAdd,sourceDoc,lineOffset){selectorsToAdd.forEach(function(selectorInfo){resultSelectors.push({name:getCompleteSelectors(selectorInfo),document:sourceDoc,lineStart:selectorInfo.ruleStartLine+lineOffset,lineEnd:selectorInfo.declListEndLine+lineOffset,selectorGroup:selectorInfo.selectorGroup})})}function _findMatchingRulesInCSSFiles(selector,resultSelectors){var result=new $.Deferred;function _loadFileAndScan(fullPath,selector){var oneFileResult=new $.Deferred;return DocumentManager.getDocumentForPath(fullPath).done(function(doc){var oneCSSFileMatches=_findAllMatchingSelectorsInText(doc.getText(),selector,doc.getLanguage().getMode());_addSelectorsToResults(resultSelectors,oneCSSFileMatches,doc,0),oneFileResult.resolve()}).fail(function(error){console.warn("Unable to read "+fullPath+" during CSS rule search:",error),oneFileResult.resolve()}),oneFileResult.promise()}return ProjectManager.getAllFiles(ProjectManager.getLanguageFilter(["css","less","scss"])).done(function(cssFiles){Async.doInParallel(cssFiles,function(fileInfo,number){return _loadFileAndScan(fileInfo.fullPath,selector)}).then(result.resolve,result.reject)}),result.promise()}function _findMatchingRulesInStyleBlocks(htmlDocument,selector,resultSelectors){var htmlEditor=EditorManager.getCurrentFullEditor(),styleBlocks;htmlEditor.document===htmlDocument?HTMLUtils.findStyleBlocks(htmlEditor).forEach(function(styleBlockInfo){var oneStyleBlockMatches=_findAllMatchingSelectorsInText(styleBlockInfo.text,selector);_addSelectorsToResults(resultSelectors,oneStyleBlockMatches,htmlDocument,styleBlockInfo.start.line)}):console.error("Cannot search for <style> blocks in HTML file other than current editor")}function findMatchingRules(selector,htmlDocument){var result=new $.Deferred,resultSelectors=[];return htmlDocument&&_findMatchingRulesInStyleBlocks(htmlDocument,selector,resultSelectors),_findMatchingRulesInCSSFiles(selector,resultSelectors).done(function(){result.resolve(resultSelectors)}).fail(function(error){result.reject(error)}),result.promise()}function findSelectorAtDocumentPos(editor,pos){var cm=editor._codeMirror,ctx=TokenUtils.getInitialContext(cm,$.extend({},pos)),selector="",foundChars=!1,encounteredSemicolon=!1,isPreprocessorDoc=isCSSPreprocessorFile(editor.document.file.fullPath),selectorArray=[];function _skipToOpeningBracket(ctx,startChar){var unmatchedBraces=0;for(startChar||(startChar="}");;){if(startChar===ctx.token.string)unmatchedBraces++;else if(ctx.token.string.match(_invertedBracketPairs[startChar])&&--unmatchedBraces<=0)return;if(!TokenUtils.movePrevToken(ctx))return}}function _parseSelector(ctx){var selector="";for(TokenUtils.movePrevToken(ctx);;){if("comment"!==ctx.token.type){if(/[\{\}\;]/.test(ctx.token.string))break;if("style"===ctx.token.string&&"tag"===ctx.token.type){var eotIndex=selector.indexOf(">");-1!==eotIndex&&(selector=selector.substring(eotIndex+1));break}selector=ctx.token.string+selector}if(!TokenUtils.movePrevToken(ctx))break}return selector}var skipPrevSibling=!1,state=_getContextState(ctx),closingLineText;isPreprocessorDoc&&_hasNonWhitespace(ctx.token.string)&&"{"!==ctx.token.string&&("block"===state.state||"top"===state.state)&&(foundChars=!0);do{if("comment"!==ctx.token.type)if("}"===ctx.token.string){if(!isPreprocessorDoc)break;if("top"===state.state)break;skipPrevSibling=!0,_skipToOpeningBracket(ctx,"}")}else if("{"===ctx.token.string){if(selector=_parseSelector(ctx),!isPreprocessorDoc)break;skipPrevSibling||/^\s*@/.test(selector)||selectorArray.unshift(selector),skipPrevSibling&&(skipPrevSibling=!1)}else isPreprocessorDoc||";"!==ctx.token.string||foundChars||(encounteredSemicolon=!0),!isPreprocessorDoc&&_hasNonWhitespace(ctx.token.string)&&(foundChars=!0),TokenUtils.movePrevToken(ctx);else TokenUtils.movePrevToken(ctx)}while(!TokenUtils.isAtStart(ctx));if(!(selector=_stripAtRules(selector))&&!isPreprocessorDoc&&"}"===cm.getLine(pos.line).trim()){var braceCtx=TokenUtils.getInitialContext(cm,{line:pos.line,ch:cm.getLine(pos.line).indexOf("}")+1});_skipToOpeningBracket(braceCtx,"}"),"{"===braceCtx.token.string&&(selector=_stripAtRules(_parseSelector(braceCtx)))}if(ctx=TokenUtils.getInitialContext(cm,$.extend({},pos)),(!selector&&!foundChars&&!isPreprocessorDoc||isPreprocessorDoc&&(""===ctx.token.string||/\s+/.test(ctx.token.string)))&&TokenUtils.moveNextToken(ctx)&&"comment"!==ctx.token.type&&_hasNonWhitespace(ctx.token.string)&&(foundChars=!0,ctx=TokenUtils.getInitialContext(cm,$.extend({},pos))),(!selector||isPreprocessorDoc)&&foundChars&&(!encounteredSemicolon||_hasNonWhitespace(cm.getLine(pos.line))))for(;;){if("comment"!==ctx.token.type){if("{"===ctx.token.string){selector=_parseSelector(ctx),isPreprocessorDoc&&!/^\s*@/.test(selector)&&selectorArray.push(selector);break}if("}"===ctx.token.string||";"===ctx.token.string)break}if(!TokenUtils.moveNextToken(ctx))break}return isPreprocessorDoc?_getSelectorInFinalCSSForm(selectorArray):_stripAtRules(selector)}function _removeComments(content){return content.replace(/\/\*(?:(?!\*\/)[\s\S])*\*\//g,"")}function _removeStrings(content){var s;return content.replace(/\\\"|\\\'/g,"").replace(/\"(.*?)\"|\'(.*?)\'/g,"")}function reduceStyleSheetForRegExParsing(content){return _removeStrings(_removeComments(content))}function addRuleToDocument(doc,selector,useTabChar,indentUnit){var newRule="\n"+selector+" {\n",blankLineOffset;if(useTabChar)newRule+="\t",blankLineOffset=1;else{var i;for(i=0;i<indentUnit;i++)newRule+=" ";blankLineOffset=indentUnit}newRule+="\n}\n";var docLines=doc.getText().split("\n"),lastDocLine=docLines.length-1,lastDocChar=docLines[docLines.length-1].length;return doc.replaceRange(newRule,{line:lastDocLine,ch:lastDocChar}),{range:{from:{line:lastDocLine+1,ch:0},to:{line:lastDocLine+3,ch:1}},pos:{line:lastDocLine+2,ch:blankLineOffset}}}function consolidateRules(rules){var newRules=[],lastRule;return rules.forEach(function(rule){rule.selectorGroup&&(rule.name=rule.selectorGroup),lastRule&&rule.document===lastRule.document&&rule.lineStart===lastRule.lineStart&&rule.lineEnd===lastRule.lineEnd&&rule.selectorGroup===lastRule.selectorGroup||newRules.push(rule),lastRule=rule}),newRules}function getRangeSelectors(range){var i,startIndex=0,endIndex,text=range.document.getText();for(i=0;i<range.startLine;i++)startIndex=text.indexOf("\n",startIndex)+1;for(endIndex=startIndex,i=range.startLine+1;i<=range.endLine+1;i++)endIndex=text.indexOf("\n",endIndex)+1;var allSelectors=extractAllSelectors(text.substring(startIndex,endIndex));return allSelectors.length?allSelectors[0].selectorGroup||allSelectors[0].selector:""}function _extractSelectorSet(selectorList){const regex=/[{}!]/,selectors=new Set;if(!selectorList)return selectors;for(let item of selectorList){if(regex.test(item)||!item.trim())continue;const extracted=extractSelectorBase(item);extracted.trim()&&selectors.add(extracted)}return selectors}const CSSSelectorCache=new Phoenix.libs.LRUCache({maxSize:104857600,sizeCalculation:value=>value.length});function _projectFileChanged(_evt,entry){if(!entry)return;let changedPath=entry.fullPath;if(entry.isFile)CSSSelectorCache.delete(changedPath);else if(entry.isDirectory){changedPath=Phoenix.VFS.ensureTrailingSlash(changedPath);const cachedFilePaths=Array.from(CSSSelectorCache.keys());for(let filePath of cachedFilePaths)filePath.startsWith(changedPath)&&CSSSelectorCache.delete(filePath)}}const CSS_MODE_MAP={css:"CSS",less:"LESS",scss:"SCSS"};function _loadFileAndScanCSSSelectorCached(fullPath){return new Promise(resolve=>{DocumentManager.getDocumentForPath(fullPath).done(function(doc){let selectors=new Set;const cachedSelectors=CSSSelectorCache.get(fullPath);if(cachedSelectors)return void resolve(new Set(JSON.parse(cachedSelectors)));const langID=doc.getLanguage().getId();if(!CSS_MODE_MAP[langID])return console.log("Cannot parse CSS for mode :",langID,"ignoring",fullPath),void resolve(selectors);console.log("scanning file for css selector collation: ",fullPath),IndexingWorker.execPeer("css_getAllSymbols",{text:doc.getText(),cssMode:CSS_MODE_MAP[langID],filePath:fullPath}).then(selectorArray=>{selectors=_extractSelectorSet(selectorArray),CSSSelectorCache.set(fullPath,JSON.stringify(Array.from(selectors))),resolve(selectors)}).catch(err=>{console.warn("CSS language service unable to get selectors for"+fullPath,err),resolve(selectors)})}).fail(function(error){console.warn("Unable to read "+fullPath+" during CSS selector search:",error),resolve(new Set)})})}function extractSelectorBase(selector){const match=selector.match(/^[^\s>+~:\[]+/);return(selector=match?match[0]:selector).startsWith(".")&&(selector="."+selector.split(".")[1]),selector}const _htmlLikeFileExts=["htm","html","xhtml","php"];function _isHtmlLike(editor){const fullPath=editor&&editor.document.file.fullPath;return!(!editor||!LanguageManager.getLanguageForPath(fullPath))&&-1!==_htmlLikeFileExts.indexOf(LanguageManager.getLanguageForPath(fullPath).getId()||"")}const cacheInProgress=new Set,fetchBlock10Secs=new Phoenix.libs.LRUCache({max:5e3,ttl:1e4});async function _precacheExternalStyleSheet(link){try{if(cacheInProgress.has(link)||fetchBlock10Secs.get(link))return;fetchBlock10Secs.set(link,!0),cacheInProgress.add(link);const extension=path.extname(new URL(link).pathname).slice(1);if(!extension||!CSS_MODE_MAP[extension])return void console.log(`Not a valid stylesheet type ${extension}, ignoring`,link);const responseHead=await fetch(link,{method:"HEAD"}),contentLength=responseHead.headers.get("Content-Length");if(!contentLength||contentLength>MAX_CONTENT_LENGTH)return void console.log(`Stylesheet is larger than ${MAX_CONTENT_LENGTH}bytes - ${contentLength}, ignoring`,link);const response=await fetch(link),styleSheetText=await response.text();IndexingWorker.execPeer("css_getAllSymbols",{text:styleSheetText,cssMode:CSS_MODE_MAP[extension],filePath:link}).then(selectorArray=>{const selectorJson=JSON.stringify(Array.from(_extractSelectorSet(selectorArray)));CSSSelectorCache.set(link,selectorJson)}).catch(err=>{console.warn("CSS language service unable to get selectors for link"+link,err)})}catch(e){console.error("Error pre caching externally linked style sheet ",link)}cacheInProgress.delete(link)}const MAX_ALLOWED_EXTERNAL_STYLE_SHEETS=30;async function _getLinkedCSSFileSelectors(htmlFileContent,fileMode,fullPath){const linkedFiles=await catchToNull(IndexingWorker.execPeer("html_getAllLinks",{text:htmlFileContent,htmlMode:fileMode,filePath:fullPath}),"error extracting linked css files from"+fullPath)||[];let selectors=new Set,externalStyleSheetCount=0;for(const link of linkedFiles){if(externalStyleSheetCount>=MAX_ALLOWED_EXTERNAL_STYLE_SHEETS)break;if(link.startsWith("http://")||link.startsWith("https://")){externalStyleSheetCount++;let cachedSelectorsArray=CSSSelectorCache.get(link);if(cachedSelectorsArray){cachedSelectorsArray=JSON.parse(cachedSelectorsArray);for(let value of cachedSelectorsArray)selectors.add(value)}else _precacheExternalStyleSheet(link)}}return selectors}async function _getAllSelectorsInCurrentHTMLEditor(){let selectors=new Set;const htmlEditor=EditorManager.getCurrentFullEditor();if(!htmlEditor||!_isHtmlLike(htmlEditor))return selectors;const styleBlocks=HTMLUtils.findStyleBlocks(htmlEditor);let cssText="";styleBlocks.forEach(function(styleBlockInfo){cssText+=styleBlockInfo.text});const fullPath=htmlEditor.document.file.fullPath,selectorsPromise=IndexingWorker.execPeer("css_getAllSymbols",{text:cssText,cssMode:"CSS",filePath:fullPath}),htmlLanguageID=LanguageManager.getLanguageForPath(fullPath).getId(),remoteLinkedSelectors=await _getLinkedCSSFileSelectors(htmlEditor.document.getText(),htmlLanguageID.toUpperCase(),fullPath);return selectors=(selectors=await catchToNull(selectorsPromise,"CSS language service unable to get selectors for"+fullPath))||new Set,new Set([...selectors,...remoteLinkedSelectors])}let globalPrecacheRun=0;function getAllCssSelectorsInProject(options={includeClasses:!0,includeIDs:!0,scanCurrentHtml:!0}){return globalPrecacheRun++,new Promise(resolve=>{ProjectManager.getAllFiles(ProjectManager.getLanguageFilter(["css","less","scss"])).done(function(cssFiles){const promises=cssFiles.map(fileInfo=>_loadFileAndScanCSSSelectorCached(fileInfo.fullPath));options.scanCurrentHtml&&promises.push(_getAllSelectorsInCurrentHTMLEditor());const mergedSets=new Set;Promise.allSettled(promises).then(results=>{results.forEach((result,index)=>{"fulfilled"===result.status?result.value.forEach(value=>{(options.includeClasses&&value.startsWith(".")||options.includeIDs&&value.startsWith("#"))&&mergedSets.add(value)}):console.error(`Error collect css selectors from file ${cssFiles[index].fullPath}:`,result.reason)}),resolve(Array.from(mergedSets.keys()))})})})}async function _populateSelectorCache(){const currentCacheRun=++globalPrecacheRun,cssFiles=await jsPromise(ProjectManager.getAllFiles(ProjectManager.getLanguageFilter(["css","less","scss"])));for(let cssFile of cssFiles){if(currentCacheRun!==globalPrecacheRun)break;await _loadFileAndScanCSSSelectorCached(cssFile.fullPath)}}AppInit.appReady(function(){Phoenix.isSpecRunnerWindow||(ProjectManager.on(ProjectManager.EVENT_PROJECT_FILE_CHANGED,_projectFileChanged),ProjectManager.on(ProjectManager.EVENT_PROJECT_OPEN,()=>{CSSSelectorCache.clear(),fetchBlock10Secs.clear(),setTimeout(_populateSelectorCache,2e3)}),setTimeout(_populateSelectorCache,2e3),DocumentManager.on(DocumentManager.EVENT_DOCUMENT_CHANGE,function(event,doc,_changelist){CSSSelectorCache.delete(doc.file.fullPath)}))}),exports._findAllMatchingSelectorsInText=_findAllMatchingSelectorsInText,exports.findMatchingRules=findMatchingRules,exports.extractAllSelectors=extractAllSelectors,exports.findSelectorAtDocumentPos=findSelectorAtDocumentPos,exports.reduceStyleSheetForRegExParsing=reduceStyleSheetForRegExParsing,exports.addRuleToDocument=addRuleToDocument,exports.consolidateRules=consolidateRules,exports.getRangeSelectors=getRangeSelectors,exports.getCompleteSelectors=getCompleteSelectors,exports.isCSSPreprocessorFile=isCSSPreprocessorFile,exports.getAllCssSelectorsInProject=getAllCssSelectorsInProject,exports.SELECTOR=SELECTOR,exports.PROP_NAME=PROP_NAME,exports.PROP_VALUE=PROP_VALUE,exports.IMPORT_URL=IMPORT_URL,exports.getInfoAtPos=getInfoAtPos,exports.createInfo=createInfo});