/// <summary> /// Fills the list of LESS-files, that were added to a LESS-asset /// by using the LESS <code>@import</code> rules /// </summary> /// <param name="rootAssetUrl">URL of root LESS-asset file</param> /// <param name="parentStylesheet">Parent LESS-stylesheet</param> /// <param name="dependencies">List of LESS-files, that were added to a /// LESS-asset by using the LESS <code>@import</code> rules</param> public void FillDependencies(string rootAssetUrl, LessStylesheet parentStylesheet, DependencyCollection dependencies) { foreach (string dataUriFunctionImageUrl in parentStylesheet.DataUriFunctionAssetUrls) { var dependency = new Dependency(dataUriFunctionImageUrl, string.Empty); dependencies.Add(dependency); } foreach (LessImport import in parentStylesheet.Imports) { string dependencyUrl = import.Url; LessImportOptions dependencyOptions = import.ImportOptions; if (UrlHelpers.StartsWithProtocol(dependencyUrl)) { if (!dependencies.ContainsUrl(dependencyUrl)) { var dependency = new Dependency(dependencyUrl, string.Empty, false); dependencies.Add(dependency); } continue; } if (string.Equals(dependencyUrl, rootAssetUrl, StringComparison.OrdinalIgnoreCase)) { continue; } var duplicateDependency = dependencies.GetByUrl(dependencyUrl); bool isDuplicateDependency = (duplicateDependency != null); bool isEmptyDependency = isDuplicateDependency && (duplicateDependency.Content.Length == 0); bool isNonExistentOptionalDependency = false; if (!isDuplicateDependency || isEmptyDependency) { if (!LessStylesheetExists(dependencyUrl)) { if (dependencyOptions.Optional) { isNonExistentOptionalDependency = true; } else { throw new FileNotFoundException( string.Format(CoreStrings.Common_FileNotExist, dependencyUrl)); } } var stylesheet = new LessStylesheet(dependencyUrl, string.Empty); string dependencyContent = null; if (dependencyOptions.Less || dependencyOptions.Inline) { if (!isNonExistentOptionalDependency) { stylesheet = GetLessStylesheet(dependencyUrl, dependencyOptions); dependencyContent = stylesheet.Content; } if (isEmptyDependency && stylesheet.Content.Length > 0) { duplicateDependency.Content = dependencyContent; duplicateDependency.IsObservable = true; } else { var dependency = new Dependency(dependencyUrl, dependencyContent); dependencies.Add(dependency); } } else { if (!isNonExistentOptionalDependency) { dependencyContent = string.Empty; } if (!isDuplicateDependency) { var dependency = new Dependency(dependencyUrl, dependencyContent, false); dependencies.Add(dependency); } } FillDependencies(rootAssetUrl, stylesheet, dependencies); } } }
/// <summary> /// Preprocess a stylesheet content /// </summary> /// <param name="assetContent">Text content of LESS-asset</param> /// <param name="assetUrl">URL of LESS-asset file</param> /// <param name="assetImportOptions">Import options</param> /// <returns>Preprocessed text content of LESS-asset</returns> public LessStylesheet PreprocessStylesheet(string assetContent, string assetUrl, LessImportOptions assetImportOptions) { var stylesheet = new LessStylesheet(assetUrl, assetContent); int contentLength = assetContent.Length; if (contentLength == 0) { return stylesheet; } MatchCollection importRuleMatches = _lessImportRuleRegex.Matches(assetContent); MatchCollection dataUriFunctionMatches = _dataUriFunctionRegex.Matches(assetContent); MatchCollection urlRuleMatches = null; if (assetImportOptions.Inline) { urlRuleMatches = CommonRegExps.CssUrlRuleRegex.Matches(assetContent); } if (importRuleMatches.Count == 0 && dataUriFunctionMatches.Count == 0 && (urlRuleMatches == null || urlRuleMatches.Count == 0)) { return stylesheet; } var nodeMatches = new List<LessNodeMatch>(); foreach (Match importRuleMatch in importRuleMatches) { var nodeMatch = new LessNodeMatch(importRuleMatch.Index, importRuleMatch.Length, LessNodeType.ImportRule, importRuleMatch); nodeMatches.Add(nodeMatch); } foreach (Match dataUriFunctionMatch in dataUriFunctionMatches) { var nodeMatch = new LessNodeMatch(dataUriFunctionMatch.Index, dataUriFunctionMatch.Length, LessNodeType.DataUriFunction, dataUriFunctionMatch); nodeMatches.Add(nodeMatch); } if (urlRuleMatches != null) { foreach (Match urlRuleMatch in urlRuleMatches) { var nodeMatch = new LessNodeMatch(urlRuleMatch.Index, urlRuleMatch.Length, LessNodeType.UrlRule, urlRuleMatch); nodeMatches.Add(nodeMatch); } } MatchCollection multilineCommentMatches; if (assetImportOptions.Less) { multilineCommentMatches = CommonRegExps.CStyleMultilineCommentRegex.Matches(assetContent); } else { multilineCommentMatches = CommonRegExps.CssMultilineCommentRegex.Matches(assetContent); } foreach (Match multilineCommentMatch in multilineCommentMatches) { var nodeMatch = new LessNodeMatch(multilineCommentMatch.Index, multilineCommentMatch.Length, LessNodeType.MultilineComment, multilineCommentMatch); nodeMatches.Add(nodeMatch); } nodeMatches = nodeMatches .OrderBy(n => n.Position) .ThenByDescending(n => n.Length) .ToList() ; var contentBuilder = new StringBuilder(); int endPosition = contentLength - 1; int currentPosition = 0; foreach (LessNodeMatch nodeMatch in nodeMatches) { LessNodeType nodeType = nodeMatch.NodeType; int nodePosition = nodeMatch.Position; Match match = nodeMatch.Match; if (nodePosition < currentPosition) { continue; } if (nodeType == LessNodeType.ImportRule || nodeType == LessNodeType.DataUriFunction || nodeType == LessNodeType.UrlRule) { ProcessOtherContent(contentBuilder, assetContent, ref currentPosition, nodePosition); int startLinePosition; int endLinePosition; string currentLine = SourceCodeNavigator.GetCurrentLine(assetContent, nodePosition, out startLinePosition, out endLinePosition); int localNodePosition = nodePosition - startLinePosition; if (StylesheetHelpers.IncludedInSinglelineComment(currentLine, localNodePosition)) { int nextPosition = (endLinePosition < endPosition) ? endLinePosition + 1 : endPosition; ProcessOtherContent(contentBuilder, assetContent, ref currentPosition, nextPosition); continue; } if (nodeType == LessNodeType.ImportRule) { GroupCollection importRuleGroups = match.Groups; string url = importRuleGroups["url"].Value.Trim(); string quote = importRuleGroups["quote"].Success ? importRuleGroups["quote"].Value : @""""; string typeList = importRuleGroups["typeList"].Value; IList<string> types = Utils.ConvertToStringCollection(typeList, ',', trimItemValues: true, removeEmptyItems: true); LessImport processedImport; string importRule = match.Value; string processedImportRule = ProcessImportRule(assetUrl, url, types, quote, out processedImport); if (processedImport != null) { var imports = stylesheet.Imports; LessImportOptions importOptions = processedImport.ImportOptions; string urlInUpperCase = processedImport.Url.ToUpperInvariant(); if (imports.Count(i => i.Url.ToUpperInvariant() == urlInUpperCase && i.ImportOptions == importOptions) == 0) { imports.Add(processedImport); } } contentBuilder.Append(processedImportRule); currentPosition += importRule.Length; } else if (nodeType == LessNodeType.DataUriFunction) { GroupCollection dataUriFunctionGroups = match.Groups; string url = dataUriFunctionGroups["url"].Value.Trim(); string mimeType = dataUriFunctionGroups["mimeType"].Value; string processedDataUriFunctionAssetUrl; string dataUriFunction = match.Value; string processedDataUriFunction = ProcessDataUriFunction(assetUrl, url, mimeType, out processedDataUriFunctionAssetUrl); if (!string.IsNullOrWhiteSpace(processedDataUriFunctionAssetUrl)) { var dataUriFunctionAssetUrls = stylesheet.DataUriFunctionAssetUrls; string urlInUpperCase = processedDataUriFunctionAssetUrl.ToUpperInvariant(); if (dataUriFunctionAssetUrls.Count(u => u.ToUpperInvariant() == urlInUpperCase) == 0) { dataUriFunctionAssetUrls.Add(processedDataUriFunctionAssetUrl); } } contentBuilder.Append(processedDataUriFunction); currentPosition += dataUriFunction.Length; } else if (nodeType == LessNodeType.UrlRule) { GroupCollection urlRuleGroups = match.Groups; string url = urlRuleGroups["url"].Value.Trim(); string quote = urlRuleGroups["quote"].Success ? urlRuleGroups["quote"].Value : string.Empty; string urlRule = match.Value; string processedUrlRule = ProcessUrlRule(assetUrl, url, quote); contentBuilder.Append(processedUrlRule); currentPosition += urlRule.Length; } } else if (nodeType == LessNodeType.MultilineComment) { int nextPosition = nodePosition + match.Length; ProcessOtherContent(contentBuilder, assetContent, ref currentPosition, nextPosition); } } if (currentPosition > 0 && currentPosition <= endPosition) { ProcessOtherContent(contentBuilder, assetContent, ref currentPosition, endPosition + 1); } stylesheet.Content = contentBuilder.ToString(); return stylesheet; }