/// <summary> /// Constructs a instance of LESS-import /// </summary> /// <param name="url">URL of imported stylesheet file</param> /// <param name="importOptions">Import options</param> public LessImport(string url, LessImportOptions importOptions) { Url = url; ImportOptions = importOptions; }
/// <summary> /// Process a LESS <code>@import</code> rule /// </summary> /// <param name="parentAssetUrl">URL of parent LESS-asset file</param> /// <param name="assetUrl">URL of LESS-asset file</param> /// <param name="assetImportTypes">List of import types</param> /// <param name="quote">Quote</param> /// <param name="processedImport">Processed LESS-import</param> /// <returns>Processed LESS <code>@import</code> rule</returns> private string ProcessImportRule(string parentAssetUrl, string assetUrl, IEnumerable<string> assetImportTypes, string quote, out LessImport processedImport) { string result; processedImport = null; string extension = Path.GetExtension(assetUrl); if (UrlHelpers.StartsWithDataUriScheme(assetUrl)) { result = string.Format(IMPORT_RULE_FORMAT, string.Empty, quote, assetUrl); return result; } if (UrlHelpers.StartsWithProtocol(assetUrl)) { result = string.Format(IMPORT_RULE_FORMAT, string.Empty, quote, assetUrl); processedImport = new LessImport(assetUrl, new LessImportOptions(extension)); return result; } var importOptions = new LessImportOptions(extension); var importTypes = new List<string>(); foreach (string importType in assetImportTypes) { switch (importType) { case Constants.ImportType.Less: importOptions.Less = true; break; case Constants.ImportType.Css: importOptions.Less = false; break; case Constants.ImportType.Multiple: importOptions.Multiple = true; break; case Constants.ImportType.Once: importOptions.Multiple = false; break; case Constants.ImportType.Inline: importOptions.Inline = true; break; case Constants.ImportType.Reference: importOptions.Reference = true; break; case Constants.ImportType.Optional: importOptions.Optional = true; break; } importTypes.Add(importType); } string absoluteUrl = _relativePathResolver.ResolveRelativePath(parentAssetUrl, assetUrl); if (!LessFileExtensionHelpers.IsLess(extension) && !CoreFileExtensionHelpers.IsCss(extension)) { string newExtension; if (importOptions.Less) { newExtension = Constants.FileExtension.Less; } else { newExtension = Core.Constants.FileExtension.Css; importTypes.Remove(newExtension); } absoluteUrl += newExtension; } string typeList = (importTypes.Count > 0) ? string.Format("({0}) ", string.Join(", ", importTypes)) : string.Empty; result = string.Format(IMPORT_RULE_FORMAT, typeList, quote, absoluteUrl); processedImport = new LessImport(absoluteUrl, importOptions); return result; }
/// <summary> /// Gets a LESS-stylesheet by URL /// </summary> /// <param name="assetUrl">URL to asset file</param> /// <param name="assetImportOptions">Import options</param> /// <returns>LESS-stylesheet</returns> private LessStylesheet GetLessStylesheet(string assetUrl, LessImportOptions assetImportOptions) { string key = GenerateLessStylesheetCacheItemKey(assetUrl); LessStylesheet stylesheet; if (_lessStylesheetCache.ContainsKey(key)) { stylesheet = _lessStylesheetCache[key]; } else { string assetContent = _virtualFileSystemWrapper.GetFileTextContent(assetUrl); stylesheet = PreprocessStylesheet(assetContent, assetUrl, assetImportOptions); _lessStylesheetCache.Add(key, stylesheet); } return stylesheet; }
/// <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; }