/// <summary>Gets a unique hash for the input spec.</summary> /// <param name="context">The context.</param> /// <param name="inputSpec">The input spec.</param> /// <returns>The unique hash>.</returns> private static string GetInputSpecHash(IWebGreaseContext context, InputSpec inputSpec) { return (inputSpec.GetFiles(context.Configuration.SourceDirectory) .ToDictionary(f => f.MakeRelativeToDirectory(context.Configuration.SourceDirectory), context.GetFileHash) .ToJson()); }
/// <summary>Initializes a new instance of the <see cref="WebGreaseContext"/> class.</summary> /// <param name="parentContext">The parent context.</param> /// <param name="configFile">The config file.</param> public WebGreaseContext(IWebGreaseContext parentContext, FileInfo configFile) { var configuration = new WebGreaseConfiguration(parentContext.Configuration, configFile); configuration.Validate(); if (configuration.Global.TreatWarningsAsErrors != null && parentContext.Log != null) { parentContext.Log.TreatWarningsAsErrors = configuration.Global.TreatWarningsAsErrors == true; } var parentWebGreaseContext = parentContext as WebGreaseContext; if (parentWebGreaseContext != null) { this.threadedMeasureResults = parentWebGreaseContext.threadedMeasureResults; } this.Initialize( configuration, parentContext.Log, parentContext.Cache, parentContext.Preprocessing, parentContext.SessionStartTime, parentContext.Measure); }
/// <summary>Initializes a new instance of the <see cref="WebGreaseSectionKey"/> class.</summary> /// <param name="context">The context.</param> /// <param name="category">The id.</param> /// <param name="cacheVarByContentItem">The cache var by content item.</param> /// <param name="cacheVarBySetting">The cache var by setting.</param> /// <param name="cacheVarByFileSet">The cache var by file set.</param> /// <param name="uniqueKey">The unique Key.</param> public WebGreaseSectionKey(IWebGreaseContext context, string category, ContentItem cacheVarByContentItem, object cacheVarBySetting, IFileSet cacheVarByFileSet, string uniqueKey = null) { this.Category = category; this.Value = uniqueKey; if (string.IsNullOrWhiteSpace(uniqueKey)) { var varyByFiles = new List <CacheVaryByFile>(); var varyBySettings = new List <string>(); if (cacheVarByContentItem != null) { varyByFiles.Add(CacheVaryByFile.FromFile(context, cacheVarByContentItem)); varyBySettings.Add(cacheVarByContentItem.ResourcePivotKeys.ToJson()); } if (cacheVarByFileSet != null) { varyBySettings.Add(cacheVarByFileSet.ToJson()); } if (context.Configuration.Overrides != null) { varyBySettings.Add(context.Configuration.Overrides.UniqueKey); } varyBySettings.Add(cacheVarBySetting.ToJson(true)); this.Value = CacheSectionFileVersionKey + Delimiter + category + Delimiter + string.Join(Delimiter, varyByFiles.Select(vbf => vbf.Hash).Concat(varyBySettings)); } }
/// <summary>Begins the section, create a new section and returns it.</summary> /// <param name="context">The context.</param> /// <param name="cacheCategory">The cache category.</param> /// <param name="uniqueKey">The unique Key.</param> /// <param name="parentCacheSection">The parent cache section.</param> /// <param name="autoLoad">The auto Load.</param> /// <returns>The <see cref="CacheSection"/>.</returns> public static CacheSection Begin(IWebGreaseContext context, string cacheCategory, string uniqueKey, ICacheSection parentCacheSection = null, bool autoLoad = true) { var cacheSection = new CacheSection { parent = parentCacheSection as CacheSection, cacheCategory = cacheCategory, context = context, UniqueKey = uniqueKey }; cacheSection.absolutePath = context.Cache.GetAbsoluteCacheFilePath(cacheSection.cacheCategory, context.GetValueHash(cacheSection.UniqueKey) + ".cache.json"); if (cacheSection.parent != null) { cacheSection.parent.AddChildCacheSection(cacheSection); } EnsureCachePath(context, cacheCategory); if (autoLoad) { cacheSection.Load(); } return(cacheSection); }
/// <summary>Applies the css validation visitors.</summary> /// <param name="stylesheetNode">The stylesheet node.</param> /// <param name="threadContext">The thread Context.</param> /// <returns>The processed node.</returns> private AstNode ApplyValidation(AstNode stylesheetNode, IWebGreaseContext threadContext) { threadContext.SectionedAction(SectionIdParts.MinifyCssActivity, SectionIdParts.Validate).Execute(() => { // Step # 1 - Remove the Css properties from Ast which need to be excluded (Bridging) if (this.ShouldExcludeProperties) { stylesheetNode = stylesheetNode.Accept(new ExcludePropertyVisitor()); } // Step # 2 - Validate for lower case if (this.ShouldValidateForLowerCase) { stylesheetNode = stylesheetNode.Accept(new ValidateLowercaseVisitor()); } // Step # 3 - Validate for Css hacks which don't work cross browser if (this.HackSelectors != null && this.HackSelectors.Any()) { stylesheetNode = stylesheetNode.Accept(new SelectorValidationOptimizationVisitor(this.HackSelectors, false, true)); } // Step # 4 - Remove any banned selectors which are exposed for page efficiency if (this.BannedSelectors != null && this.BannedSelectors.Any()) { stylesheetNode = stylesheetNode.Accept(new SelectorValidationOptimizationVisitor(this.BannedSelectors, false, false)); } }); return(stylesheetNode); }
/// <summary>Gets the md5 hash for the current content item.</summary> /// <param name="context">The context.</param> /// <returns>The md5 hash as a string.</returns> internal string GetContentHash(IWebGreaseContext context) { return(this.contentHash ?? (this.contentHash = ContentItemType == ContentItemType.Value ? context.GetValueHash(this.Content) : context.GetFileHash(this.AbsoluteContentPath))); }
/// <summary>Creates a <see cref="CacheVaryByFile"/> from a file.</summary> /// <param name="context">The context.</param> /// <param name="contentItem">The result file.</param> /// <returns>The <see cref="CacheVaryByFile"/>.</returns> public static CacheVaryByFile FromFile(IWebGreaseContext context, ContentItem contentItem) { return(new CacheVaryByFile { Path = contentItem.RelativeContentPath, Hash = contentItem.GetContentHash(context) }); }
/// <summary>The ensure cache path.</summary> /// <param name="context">The context.</param> /// <param name="cacheCategory">The cache category.</param> private static void EnsureCachePath(IWebGreaseContext context, string cacheCategory) { var cachePath = context.Cache.GetAbsoluteCacheFilePath(cacheCategory, string.Empty); if (!Directory.Exists(cachePath)) { Directory.CreateDirectory(cachePath); } }
/// <summary>Assembles the background images</summary> /// <param name="stylesheetNode">the style sheet node</param> /// <param name="dpi">The dpi.</param> /// <param name="threadContext">The thread Context.</param> /// <param name="spritedImageContentItems">The sprited Image Content Items.</param> /// <returns>The stylesheet node with the sprited images aplied.</returns> private AstNode SpriteBackgroundImages(AstNode stylesheetNode, float dpi, IWebGreaseContext threadContext, BlockingCollection <ContentItem> spritedImageContentItems) { // The image assembly is a 3 step process: // 1. Scan the Css followed by Pretty Print // 2. Run the image assembly tool // 3. Update the Css with generated images followed by Pretty Print return(threadContext.SectionedAction(SectionIdParts.MinifyCssActivity, SectionIdParts.Spriting).Execute(() => { // Execute the pipeline for image assembly scan var scanLog = this.ExecuteImageAssemblyScan(stylesheetNode, threadContext); // Execute the pipeline for image assembly tool var imageMaps = new List <ImageLog>(); var count = 0; foreach (var scanOutput in scanLog.ImageAssemblyScanOutputs) { var spriteResult = this.SpriteImageFromLog(scanOutput, this.ImageAssembleScanDestinationFile + (count == 0 ? string.Empty : "." + count) + ".xml", scanLog.ImageAssemblyAnalysisLog, threadContext, spritedImageContentItems); if (spriteResult != null) { imageMaps.Add(spriteResult); count++; } } // Step # 8 - Execute the pipeline for image assembly update stylesheetNode = this.ExecuteImageAssemblyUpdate(stylesheetNode, imageMaps, dpi); if (!string.IsNullOrWhiteSpace(this.ImageSpritingLogPath)) { scanLog.ImageAssemblyAnalysisLog.Save(this.ImageSpritingLogPath); } var imageAssemblyAnalysisLog = scanLog.ImageAssemblyAnalysisLog; if (this.ErrorOnInvalidSprite && imageAssemblyAnalysisLog.FailedSprites.Any()) { foreach (var failedSprite in imageAssemblyAnalysisLog.FailedSprites) { var failureMessage = ImageAssemblyAnalysisLog.GetFailureMessage(failedSprite); if (!string.IsNullOrWhiteSpace(failedSprite.Image)) { threadContext.Log.Error( "Failed to sprite image {0}\r\nReason:{1}\r\nCss:{2}".InvariantFormat( failedSprite.Image, failureMessage, failedSprite.AstNode.PrettyPrint())); } else { threadContext.Log.Error( "Failed to sprite:{0}\r\nReason:{1}".InvariantFormat( failedSprite.Image, failureMessage)); } } } return stylesheetNode; })); }
/// <summary>This method will be called to check if the processor believes it can handle the file based on the filename.</summary> /// <param name="context">The context.</param> /// <param name="contentItem">The full path to the file.</param> /// <param name="preprocessConfig">The configuration</param> /// <returns>If it thinks it can process it.</returns> public bool CanProcess(IWebGreaseContext context, ContentItem contentItem, PreprocessingConfig preprocessConfig = null) { var sassConfig = GetConfig(preprocessConfig); var extension = Path.GetExtension(contentItem.RelativeContentPath); return (extension != null && (extension.EndsWith(sassConfig.SassExtension, StringComparison.OrdinalIgnoreCase) || extension.EndsWith(sassConfig.ScssExtension, StringComparison.OrdinalIgnoreCase))); }
/// <summary>Resource Manager factory.</summary> /// <param name="context">The webgrease context</param> /// <param name="inputContentDirectory">The base Resources Directory.</param> /// <param name="resourceGroupKey">The resource type.</param> /// <param name="applicationDirectoryName">The modules Aggregation Directory Name.</param> /// <param name="siteName">The site name</param> /// <param name="resourceKeys">The resource keys for which the resources will be compressed.</param> /// <param name="outputDirectoryPath">Output folder to write the resource files on hard drive.</param> /// <returns>A new instance of Resource Manager class.</returns> internal static ResourcesResolver Factory( IWebGreaseContext context, string inputContentDirectory, string resourceGroupKey, string applicationDirectoryName, string siteName, IEnumerable <string> resourceKeys, string outputDirectoryPath) { return(new ResourcesResolver(context, inputContentDirectory, resourceGroupKey, applicationDirectoryName, siteName, resourceKeys, outputDirectoryPath)); }
private static bool HasCachedEndResultThatChanged(IWebGreaseContext context, CacheResult r) { if (r == null) { return(true); } var absoluteEndResultPath = Path.Combine(context.Configuration.DestinationDirectory, r.RelativeHashedContentPath ?? r.RelativeContentPath); return(!File.Exists(absoluteEndResultPath) || !r.ContentHash.Equals(context.GetFileHash(absoluteEndResultPath))); }
/// <summary>Processes css files for images to merge (sprite)</summary> /// <param name="context">The context.</param> private static void ExecuteImageSpriting(IWebGreaseContext context) { // whiles this uses the minification activity, it is only assembling images var spriter = new MinifyCssActivity(context) { ShouldMinify = false, ShouldOptimize = false, ShouldAssembleBackgroundImages = true }; foreach (var fileSet in context.Configuration.CssFileSets.Where(file => file.InputSpecs.Any())) { // for each file set, get the configuration and setup the assembler object. var spriteConfig = fileSet.ImageSpriting.GetNamedConfig(context.Configuration.ConfigType); if (spriteConfig.ShouldAutoSprite) { var outputPath = GetOutputFolder(fileSet.Output, context.Configuration.DestinationDirectory); var directoryName = string.IsNullOrWhiteSpace(Path.GetExtension(outputPath)) ? outputPath : Path.GetDirectoryName(outputPath); spriter.ShouldAssembleBackgroundImages = spriteConfig.ShouldAutoSprite; spriter.ImageAssemblyPadding = spriteConfig.ImagePadding; spriter.ImageAssembleReferencesToIgnore.Clear(); foreach (var image in spriteConfig.ImagesToIgnore) { spriter.ImageAssembleReferencesToIgnore.Add(image); } // run the spriter on every file in each of the input specs foreach (var source in fileSet.InputSpecs.SelectMany(inputSpec => GetFiles(inputSpec.Path, inputSpec.SearchPattern, inputSpec.SearchOption))) { spriter.SourceFile = source; spriter.DestinationFile = Path.Combine(directoryName, Path.GetFileName(source)); spriter.ImagesOutputDirectory = Path.IsPathRooted(spriteConfig.DestinationImageFolder) ? spriteConfig.DestinationImageFolder : Path.Combine(directoryName, spriteConfig.DestinationImageFolder); var file = Path.GetFileNameWithoutExtension(spriter.DestinationFile); var scanFilePath = Path.Combine(directoryName, Path.GetFileNameWithoutExtension(file) + ".scan." + Strings.Css); spriter.ImageAssembleScanDestinationFile = scanFilePath; try { spriter.Execute(); } catch (WorkflowException ex) { HandleError(ex.InnerException ?? ex, source); } } } } }
/// <summary>The handle other content type cache sections.</summary> /// <param name="context">The context.</param> /// <param name="parentCacheSection">The session cache section.</param> /// <param name="sessionCacheData">The session cache data.</param> /// <param name="contentTypeSectionId">The content type section id.</param> private void HandleOtherContentTypeCacheSections(IWebGreaseContext context, ICacheSection parentCacheSection, SessionCacheData sessionCacheData, string[] contentTypeSectionId) { if (sessionCacheData != null) { foreach (var configType in sessionCacheData.ConfigTypes.Keys.Where(ct => !ct.Equals(this.ConfigType, StringComparison.OrdinalIgnoreCase))) { // TODO: Do a better job at touching all the files used by the last build from another config type. var otherContentTypeCacheSection = CacheSection.Begin(context, WebGreaseContext.ToStringId(contentTypeSectionId), sessionCacheData.GetConfigTypeUniqueKey(configType), parentCacheSection); otherContentTypeCacheSection.Save(); } } }
/// <summary>The from result file.</summary> /// <param name="context">The context.</param> /// <param name="cacheCategory">The cache category.</param> /// <param name="endResult">The end result.</param> /// <param name="fileCategory">The file category.</param> /// <param name="contentItem">The result file.</param> /// <returns>The <see cref="CacheResult"/>.</returns> public static CacheResult FromContentFile(IWebGreaseContext context, string cacheCategory, bool endResult, string fileCategory, ContentItem contentItem) { return(new CacheResult { EndResult = endResult, FileCategory = fileCategory, CachedFilePath = context.Cache.StoreInCache(cacheCategory, contentItem), ContentHash = contentItem.GetContentHash(context), RelativeContentPath = contentItem.RelativeContentPath, RelativeHashedContentPath = contentItem.RelativeHashedContentPath, }); }
/// <summary>Execute a single config file.</summary> /// <param name="sessionContext">The session context.</param> /// <param name="configFile">The config file.</param> /// <param name="activity">The activity</param> /// <param name="fileType">The file types</param> /// <param name="measure">If it should measure.</param> /// <param name="fullPathToConfigFiles">The full Path To Config Files.</param> /// <returns>The success.</returns> private static Tuple <bool, int> ExecuteConfigFile(IWebGreaseContext sessionContext, string configFile, ActivityName activity, FileTypes fileType, bool measure, string fullPathToConfigFiles) { var configFileStart = DateTimeOffset.Now; var configFileInfo = new FileInfo(configFile); // Creates the context specific to the configuration file var fileContext = new WebGreaseContext(sessionContext, configFileInfo); var configFileSuccess = true; var fileSets = GetFileSets(fileContext.Configuration, fileType).ToArray(); if (fileSets.Length > 0 || (fileType.HasFlag(FileTypes.Image) && fileContext.Configuration.ImageDirectoriesToHash.Any())) { var configFileContentItem = ContentItem.FromFile(configFileInfo.FullName); configFileSuccess = sessionContext .SectionedActionGroup(fileType.ToString(), SectionIdParts.WebGreaseBuildTask, SectionIdParts.ConfigurationFile) .MakeCachable(configFileContentItem, new { activity, fileContext.Configuration }, activity == ActivityName.Bundle) // Cached action can only be skipped when it is the bundle activity, otherwise don't. .Execute(configFileCacheSection => { fileContext.Configuration.AllLoadedConfigurationFiles.ForEach(configFileCacheSection.AddSourceDependency); var success = true; fileContext.Log.Information("Activity Start: [{0}] for [{1}] on configuration file \"{2}\"".InvariantFormat(activity, fileType, configFile), MessageImportance.High); switch (activity) { case ActivityName.Bundle: // execute the bundle pipeline var bundleActivity = new BundleActivity(fileContext); success &= bundleActivity.Execute(fileSets); break; case ActivityName.Everything: // execute the full pipeline var everythingActivity = new EverythingActivity(fileContext); success &= everythingActivity.Execute(fileSets, fileType); break; } if (success && measure) { var configReportFile = Path.Combine(sessionContext.Configuration.ReportPath, (configFileInfo.Directory != null ? configFileInfo.Directory.Name + "." : string.Empty) + activity.ToString() + "." + fileType + "." + configFileInfo.Name); fileContext.Measure.WriteResults(configReportFile, configFileInfo.FullName, configFileStart); } fileContext.Log.Information("Activity End: [{0}] for [{1}] on configuration file \"{2}\"".InvariantFormat(activity, fileType, configFile), MessageImportance.High); return(success); }); } return(Tuple.Create(configFileSuccess, fileSets.Length)); }
/// <summary>Initializes a new instance of the <see cref="CssMinifier"/> class with default settings.</summary> /// <param name="context">The context.</param> public CssMinifier(IWebGreaseContext context) { this.CssActivity = new MinifyCssActivity(context) { ShouldMinify = true, ShouldOptimize = true, ShouldValidateForLowerCase = false, ShouldExcludeProperties = false, ShouldAssembleBackgroundImages = false }; this.ShouldMinify = true; this.Errors = new List <string>(); }
private ReadOnlyCacheSection(string jsonString, IWebGreaseContext context) { this.context = context; var json = JObject.Parse(jsonString); this.sourceDependencies = json["sourceDependencies"].ToString().FromJson <IEnumerable <CacheSourceDependency> >(true); this.cacheResults = json["cacheResults"].ToString().FromJson <IEnumerable <CacheResult> >(true); this.childCacheSectionFiles = json["children"].AsEnumerable().Select(f => (string)f); this.absolutePath = (string)json["absolutePath"]; }
/// <summary>The create sprited images.</summary> /// <param name="mapXmlFile">The map xml file.</param> /// <param name="imageAssemblyAnalysisLog">The image assembly analysis log.</param> /// <param name="imageReferencesToAssemble">The image references to assemble.</param> /// <param name="cacheSection">The cache section.</param> /// <param name="results">The results.</param> /// <param name="threadContext">The thread Context.</param> /// <returns>The <see cref="bool"/>.</returns> private ImageLog CreateSpritedImages( string mapXmlFile, ImageAssemblyAnalysisLog imageAssemblyAnalysisLog, IEnumerable <InputImage> imageReferencesToAssemble, ICacheSection cacheSection, BlockingCollection <ContentItem> results, IWebGreaseContext threadContext) { if (!Directory.Exists(this.ImagesOutputDirectory)) { Directory.CreateDirectory(this.ImagesOutputDirectory); } var imageMap = ImageAssembleGenerator.AssembleImages( imageReferencesToAssemble.ToSafeReadOnlyCollection(), SpritePackingType.Vertical, this.ImagesOutputDirectory, string.Empty, true, threadContext, this.ImageAssemblyPadding, imageAssemblyAnalysisLog, this.ForcedSpritingImageType); if (imageMap == null || imageMap.Document == null) { return(null); } var destinationDirectory = threadContext.Configuration.DestinationDirectory; if (!string.IsNullOrWhiteSpace(this.ImageAssembleScanDestinationFile)) { var scanXml = imageMap.Document.ToString(); FileHelper.WriteFile(mapXmlFile, scanXml); cacheSection.AddResult(ContentItem.FromFile(mapXmlFile), CacheFileCategories.SpriteLogFileXml); } var imageLog = new ImageLog(imageMap.Document); cacheSection.AddResult(ContentItem.FromContent(imageLog.ToJson(true)), CacheFileCategories.SpriteLogFile); foreach (var spritedFile in imageLog.InputImages.Select(il => il.OutputFilePath).Distinct()) { var spritedImageContentItem = ContentItem.FromFile(spritedFile, spritedFile.MakeRelativeToDirectory(destinationDirectory)); results.Add(spritedImageContentItem); cacheSection.AddResult(spritedImageContentItem, CacheFileCategories.HashedSpriteImage); } return(imageLog); }
/// <summary>The dispose method, cleans up references and objects.</summary> private void Dispose() { if (this.cachedSection != null) { this.cachedSection.Dispose(); } this.context = null; this.parent = null; this.sourceDependencies.Clear(); this.ChildCacheSections.Clear(); this.childCacheSections = null; this.cacheResults.Clear(); }
/// <summary>Initializes a new instance of the <see cref="MinifyCssActivity"/> class.</summary> /// <param name="context">The context.</param> internal MinifyCssActivity(IWebGreaseContext context) { this.context = context; this.HackSelectors = new HashSet <string>(); this.BannedSelectors = new HashSet <string>(); this.ShouldExcludeProperties = true; this.ShouldValidateForLowerCase = false; this.ShouldOptimize = true; this.ShouldAssembleBackgroundImages = true; this.ImageAssembleReferencesToIgnore = new HashSet <string>(); this.OutputUnitFactor = 1; this.ShouldPreventOrderBasedConflict = false; this.ShouldMergeBasedOnCommonDeclarations = false; }
/// <summary> /// Executes the minification task /// </summary> /// <param name="context">context with settings to be used. Only used for the input/output settings.</param> private static void ExecuteMinification(IWebGreaseContext context) { var jsCruncher = new MinifyJSActivity(context); var cssCruncher = new MinifyCssActivity(context); // only run the crunchers if the configuration has files for that particular file type foreach (var fileSet in context.Configuration.JSFileSets.Where(set => set.InputSpecs.Any())) { ProcessJsFileSet(jsCruncher, fileSet, context.Configuration.ConfigType, context.Configuration.DestinationDirectory); } // do the same thing for CSS files... nested loops are fun! foreach (var fileSet in context.Configuration.CssFileSets.Where(set => set.InputSpecs.Any())) { ProcessCssFileSet(cssCruncher, fileSet, context.Configuration.ConfigType, context.Configuration.DestinationDirectory); } }
/// <summary>Determines if the processor can parse the filetype, always true for this engine.</summary> /// <param name="context">The context.</param> /// <param name="contentItem">The full filename</param> /// <param name="preprocessConfig">The pre processing config</param> /// <returns>True if it can process it, otherwise false.</returns> public bool CanProcess(IWebGreaseContext context, ContentItem contentItem, PreprocessingConfig preprocessConfig = null) { if (preprocessConfig != null && preprocessConfig.Element != null) { var extensions = (string)preprocessConfig.Element.Attribute("wgincludeextensions") ?? (string)preprocessConfig.Element.Element("wgincludeextensions"); if (!string.IsNullOrWhiteSpace(extensions)) { return(extensions .Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) .Any(wgIncludeExtension => contentItem.RelativeContentPath.EndsWith(wgIncludeExtension, StringComparison.OrdinalIgnoreCase))); } } return(true); }
/// <summary>Applies the css optimization visitors.</summary> /// <param name="stylesheetNode">The stylesheet node.</param> /// <param name="threadContext">The thread Context.</param> /// <returns>The processed node.</returns> private AstNode ApplyOptimization(AstNode stylesheetNode, IWebGreaseContext threadContext) { // Step # 5 - Run the Css optimization visitors if (this.ShouldOptimize) { threadContext.SectionedAction(SectionIdParts.MinifyCssActivity, SectionIdParts.Optimize).Execute( () => { stylesheetNode = stylesheetNode.Accept(new OptimizationVisitor { ShouldMergeMediaQueries = this.ShouldMergeMediaQueries, ShouldPreventOrderBasedConflict = this.ShouldPreventOrderBasedConflict, ShouldMergeBasedOnCommonDeclarations = this.ShouldMergeBasedOnCommonDeclarations, NonMergeRuleSetSelectors = this.NonMergeSelectors }); stylesheetNode = stylesheetNode.Accept(new ColorOptimizationVisitor()); stylesheetNode = stylesheetNode.Accept(new FloatOptimizationVisitor()); }); } return(stylesheetNode); }
/// <summary>Parse the styleSheet.</summary> /// <param name="cssContent">The css content.</param> /// <param name="shouldLogDiagnostics">The should log diagnostics.</param> /// <returns>The styleSheet node.</returns> private static StyleSheetNode ParseStyleSheet(IWebGreaseContext context, string cssContent, bool shouldLogDiagnostics) { var lexer = new CssLexer(new ANTLRStringStream(cssContent)); var tokenStream = new CommonTokenStream(lexer); var parser = new CssParser(tokenStream); var commonTree = context .SectionedAction("CssParser", "Antlr") .Execute(() => { // Assign listener to parser. if (shouldLogDiagnostics) { var listener = Trace.Listeners.OfType <TextWriterTraceListener>().FirstOrDefault(); if (listener != null) { parser.TraceDestination = listener.Writer; } } var styleSheet = parser.main(); return(styleSheet.Tree as CommonTree); }); if (commonTree != null) { return(context.SectionedAction("CssParser", "CreateObjects").Execute(() => { if (shouldLogDiagnostics) { LogDiagnostics(cssContent, commonTree); } if (parser.NumberOfSyntaxErrors > 0) { throw new AggregateException("Syntax errors found.", parser._exceptions); } return CommonTreeTransformer.CreateStyleSheetNode(commonTree); })); } return(null); }
/// <summary>The load.</summary> /// <param name="fullPath">The full path.</param> /// <param name="context">The context.</param> /// <returns>The <see cref="CacheSection"/>.</returns> internal static ReadOnlyCacheSection Load(string fullPath, IWebGreaseContext context) { if (!File.Exists(fullPath)) { return(null); } return(Safe.Lock(LoadLock, () => { ReadOnlyCacheSection cacheSection; if (!context.Cache.LoadedCacheSections.TryGetValue(fullPath, out cacheSection)) { cacheSection = new ReadOnlyCacheSection(File.ReadAllText(fullPath), context); context.Cache.LoadedCacheSections.Add(fullPath, cacheSection); } cacheSection.referenceCount++; return cacheSection; })); }
/// <summary>The unload.</summary> /// <param name="context">the context</param> /// <param name="fullPath">The full path.</param> /// <returns>The <see cref="bool"/>.</returns> private static bool Unload(IWebGreaseContext context, string fullPath) { return(Safe.Lock(LoadLock, () => { ReadOnlyCacheSection cacheSection; if (context.Cache.LoadedCacheSections.TryGetValue(fullPath, out cacheSection)) { cacheSection.referenceCount--; if (cacheSection.referenceCount == 0) { context.Cache.LoadedCacheSections.Remove(fullPath); } else { return false; } } return true; })); }
/// <summary>Registers available Image Assemblers.</summary> /// <param name="context">The global web grease context.</param> /// <returns>Dictionary of registered image assembler for file extension</returns> private static IEnumerable <ImageAssembleBase> RegisterAvailableAssemblers(IWebGreaseContext context) { var registeredAssemblers = new List <ImageAssembleBase>(); var notSupportedAssemble = new NotSupportedAssemble(context); registeredAssemblers.Add(notSupportedAssemble); var photoAssemble = new PhotoAssemble(context); registeredAssemblers.Add(photoAssemble); var nonphotoNonindexedAssemble = new NonphotoNonindexedAssemble(context); registeredAssemblers.Add(nonphotoNonindexedAssemble); var nonphotoIndexedAssemble = new NonphotoIndexedAssemble(context); registeredAssemblers.Add(nonphotoIndexedAssemble); return(registeredAssemblers); }
internal void Dispose() { if (this.disposed) { throw new BuildWorkflowException("Cannot dispose an object twice."); } if (Unload(this.context, this.absolutePath)) { this.disposed = true; if (this.childCacheSections != null) { this.childCacheSections.Where(ccs => ccs != null).ForEach(ccs => ccs.Dispose()); } this.context = null; this.cacheResults = null; this.sourceDependencies = null; this.childCacheSections = null; this.childCacheSectionFiles = null; } }
/// <summary>Processed the contents of the file and returns the processed content. /// returns null if anything went wrong, and reports any errors through the lot delegates.</summary> /// <param name="context">The context.</param> /// <param name="contentItem">The content of the file.</param> /// <param name="preprocessingConfig">The pre processing configuration</param> /// <param name="minimalOutput">Is the goal to have the most minimal output (true skips lots of comments)</param> /// <returns>The processed contents or null of an error occurred.</returns> public ContentItem Process(IWebGreaseContext context, ContentItem contentItem, PreprocessingConfig preprocessingConfig, bool minimalOutput) { var settingsMinimalOutput = preprocessingConfig != null && preprocessingConfig.Element != null && (bool?)preprocessingConfig.Element.Attribute("minimalOutput") == true; context.SectionedAction(SectionIdParts.Preprocessing, SectionIdParts.Process, "WgInclude") .MakeCachable(contentItem, new { minimalOutput }) .Execute(wgincludeCacheImportsSection => { var workingFolder = context.GetWorkingSourceDirectory(contentItem.RelativeContentPath); var content = contentItem.Content; if (string.IsNullOrWhiteSpace(content)) { return(true); } content = IncludeRegex.Replace(content, match => ReplaceInputs(match, workingFolder, wgincludeCacheImportsSection, minimalOutput || settingsMinimalOutput)); contentItem = ContentItem.FromContent(content, contentItem); return(true); }); return(contentItem); }