diff --git a/SquishIt.Framework/Base/BundleBase.Rendering.cs b/SquishIt.Framework/Base/BundleBase.Rendering.Internals.cs similarity index 57% rename from SquishIt.Framework/Base/BundleBase.Rendering.cs rename to SquishIt.Framework/Base/BundleBase.Rendering.Internals.cs index 1eb2518..2368959 100644 --- a/SquishIt.Framework/Base/BundleBase.Rendering.cs +++ b/SquishIt.Framework/Base/BundleBase.Rendering.Internals.cs @@ -1,32 +1,24 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Web; -using SquishIt.Framework.Resolvers; -using SquishIt.Framework.Renderers; using SquishIt.Framework.Files; +using SquishIt.Framework.Renderers; +using SquishIt.Framework.Resolvers; using SquishIt.Framework.Utilities; -using System.IO; namespace SquishIt.Framework.Base { public abstract partial class BundleBase where T : BundleBase { - protected IRenderer GetFileRenderer() - { - return debugStatusReader.IsDebuggingEnabled() ? new FileRenderer(fileWriterFactory) : - releaseFileRenderer ?? - Configuration.Instance.DefaultReleaseRenderer() ?? - new FileRenderer(fileWriterFactory); - } - - private List GetFiles(List assets) + List GetFiles(List assets) { var inputFiles = GetInputFiles(assets); var resolvedFilePaths = new List(); - foreach(Input input in inputFiles) + foreach (var input in inputFiles) { resolvedFilePaths.AddRange(input.TryResolve(allowedExtensions, disallowedExtensions)); } @@ -34,16 +26,16 @@ private List GetFiles(List assets) return resolvedFilePaths; } - private Input GetInputFile(Asset asset) + Input GetInputFile(Asset asset) { - if(!asset.IsEmbeddedResource) + if (!asset.IsEmbeddedResource) { - if(debugStatusReader.IsDebuggingEnabled()) + if (debugStatusReader.IsDebuggingEnabled()) { return GetFileSystemPath(asset.LocalPath, asset.IsRecursive); } - if(asset.IsRemoteDownload) + if (asset.IsRemoteDownload) { return GetHttpPath(asset.RemotePath); } @@ -58,28 +50,28 @@ private Input GetInputFile(Asset asset) } } - private List GetInputFiles(List assets) + List GetInputFiles(List assets) { var inputFiles = new List(); - foreach(var asset in assets) + foreach (var asset in assets) { inputFiles.Add(GetInputFile(asset)); } return inputFiles; } - private Input GetFileSystemPath(string localPath, bool isRecursive = true) + Input GetFileSystemPath(string localPath, bool isRecursive = true) { string mappedPath = FileSystem.ResolveAppRelativePathToFileSystem(localPath); return new Input(mappedPath, isRecursive, ResolverFactory.Get()); } - private Input GetHttpPath(string remotePath) + Input GetHttpPath(string remotePath) { return new Input(remotePath, false, ResolverFactory.Get()); } - private Input GetEmbeddedResourcePath(string resourcePath) + Input GetEmbeddedResourcePath(string resourcePath) { return new Input(resourcePath, false, ResolverFactory.Get()); } @@ -94,8 +86,6 @@ protected IEnumerable FindPreprocessors(string file) .Where(p => p != null); } - protected abstract string ProcessFile(string file, string outputFile); - protected string PreprocessFile(string file, IEnumerable preprocessors) { try @@ -112,30 +102,30 @@ protected string PreprocessFile(string file, IEnumerable preproce } } - protected string PreprocessContent(string file, IEnumerable preprocessors, string content) + string PreprocessContent(string file, IEnumerable preprocessors, string content) { - if(preprocessors == null) + if (preprocessors == null) { return content; } - return preprocessors.Aggregate(content, (cntnt, pp) => pp.Process(file, cntnt)); + return preprocessors.Aggregate(content, (cntnt, pp) => pp.Process(file, cntnt)); } IPreprocessor FindPreprocessor(string extension) { - var instanceTypes = instancePreprocessors.Select(ipp => ipp.GetType()).ToArray(); + var instanceTypes = bundleState.Preprocessors.Select(ipp => ipp.GetType()).ToArray(); return Bundle.Preprocessors.Where(pp => !instanceTypes.Contains(pp.GetType())) - .Union(instancePreprocessors) + .Union(bundleState.Preprocessors.Where(pp => pp.Extensions.Any(ext => allowedExtensions.Contains(ext)))) .FirstOrDefault(p => p.ValidFor(extension)); } - private string ExpandAppRelativePath(string file) + string ExpandAppRelativePath(string file) { - if(file.StartsWith("~/")) + if (file.StartsWith("~/")) { string appRelativePath = HttpRuntime.AppDomainAppVirtualPath; - if(appRelativePath != null && !appRelativePath.EndsWith("/")) + if (appRelativePath != null && !appRelativePath.EndsWith("/")) appRelativePath += "/"; return file.Replace("~/", appRelativePath); } @@ -144,21 +134,21 @@ private string ExpandAppRelativePath(string file) protected string ReadFile(string file) { - using(var sr = fileReaderFactory.GetFileReader(file)) + using (var sr = fileReaderFactory.GetFileReader(file)) { return sr.ReadToEnd(); } } - protected bool FileExists(string file) + bool FileExists(string file) { return fileReaderFactory.FileExists(file); } - private string GetAdditionalAttributes(BundleState bundleState) + string GetAdditionalAttributes(BundleState bundleState) { var result = new StringBuilder(); - foreach(var attribute in bundleState.Attributes) + foreach (var attribute in bundleState.Attributes) { result.Append(attribute.Key); result.Append("=\""); @@ -168,10 +158,10 @@ private string GetAdditionalAttributes(BundleState bundleState) return result.ToString(); } - private string GetFilesForRemote(List remoteAssetPaths, BundleState bundleState) + string GetFilesForRemote(List remoteAssetPaths, BundleState bundleState) { var sb = new StringBuilder(); - foreach(var uri in remoteAssetPaths) + foreach (var uri in remoteAssetPaths) { sb.Append(FillTemplate(bundleState, uri)); } @@ -179,51 +169,38 @@ private string GetFilesForRemote(List remoteAssetPaths, BundleState bund return sb.ToString(); } - private void AddAsset(Asset asset) - { - bundleState.Assets.Add(asset); - } - - public T WithoutTypeAttribute() - { - this.typeless = true; - return (T)this; - } - string BuildAbsolutePath(string siteRelativePath) { - if(HttpContext.Current == null) - throw new InvalidOperationException("Absolute path can only be constructed in the presence of an HttpContext."); - if(!siteRelativePath.StartsWith("/")) + if (HttpContext.Current == null) + throw new InvalidOperationException( + "Absolute path can only be constructed in the presence of an HttpContext."); + if (!siteRelativePath.StartsWith("/")) throw new InvalidOperationException("This helper method only works with site relative paths."); var url = HttpContext.Current.Request.Url; var port = url.Port != 80 ? (":" + url.Port) : String.Empty; - return string.Format("{0}://{1}{2}{3}", url.Scheme, url.Host, port, VirtualPathUtility.ToAbsolute(siteRelativePath)); + return string.Format("{0}://{1}{2}{3}", url.Scheme, url.Host, port, + VirtualPathUtility.ToAbsolute(siteRelativePath)); } - public string Render(string renderTo) + string Render(string renderTo, string key, IRenderer renderer) { - string key = renderTo; - return Render(renderTo, key, GetFileRenderer()); - } - - private string Render(string renderTo, string key, IRenderer renderer) - { - var cacheUniquenessHash = key.Contains("#") ? hasher.GetHash(bundleState.Assets - .Select(a => a.IsRemote ? a.RemotePath : a.LocalPath) - .Union(bundleState.Arbitrary.Select(ac => ac.Content)) - .OrderBy(s => s) - .Aggregate((acc, val) => acc + val)) : string.Empty; + var cacheUniquenessHash = key.Contains("#") + ? hasher.GetHash(bundleState.Assets + .Select(a => a.IsRemote ? a.RemotePath : a.LocalPath) + .Union(bundleState.Arbitrary.Select(ac => ac.Content)) + .OrderBy(s => s) + .Aggregate((acc, val) => acc + val)) + : string.Empty; key = CachePrefix + key + cacheUniquenessHash; - if(!String.IsNullOrEmpty(BaseOutputHref)) + if (!String.IsNullOrEmpty(BaseOutputHref)) { key = BaseOutputHref + key; } - if(debugStatusReader.IsDebuggingEnabled()) + if (debugStatusReader.IsDebuggingEnabled()) { var content = RenderDebug(renderTo, key, renderer); return content; @@ -231,60 +208,25 @@ private string Render(string renderTo, string key, IRenderer renderer) return RenderRelease(key, renderTo, renderer); } - public string RenderNamed(string name) + BundleState GetCachedBundleState(string name) { - bundleState = GetCachedBundleState(name); - //TODO: this sucks - // Revisit https://github.com/jetheredge/SquishIt/pull/155 and https://github.com/jetheredge/SquishIt/issues/183 - //hopefully we can find a better way to satisfy both of these requirements - var fullName = (BaseOutputHref ?? "") + CachePrefix + name; - var content = bundleCache.GetContent(fullName); - if(content == null) + var bundle = bundleStateCache[CachePrefix + name]; + if (bundle.ForceDebug) { - AsNamed(name, bundleState.Path); - return bundleCache.GetContent(CachePrefix + name); + debugStatusReader.ForceDebug(); } - return content; - } - - public string RenderCached(string name) - { - bundleState = GetCachedBundleState(name); - var content = CacheRenderer.Get(CachePrefix, name); - if(content == null) + if (bundle.ForceRelease) { - AsCached(name, bundleState.Path); - return CacheRenderer.Get(CachePrefix, name); + debugStatusReader.ForceRelease(); } - return content; - } - - public string RenderCachedAssetTag(string name) - { - bundleState = GetCachedBundleState(name); - return Render(null, name, new CacheRenderer(CachePrefix, name)); - } - - public void AsNamed(string name, string renderTo) - { - Render(renderTo, name, GetFileRenderer()); - bundleState.Path = renderTo; - bundleStateCache[CachePrefix + name] = bundleState; - } - - public string AsCached(string name, string filePath) - { - string result = Render(filePath, name, new CacheRenderer(CachePrefix, name)); - bundleState.Path = filePath; - bundleStateCache[CachePrefix + name] = bundleState; - return result; + return bundle; } string RenderDebug(string renderTo, string name, IRenderer renderer) { string content = null; - DependentFiles.Clear(); + bundleState.DependentFiles.Clear(); var renderedFiles = new HashSet(); @@ -294,17 +236,17 @@ string RenderDebug(string renderTo, string name, IRenderer renderer) var attributes = GetAdditionalAttributes(bundleState); var assets = bundleState.Assets; - DependentFiles.AddRange(GetFiles(assets)); - foreach(var asset in assets) + bundleState.DependentFiles.AddRange(GetFiles(assets)); + foreach (var asset in assets) { var inputFile = GetInputFile(asset); var files = inputFile.TryResolve(allowedExtensions, disallowedExtensions); - if(asset.IsEmbeddedResource) + if (asset.IsEmbeddedResource) { var tsb = new StringBuilder(); - foreach(var fn in files) + foreach (var fn in files) { tsb.Append(ReadFile(fn) + "\n\n\n"); } @@ -314,15 +256,15 @@ string RenderDebug(string renderTo, string name, IRenderer renderer) renderer.Render(tsb.ToString(), FileSystem.ResolveAppRelativePathToFileSystem(processedFile)); sb.AppendLine(FillTemplate(bundleState, processedFile)); } - else if(asset.RemotePath != null) + else if (asset.RemotePath != null) { sb.AppendLine(FillTemplate(bundleState, ExpandAppRelativePath(asset.LocalPath))); } else { - foreach(var file in files) + foreach (var file in files) { - if(!renderedFiles.Contains(file)) + if (!renderedFiles.Contains(file)) { var fileBase = FileSystem.ResolveAppRelativePathToFileSystem(asset.LocalPath); var newPath = file.Replace(fileBase, ""); @@ -334,7 +276,7 @@ string RenderDebug(string renderTo, string name, IRenderer renderer) } } - foreach(var cntnt in bundleState.Arbitrary) + foreach (var cntnt in bundleState.Arbitrary) { var filename = "dummy" + cntnt.Extension; var preprocessors = FindPreprocessors(filename); @@ -344,36 +286,36 @@ string RenderDebug(string renderTo, string name, IRenderer renderer) content = sb.ToString(); - if(bundleCache.ContainsKey(name)) + if (bundleCache.ContainsKey(name)) { bundleCache.Remove(name); } - bundleCache.Add(name, content, DependentFiles); + bundleCache.Add(name, content, bundleState.DependentFiles); //need to render the bundle to caches, otherwise leave it - if(renderer is CacheRenderer) + if (renderer is CacheRenderer) renderer.Render(content, renderTo); return content; } - private string RenderRelease(string key, string renderTo, IRenderer renderer) + string RenderRelease(string key, string renderTo, IRenderer renderer) { string content; - if(!bundleCache.TryGetValue(key, out content)) + if (!bundleCache.TryGetValue(key, out content)) { - using(new CriticalRenderingSection(renderTo)) + using (new CriticalRenderingSection(renderTo)) { - if(!bundleCache.TryGetValue(key, out content)) + if (!bundleCache.TryGetValue(key, out content)) { var uniqueFiles = new List(); string minifiedContent = null; string hash = null; bool hashInFileName = false; - DependentFiles.Clear(); + bundleState.DependentFiles.Clear(); - if(renderTo == null) + if (renderTo == null) { renderTo = renderPathCache[CachePrefix + "." + key]; } @@ -385,73 +327,77 @@ private string RenderRelease(string key, string renderTo, IRenderer renderer) string outputFile = FileSystem.ResolveAppRelativePathToFileSystem(renderTo); var renderToPath = ExpandAppRelativePath(renderTo); - if(!String.IsNullOrEmpty(BaseOutputHref)) + if (!String.IsNullOrEmpty(BaseOutputHref)) { renderToPath = String.Concat(BaseOutputHref.TrimEnd('/'), "/", renderToPath.TrimStart('/')); } var remoteAssetPaths = new List(); - foreach(var asset in bundleState.Assets) + foreach (var asset in bundleState.Assets) { - if(asset.IsRemote) + if (asset.IsRemote) { remoteAssetPaths.Add(asset.RemotePath); } } uniqueFiles.AddRange(GetFiles(bundleState.Assets.Where(asset => - asset.IsEmbeddedResource || - asset.IsLocal || - asset.IsRemoteDownload).ToList()).Distinct()); + asset.IsEmbeddedResource || + asset.IsLocal || + asset.IsRemoteDownload).ToList()). + Distinct()); string renderedTag = string.Empty; - if(uniqueFiles.Count > 0 || bundleState.Arbitrary.Count > 0) + if (uniqueFiles.Count > 0 || bundleState.Arbitrary.Count > 0) { - DependentFiles.AddRange(uniqueFiles); + bundleState.DependentFiles.AddRange(uniqueFiles); - if(renderTo.Contains("#")) + if (renderTo.Contains("#")) { hashInFileName = true; - minifiedContent = Minifier.Minify(BeforeMinify(outputFile, uniqueFiles, bundleState.Arbitrary)); + minifiedContent = + Minifier.Minify(BeforeMinify(outputFile, uniqueFiles, bundleState.Arbitrary)); hash = hasher.GetHash(minifiedContent); renderToPath = renderToPath.Replace("#", hash); outputFile = outputFile.Replace("#", hash); } - if(ShouldRenderOnlyIfOutputFileIsMissing && FileExists(outputFile)) + if (bundleState.ShouldRenderOnlyIfOutputFileIsMissing && FileExists(outputFile)) { minifiedContent = ReadFile(outputFile); } else { - minifiedContent = minifiedContent ?? Minifier.Minify(BeforeMinify(outputFile, uniqueFiles, bundleState.Arbitrary)); + minifiedContent = minifiedContent ?? + Minifier.Minify(BeforeMinify(outputFile, uniqueFiles, + bundleState.Arbitrary)); renderer.Render(minifiedContent, outputFile); } - if(hash == null && !string.IsNullOrEmpty(HashKeyName)) + if (hash == null && !string.IsNullOrEmpty(bundleState.HashKeyName)) { hash = hasher.GetHash(minifiedContent); } - if(hashInFileName) + if (hashInFileName) { renderedTag = FillTemplate(bundleState, renderToPath); } else { - if(string.IsNullOrEmpty(HashKeyName)) + if (string.IsNullOrEmpty(bundleState.HashKeyName)) { renderedTag = FillTemplate(bundleState, renderToPath); } - else if(renderToPath.Contains("?")) + else if (renderToPath.Contains("?")) { renderedTag = FillTemplate(bundleState, - renderToPath + "&" + HashKeyName + "=" + hash); + renderToPath + "&" + bundleState.HashKeyName + "=" + hash); } else { renderedTag = FillTemplate(bundleState, - renderToPath + "?" + HashKeyName + "=" + hash); + renderToPath + "?" + bundleState.HashKeyName + "=" + hash); } } } @@ -459,43 +405,23 @@ private string RenderRelease(string key, string renderTo, IRenderer renderer) content += String.Concat(GetFilesForRemote(remoteAssetPaths, bundleState), renderedTag); } } - bundleCache.Add(key, content, DependentFiles); + bundleCache.Add(key, content, bundleState.DependentFiles); } return content; } - public void ClearCache() - { - bundleCache.ClearTestingCache(); - } - - private void AddAttributes(Dictionary attributes, bool merge = true) - { - if(merge) - { - foreach(var attribute in attributes) - { - bundleState.Attributes[attribute.Key] = attribute.Value; - } - } - else - { - bundleState.Attributes = attributes; - } - } - - protected string BeforeMinify(string outputFile, List files, IEnumerable arbitraryContent) + string BeforeMinify(string outputFile, List files, IEnumerable arbitraryContent) { var sb = new StringBuilder(); files.Select(f => ProcessFile(f, outputFile)) .Concat(arbitraryContent.Select(ac => - { - var filename = "dummy." + ac.Extension; - var preprocessors = FindPreprocessors(filename); - return PreprocessContent(filename, preprocessors, ac.Content); - })) + { + var filename = "dummy." + ac.Extension; + var preprocessors = FindPreprocessors(filename); + return PreprocessContent(filename, preprocessors, ac.Content); + })) .Aggregate(sb, (builder, val) => builder.Append(val + "\n")); return sb.ToString(); @@ -503,21 +429,21 @@ protected string BeforeMinify(string outputFile, List files, IEnumerable void BeforeRenderDebug() { - foreach(var asset in bundleState.Assets) + foreach (var asset in bundleState.Assets) { var localPath = asset.LocalPath; var preprocessors = FindPreprocessors(localPath); - if(preprocessors != null && preprocessors.Count() > 0) + if (preprocessors != null && preprocessors.Count() > 0) { var outputFile = FileSystem.ResolveAppRelativePathToFileSystem(localPath); var appendExtension = ".debug" + defaultExtension.ToLowerInvariant(); string content; - lock(typeof(T)) + lock (typeof (T)) { content = PreprocessFile(outputFile, preprocessors); } outputFile += appendExtension; - using(var fileWriter = fileWriterFactory.GetFileWriter(outputFile)) + using (var fileWriter = fileWriterFactory.GetFileWriter(outputFile)) { fileWriter.Write(content); } @@ -525,19 +451,5 @@ void BeforeRenderDebug() } } } - - private BundleState GetCachedBundleState(string name) - { - var bundle = bundleStateCache[CachePrefix + name]; - if(bundle.ForceDebug) - { - debugStatusReader.ForceDebug(); - } - if(bundle.ForceRelease) - { - debugStatusReader.ForceRelease(); - } - return bundle; - } } } \ No newline at end of file diff --git a/SquishIt.Framework/Base/BundleBase.Setup.cs b/SquishIt.Framework/Base/BundleBase.Setup.cs deleted file mode 100644 index b69f0e6..0000000 --- a/SquishIt.Framework/Base/BundleBase.Setup.cs +++ /dev/null @@ -1,154 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using SquishIt.Framework.Minifiers; -using SquishIt.Framework.Renderers; - -namespace SquishIt.Framework.Base -{ - public abstract partial class BundleBase where T : BundleBase - { - public T ForceDebug() - { - debugStatusReader.ForceDebug(); - bundleState.ForceDebug = true; - return (T)this; - } - - public T ForceRelease() - { - debugStatusReader.ForceRelease(); - bundleState.ForceRelease = true; - return (T)this; - } - - public T RenderOnlyIfOutputFileMissing() - { - ShouldRenderOnlyIfOutputFileIsMissing = true; - return (T)this; - } - - public T WithOutputBaseHref(string href) - { - BaseOutputHref = href; - return (T)this; - } - - public T WithReleaseFileRenderer(IRenderer renderer) - { - this.releaseFileRenderer = renderer; - return (T)this; - } - - public T WithAttribute(string name, string value) - { - AddAttributes(new Dictionary { { name, value } }); - return (T)this; - } - - public T WithAttributes(Dictionary attributes, bool merge = true) - { - AddAttributes(attributes, merge: merge); - return (T)this; - } - - public T WithMinifier() where TMin : IMinifier - { - return WithMinifier(MinifierFactory.Get()); - } - - public T WithMinifier(TMin instance) where TMin : IMinifier - { - Minifier = instance; - return (T)this; - } - - private string FillTemplate(BundleState state, string path) - { - return string.Format(Template, GetAdditionalAttributes(state), path); - } - - public T HashKeyNamed(string hashQueryStringKeyName) - { - HashKeyName = hashQueryStringKeyName; - return (T)this; - } - - public T WithoutRevisionHash() - { - return HashKeyNamed(string.Empty); - } - - public T WithPreprocessor(IPreprocessor instance) - { - if(!instancePreprocessors.Any(ipp => ipp.GetType() == instance.GetType())) - { - foreach(var extension in instance.Extensions) - { - instanceAllowedExtensions.Add(extension); - } - instancePreprocessors.Add(instance); - } - return (T)this; - } - - public T Add(string fileOrFolderPath) - { - AddAsset(new Asset(fileOrFolderPath)); - return (T)this; - } - - public T AddDirectory(string folderPath, bool recursive = true) - { - AddAsset(new Asset(folderPath, isRecursive: recursive)); - return (T)this; - } - - public T AddString(string content) - { - return AddString(content, defaultExtension); - } - - public T AddString(string content, string extension) - { - if(!bundleState.Arbitrary.Any(ac => ac.Content == content)) - bundleState.Arbitrary.Add(new ArbitraryContent { Content = content, Extension = extension }); - return (T)this; - } - - public T AddString(string format, object[] values) - { - return AddString(format, defaultExtension, values); - } - - public T AddString(string format, string extension, object[] values) - { - var content = string.Format(format, values); - return AddString(content, extension); - } - - public T AddRemote(string localPath, string remotePath) - { - return AddRemote(localPath, remotePath, false); - } - - public T AddRemote(string localPath, string remotePath, bool downloadRemote) - { - var asset = new Asset(localPath, remotePath); - asset.DownloadRemote = downloadRemote; - AddAsset(asset); - return (T)this; - } - - public T AddDynamic(string siteRelativePath) - { - var absolutePath = BuildAbsolutePath(siteRelativePath); - return AddRemote(siteRelativePath, absolutePath, true); - } - - public T AddEmbeddedResource(string localPath, string embeddedResourcePath) - { - AddAsset(new Asset(localPath, embeddedResourcePath, 0, true)); - return (T)this; - } - } -} diff --git a/SquishIt.Framework/Base/BundleBase.State.cs b/SquishIt.Framework/Base/BundleBase.State.cs deleted file mode 100644 index 41f1657..0000000 --- a/SquishIt.Framework/Base/BundleBase.State.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.Collections.Generic; -using SquishIt.Framework.Files; -using SquishIt.Framework.Minifiers; -using SquishIt.Framework.Renderers; -using SquishIt.Framework.Utilities; - -namespace SquishIt.Framework.Base -{ - public abstract partial class BundleBase where T : BundleBase - { - private static readonly Dictionary renderPathCache = new Dictionary(); - - protected string BaseOutputHref = Configuration.Instance.DefaultOutputBaseHref() ?? String.Empty; - protected IFileWriterFactory fileWriterFactory; - protected IFileReaderFactory fileReaderFactory; - protected IDebugStatusReader debugStatusReader; - protected ICurrentDirectoryWrapper currentDirectoryWrapper; - protected IHasher hasher; - protected abstract IMinifier DefaultMinifier { get; } - - protected abstract string tagFormat { get; } - protected bool typeless; - protected abstract string Template { get; } - protected abstract string CachePrefix { get; } - - protected HashSet instanceAllowedExtensions = new HashSet(); - protected IList instancePreprocessors = new List(); - protected abstract IEnumerable allowedExtensions { get; } - protected abstract IEnumerable disallowedExtensions { get; } - protected abstract string defaultExtension { get; } - - private IMinifier minifier; - protected IMinifier Minifier - { - get - { - return minifier ?? DefaultMinifier; - } - set { minifier = value; } - } - - protected string HashKeyName { get; set; } - private bool ShouldRenderOnlyIfOutputFileIsMissing { get; set; } - internal List DependentFiles = new List(); - internal BundleState bundleState = new BundleState(); - - private static Dictionary bundleStateCache = new Dictionary(); - - private IBundleCache bundleCache; - private IRenderer releaseFileRenderer; - - protected BundleBase(IFileWriterFactory fileWriterFactory, IFileReaderFactory fileReaderFactory, IDebugStatusReader debugStatusReader, ICurrentDirectoryWrapper currentDirectoryWrapper, IHasher hasher, IBundleCache bundleCache) - { - this.fileWriterFactory = fileWriterFactory; - this.fileReaderFactory = fileReaderFactory; - this.debugStatusReader = debugStatusReader; - this.currentDirectoryWrapper = currentDirectoryWrapper; - this.hasher = hasher; - ShouldRenderOnlyIfOutputFileIsMissing = false; - HashKeyName = "r"; - this.bundleCache = bundleCache; - } - } -} diff --git a/SquishIt.Framework/Base/BundleBase.cs b/SquishIt.Framework/Base/BundleBase.cs index db75f57..7a60d2a 100644 --- a/SquishIt.Framework/Base/BundleBase.cs +++ b/SquishIt.Framework/Base/BundleBase.cs @@ -1,268 +1,149 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Web; +using SquishIt.Framework.Files; using SquishIt.Framework.Minifiers; -using SquishIt.Framework.Resolvers; using SquishIt.Framework.Renderers; -using SquishIt.Framework.Files; using SquishIt.Framework.Utilities; -using System.IO; namespace SquishIt.Framework.Base { - public abstract class BundleBase where T : BundleBase + public abstract partial class BundleBase where T : BundleBase { - private static readonly Dictionary renderPathCache = new Dictionary(); + static readonly Dictionary renderPathCache = new Dictionary(); + static readonly Dictionary bundleStateCache = new Dictionary(); - protected string BaseOutputHref = Configuration.Instance.DefaultOutputBaseHref() ?? String.Empty; - protected IFileWriterFactory fileWriterFactory; - protected IFileReaderFactory fileReaderFactory; - protected IDebugStatusReader debugStatusReader; - protected ICurrentDirectoryWrapper currentDirectoryWrapper; - protected IHasher hasher; protected abstract IMinifier DefaultMinifier { get; } - protected abstract string tagFormat { get; } - protected bool typeless; protected abstract string Template { get; } protected abstract string CachePrefix { get; } - - protected HashSet instanceAllowedExtensions = new HashSet(); - protected IList instancePreprocessors = new List(); protected abstract IEnumerable allowedExtensions { get; } protected abstract IEnumerable disallowedExtensions { get; } protected abstract string defaultExtension { get; } + protected abstract string ProcessFile(string file, string outputFile); + + internal BundleState bundleState; + readonly IBundleCache bundleCache; + protected string BaseOutputHref = Configuration.Instance.DefaultOutputBaseHref() ?? String.Empty; + protected IFileWriterFactory fileWriterFactory; + protected IFileReaderFactory fileReaderFactory; + protected IDebugStatusReader debugStatusReader; + protected ICurrentDirectoryWrapper currentDirectoryWrapper; + protected IHasher hasher; + IMinifier minifier; - private IMinifier minifier; protected IMinifier Minifier { - get - { - return minifier ?? DefaultMinifier; - } + get { return minifier ?? DefaultMinifier; } set { minifier = value; } } - protected string HashKeyName { get; set; } - private bool ShouldRenderOnlyIfOutputFileIsMissing { get; set; } - internal List DependentFiles = new List(); - internal BundleState bundleState = new BundleState(); - - private static Dictionary bundleStateCache = new Dictionary(); - - private IBundleCache bundleCache; - private IRenderer releaseFileRenderer; - - protected BundleBase(IFileWriterFactory fileWriterFactory, IFileReaderFactory fileReaderFactory, IDebugStatusReader debugStatusReader, ICurrentDirectoryWrapper currentDirectoryWrapper, IHasher hasher, IBundleCache bundleCache) + protected BundleBase(IFileWriterFactory fileWriterFactory, IFileReaderFactory fileReaderFactory, + IDebugStatusReader debugStatusReader, ICurrentDirectoryWrapper currentDirectoryWrapper, + IHasher hasher, IBundleCache bundleCache) { this.fileWriterFactory = fileWriterFactory; this.fileReaderFactory = fileReaderFactory; this.debugStatusReader = debugStatusReader; this.currentDirectoryWrapper = currentDirectoryWrapper; this.hasher = hasher; - ShouldRenderOnlyIfOutputFileIsMissing = false; - HashKeyName = "r"; this.bundleCache = bundleCache; - } - protected IRenderer GetFileRenderer() - { - return debugStatusReader.IsDebuggingEnabled() ? new FileRenderer(fileWriterFactory) : - releaseFileRenderer ?? - Configuration.Instance.DefaultReleaseRenderer() ?? - new FileRenderer(fileWriterFactory); + bundleState = new BundleState + { + BaseOutputHref = Configuration.Instance.DefaultOutputBaseHref() ?? string.Empty, + HashKeyName = "r", + ShouldRenderOnlyIfOutputFileIsMissing = false + }; } - private List GetFiles(List assets) - { - var inputFiles = GetInputFiles(assets); - var resolvedFilePaths = new List(); - - foreach(Input input in inputFiles) - { - resolvedFilePaths.AddRange(input.TryResolve(allowedExtensions, disallowedExtensions)); - } - - return resolvedFilePaths; - } - - private Input GetInputFile(Asset asset) - { - if(!asset.IsEmbeddedResource) - { - if(debugStatusReader.IsDebuggingEnabled()) - { - return GetFileSystemPath(asset.LocalPath, asset.IsRecursive); - } - - if(asset.IsRemoteDownload) - { - return GetHttpPath(asset.RemotePath); - } - else - { - return GetFileSystemPath(asset.LocalPath, asset.IsRecursive); - } - } - else - { - return GetEmbeddedResourcePath(asset.RemotePath); - } - } - - private List GetInputFiles(List assets) - { - var inputFiles = new List(); - foreach(var asset in assets) - { - inputFiles.Add(GetInputFile(asset)); - } - return inputFiles; - } - - private Input GetFileSystemPath(string localPath, bool isRecursive = true) - { - string mappedPath = FileSystem.ResolveAppRelativePathToFileSystem(localPath); - return new Input(mappedPath, isRecursive, ResolverFactory.Get()); - } - - private Input GetHttpPath(string remotePath) - { - return new Input(remotePath, false, ResolverFactory.Get()); - } - - private Input GetEmbeddedResourcePath(string resourcePath) + public T ForceDebug() { - return new Input(resourcePath, false, ResolverFactory.Get()); + debugStatusReader.ForceDebug(); + bundleState.ForceDebug = true; + return (T) this; } - protected IEnumerable FindPreprocessors(string file) + public T ForceRelease() { - //using rails convention of applying preprocessing based on file extension components in reverse order - return file.Split('.') - .Skip(1) - .Reverse() - .Select(FindPreprocessor) - .Where(p => p != null); + debugStatusReader.ForceRelease(); + bundleState.ForceRelease = true; + return (T) this; } - protected abstract string ProcessFile(string file, string outputFile); - - protected string PreprocessFile(string file, IEnumerable preprocessors) + public T RenderOnlyIfOutputFileMissing() { - try - { - currentDirectoryWrapper.SetCurrentDirectory(Path.GetDirectoryName(file)); - var preprocessedContent = PreprocessContent(file, preprocessors, ReadFile(file)); - currentDirectoryWrapper.Revert(); - return preprocessedContent; - } - catch - { - currentDirectoryWrapper.Revert(); - throw; - } + bundleState.ShouldRenderOnlyIfOutputFileIsMissing = true; + return (T) this; } - protected string PreprocessContent(string file, IEnumerable preprocessors, string content) + public T WithOutputBaseHref(string href) { - if(preprocessors == null) - { - return content; - } - return preprocessors.Aggregate(content, (cntnt, pp) => pp.Process(file, cntnt)); + BaseOutputHref = href; + return (T) this; } - IPreprocessor FindPreprocessor(string extension) + public T WithReleaseFileRenderer(IRenderer renderer) { - var instanceTypes = instancePreprocessors.Select(ipp => ipp.GetType()).ToArray(); - - return Bundle.Preprocessors.Where(pp => !instanceTypes.Contains(pp.GetType())) - .Union(instancePreprocessors) - .FirstOrDefault(p => p.ValidFor(extension)); + bundleState.ReleaseFileRenderer = renderer; + return (T) this; } - private string ExpandAppRelativePath(string file) + public T WithAttribute(string name, string value) { - if(file.StartsWith("~/")) - { - string appRelativePath = HttpRuntime.AppDomainAppVirtualPath; - if(appRelativePath != null && !appRelativePath.EndsWith("/")) - appRelativePath += "/"; - return file.Replace("~/", appRelativePath); - } - return file; + AddAttributes(new Dictionary {{name, value}}); + return (T) this; } - protected string ReadFile(string file) + public T WithAttributes(Dictionary attributes, bool merge = true) { - using(var sr = fileReaderFactory.GetFileReader(file)) - { - return sr.ReadToEnd(); - } + AddAttributes(attributes, merge: merge); + return (T) this; } - protected bool FileExists(string file) + public T WithMinifier() where TMin : IMinifier { - return fileReaderFactory.FileExists(file); + return WithMinifier(MinifierFactory.Get()); } - private string GetAdditionalAttributes(BundleState bundleState) + public T WithMinifier(TMin instance) where TMin : IMinifier { - var result = new StringBuilder(); - foreach(var attribute in bundleState.Attributes) - { - result.Append(attribute.Key); - result.Append("=\""); - result.Append(attribute.Value); - result.Append("\" "); - } - return result.ToString(); + Minifier = instance; + return (T) this; } - private string GetFilesForRemote(List remoteAssetPaths, BundleState bundleState) + string FillTemplate(BundleState state, string path) { - var sb = new StringBuilder(); - foreach(var uri in remoteAssetPaths) - { - sb.Append(FillTemplate(bundleState, uri)); - } - - return sb.ToString(); + return string.Format(Template, GetAdditionalAttributes(state), path); } - private void AddAsset(Asset asset) + public T HashKeyNamed(string hashQueryStringKeyName) { - bundleState.Assets.Add(asset); + bundleState.HashKeyName = hashQueryStringKeyName; + return (T) this; } - public T WithoutTypeAttribute() + public T WithoutRevisionHash() { - this.typeless = true; - return (T)this; + return HashKeyNamed(string.Empty); } - [Obsolete] - public T Add(params string[] filesPath) + public T WithPreprocessor(IPreprocessor instance) { - foreach(var filePath in filesPath) - Add(filePath); - - return (T)this; + bundleState.AddPreprocessor(instance); + return (T) this; } public T Add(string fileOrFolderPath) { AddAsset(new Asset(fileOrFolderPath)); - return (T)this; + return (T) this; } public T AddDirectory(string folderPath, bool recursive = true) { AddAsset(new Asset(folderPath, isRecursive: recursive)); - return (T)this; + return (T) this; } public T AddString(string content) @@ -272,9 +153,9 @@ public T AddString(string content) public T AddString(string content, string extension) { - if(!bundleState.Arbitrary.Any(ac => ac.Content == content)) - bundleState.Arbitrary.Add(new ArbitraryContent { Content = content, Extension = extension }); - return (T)this; + if (!bundleState.Arbitrary.Any(ac => ac.Content == content)) + bundleState.Arbitrary.Add(new ArbitraryContent {Content = content, Extension = extension}); + return (T) this; } public T AddString(string format, object[] values) @@ -298,7 +179,7 @@ public T AddRemote(string localPath, string remotePath, bool downloadRemote) var asset = new Asset(localPath, remotePath); asset.DownloadRemote = downloadRemote; AddAsset(asset); - return (T)this; + return (T) this; } public T AddDynamic(string siteRelativePath) @@ -307,54 +188,46 @@ public T AddDynamic(string siteRelativePath) return AddRemote(siteRelativePath, absolutePath, true); } - string BuildAbsolutePath(string siteRelativePath) - { - if(HttpContext.Current == null) - throw new InvalidOperationException("Absolute path can only be constructed in the presence of an HttpContext."); - if(!siteRelativePath.StartsWith("/")) - throw new InvalidOperationException("This helper method only works with site relative paths."); - - var url = HttpContext.Current.Request.Url; - var port = url.Port != 80 ? (":" + url.Port) : String.Empty; - return string.Format("{0}://{1}{2}{3}", url.Scheme, url.Host, port, VirtualPathUtility.ToAbsolute(siteRelativePath)); - } - public T AddEmbeddedResource(string localPath, string embeddedResourcePath) { AddAsset(new Asset(localPath, embeddedResourcePath, 0, true)); - return (T)this; + return (T) this; } - public T RenderOnlyIfOutputFileMissing() - { - ShouldRenderOnlyIfOutputFileIsMissing = true; - return (T)this; - } - - public T ForceDebug() + public T WithoutTypeAttribute() { - debugStatusReader.ForceDebug(); - bundleState.ForceDebug = true; - return (T)this; + bundleState.Typeless = true; + return (T) this; } - public T ForceRelease() + void AddAttributes(Dictionary attributes, bool merge = true) { - debugStatusReader.ForceRelease(); - bundleState.ForceRelease = true; - return (T)this; + if (merge) + { + foreach (var attribute in attributes) + { + bundleState.Attributes[attribute.Key] = attribute.Value; + } + } + else + { + bundleState.Attributes = attributes; + } } - public T WithOutputBaseHref(string href) + void AddAsset(Asset asset) { - BaseOutputHref = href; - return (T)this; + bundleState.Assets.Add(asset); } - public T WithReleaseFileRenderer(IRenderer renderer) + //rendering + protected IRenderer GetFileRenderer() { - this.releaseFileRenderer = renderer; - return (T)this; + return debugStatusReader.IsDebuggingEnabled() + ? new FileRenderer(fileWriterFactory) + : bundleState.ReleaseFileRenderer ?? + Configuration.Instance.DefaultReleaseRenderer() ?? + new FileRenderer(fileWriterFactory); } public string Render(string renderTo) @@ -363,27 +236,25 @@ public string Render(string renderTo) return Render(renderTo, key, GetFileRenderer()); } - private string Render(string renderTo, string key, IRenderer renderer) + public void AsNamed(string name, string renderTo) { - var cacheUniquenessHash = key.Contains("#") ? hasher.GetHash(bundleState.Assets - .Select(a => a.IsRemote ? a.RemotePath : a.LocalPath) - .Union(bundleState.Arbitrary.Select(ac => ac.Content)) - .OrderBy(s => s) - .Aggregate((acc, val) => acc + val)) : string.Empty; - - key = CachePrefix + key + cacheUniquenessHash; + Render(renderTo, name, GetFileRenderer()); + bundleState.Path = renderTo; + bundleStateCache[CachePrefix + name] = bundleState; + } - if(!String.IsNullOrEmpty(BaseOutputHref)) - { - key = BaseOutputHref + key; - } + public string AsCached(string name, string filePath) + { + string result = Render(filePath, name, new CacheRenderer(CachePrefix, name)); + bundleState.Path = filePath; + bundleStateCache[CachePrefix + name] = bundleState; + return result; + } - if(debugStatusReader.IsDebuggingEnabled()) - { - var content = RenderDebug(renderTo, key, renderer); - return content; - } - return RenderRelease(key, renderTo, renderer); + public string RenderCachedAssetTag(string name) + { + bundleState = GetCachedBundleState(name); + return Render(null, name, new CacheRenderer(CachePrefix, name)); } public string RenderNamed(string name) @@ -394,7 +265,7 @@ public string RenderNamed(string name) //hopefully we can find a better way to satisfy both of these requirements var fullName = (BaseOutputHref ?? "") + CachePrefix + name; var content = bundleCache.GetContent(fullName); - if(content == null) + if (content == null) { AsNamed(name, bundleState.Path); return bundleCache.GetContent(CachePrefix + name); @@ -406,7 +277,7 @@ public string RenderCached(string name) { bundleState = GetCachedBundleState(name); var content = CacheRenderer.Get(CachePrefix, name); - if(content == null) + if (content == null) { AsCached(name, bundleState.Path); return CacheRenderer.Get(CachePrefix, name); @@ -414,338 +285,10 @@ public string RenderCached(string name) return content; } - public string RenderCachedAssetTag(string name) - { - bundleState = GetCachedBundleState(name); - return Render(null, name, new CacheRenderer(CachePrefix, name)); - } - - public void AsNamed(string name, string renderTo) - { - Render(renderTo, name, GetFileRenderer()); - bundleState.Path = renderTo; - bundleStateCache[CachePrefix + name] = bundleState; - } - - public string AsCached(string name, string filePath) - { - string result = Render(filePath, name, new CacheRenderer(CachePrefix, name)); - bundleState.Path = filePath; - bundleStateCache[CachePrefix + name] = bundleState; - return result; - } - - string RenderDebug(string renderTo, string name, IRenderer renderer) - { - string content = null; - - DependentFiles.Clear(); - - var renderedFiles = new HashSet(); - - BeforeRenderDebug(); - - var sb = new StringBuilder(); - var attributes = GetAdditionalAttributes(bundleState); - var assets = bundleState.Assets; - - DependentFiles.AddRange(GetFiles(assets)); - foreach(var asset in assets) - { - var inputFile = GetInputFile(asset); - var files = inputFile.TryResolve(allowedExtensions, disallowedExtensions); - - if(asset.IsEmbeddedResource) - { - var tsb = new StringBuilder(); - - foreach(var fn in files) - { - tsb.Append(ReadFile(fn) + "\n\n\n"); - } - - var processedFile = ExpandAppRelativePath(asset.LocalPath); - //embedded resources need to be rendered regardless to be usable - renderer.Render(tsb.ToString(), FileSystem.ResolveAppRelativePathToFileSystem(processedFile)); - sb.AppendLine(FillTemplate(bundleState, processedFile)); - } - else if(asset.RemotePath != null) - { - sb.AppendLine(FillTemplate(bundleState, ExpandAppRelativePath(asset.LocalPath))); - } - else - { - foreach(var file in files) - { - if(!renderedFiles.Contains(file)) - { - var fileBase = FileSystem.ResolveAppRelativePathToFileSystem(asset.LocalPath); - var newPath = file.Replace(fileBase, ""); - var path = ExpandAppRelativePath(asset.LocalPath + newPath.Replace("\\", "/")); - sb.AppendLine(FillTemplate(bundleState, path)); - renderedFiles.Add(file); - } - } - } - } - - foreach(var cntnt in bundleState.Arbitrary) - { - var filename = "dummy" + cntnt.Extension; - var preprocessors = FindPreprocessors(filename); - var processedContent = PreprocessContent(filename, preprocessors, cntnt.Content); - sb.AppendLine(string.Format(tagFormat, processedContent)); - } - - content = sb.ToString(); - - if(bundleCache.ContainsKey(name)) - { - bundleCache.Remove(name); - } - bundleCache.Add(name, content, DependentFiles); - - //need to render the bundle to caches, otherwise leave it - if(renderer is CacheRenderer) - renderer.Render(content, renderTo); - - return content; - } - - private string RenderRelease(string key, string renderTo, IRenderer renderer) - { - string content; - if(!bundleCache.TryGetValue(key, out content)) - { - using(new CriticalRenderingSection(renderTo)) - { - if(!bundleCache.TryGetValue(key, out content)) - { - var uniqueFiles = new List(); - string minifiedContent = null; - string hash = null; - bool hashInFileName = false; - - DependentFiles.Clear(); - - if(renderTo == null) - { - renderTo = renderPathCache[CachePrefix + "." + key]; - } - else - { - renderPathCache[CachePrefix + "." + key] = renderTo; - } - - string outputFile = FileSystem.ResolveAppRelativePathToFileSystem(renderTo); - var renderToPath = ExpandAppRelativePath(renderTo); - - if(!String.IsNullOrEmpty(BaseOutputHref)) - { - renderToPath = String.Concat(BaseOutputHref.TrimEnd('/'), "/", renderToPath.TrimStart('/')); - } - - var remoteAssetPaths = new List(); - foreach(var asset in bundleState.Assets) - { - if(asset.IsRemote) - { - remoteAssetPaths.Add(asset.RemotePath); - } - } - - uniqueFiles.AddRange(GetFiles(bundleState.Assets.Where(asset => - asset.IsEmbeddedResource || - asset.IsLocal || - asset.IsRemoteDownload).ToList()).Distinct()); - - string renderedTag = string.Empty; - if(uniqueFiles.Count > 0 || bundleState.Arbitrary.Count > 0) - { - DependentFiles.AddRange(uniqueFiles); - - if(renderTo.Contains("#")) - { - hashInFileName = true; - minifiedContent = Minifier.Minify(BeforeMinify(outputFile, uniqueFiles, bundleState.Arbitrary)); - hash = hasher.GetHash(minifiedContent); - renderToPath = renderToPath.Replace("#", hash); - outputFile = outputFile.Replace("#", hash); - } - - if(ShouldRenderOnlyIfOutputFileIsMissing && FileExists(outputFile)) - { - minifiedContent = ReadFile(outputFile); - } - else - { - minifiedContent = minifiedContent ?? Minifier.Minify(BeforeMinify(outputFile, uniqueFiles, bundleState.Arbitrary)); - renderer.Render(minifiedContent, outputFile); - } - - if(hash == null && !string.IsNullOrEmpty(HashKeyName)) - { - hash = hasher.GetHash(minifiedContent); - } - - if(hashInFileName) - { - renderedTag = FillTemplate(bundleState, renderToPath); - } - else - { - if(string.IsNullOrEmpty(HashKeyName)) - { - renderedTag = FillTemplate(bundleState, renderToPath); - } - else if(renderToPath.Contains("?")) - { - renderedTag = FillTemplate(bundleState, - renderToPath + "&" + HashKeyName + "=" + hash); - } - else - { - renderedTag = FillTemplate(bundleState, - renderToPath + "?" + HashKeyName + "=" + hash); - } - } - } - - content += String.Concat(GetFilesForRemote(remoteAssetPaths, bundleState), renderedTag); - } - } - bundleCache.Add(key, content, DependentFiles); - } - - return content; - } - - public void ClearCache() + //test helpers + internal void ClearCache() { bundleCache.ClearTestingCache(); } - - private void AddAttributes(Dictionary attributes, bool merge = true) - { - if(merge) - { - foreach(var attribute in attributes) - { - bundleState.Attributes[attribute.Key] = attribute.Value; - } - } - else - { - bundleState.Attributes = attributes; - } - } - - public T WithAttribute(string name, string value) - { - AddAttributes(new Dictionary { { name, value } }); - return (T)this; - } - - public T WithAttributes(Dictionary attributes, bool merge = true) - { - AddAttributes(attributes, merge: merge); - return (T)this; - } - - public T WithMinifier() where TMin : IMinifier - { - Minifier = MinifierFactory.Get(); - return (T)this; - } - - public T WithMinifier(TMin minifier) where TMin : IMinifier - { - Minifier = minifier; - return (T)this; - } - - private string FillTemplate(BundleState bundleState, string path) - { - return string.Format(Template, GetAdditionalAttributes(bundleState), path); - } - - public T HashKeyNamed(string hashQueryStringKeyName) - { - HashKeyName = hashQueryStringKeyName; - return (T)this; - } - - public T WithoutRevisionHash() - { - return HashKeyNamed(string.Empty); - } - - public T WithPreprocessor(IPreprocessor instance) - { - if(!instancePreprocessors.Any(ipp => ipp.GetType() == instance.GetType())) - { - foreach(var extension in instance.Extensions) - { - instanceAllowedExtensions.Add(extension); - } - instancePreprocessors.Add(instance); - } - return (T)this; - } - - protected string BeforeMinify(string outputFile, List files, IEnumerable arbitraryContent) - { - var sb = new StringBuilder(); - - files.Select(f => ProcessFile(f, outputFile)) - .Concat(arbitraryContent.Select(ac => - { - var filename = "dummy." + ac.Extension; - var preprocessors = FindPreprocessors(filename); - return PreprocessContent(filename, preprocessors, ac.Content); - })) - .Aggregate(sb, (builder, val) => builder.Append(val + "\n")); - - return sb.ToString(); - } - - void BeforeRenderDebug() - { - foreach(var asset in bundleState.Assets) - { - var localPath = asset.LocalPath; - var preprocessors = FindPreprocessors(localPath); - if(preprocessors != null && preprocessors.Count() > 0) - { - var outputFile = FileSystem.ResolveAppRelativePathToFileSystem(localPath); - var appendExtension = ".debug" + defaultExtension.ToLowerInvariant(); - string content; - lock(typeof(T)) - { - content = PreprocessFile(outputFile, preprocessors); - } - outputFile += appendExtension; - using(var fileWriter = fileWriterFactory.GetFileWriter(outputFile)) - { - fileWriter.Write(content); - } - asset.LocalPath = localPath + appendExtension; - } - } - } - - private BundleState GetCachedBundleState(string name) - { - var bundle = bundleStateCache[CachePrefix + name]; - if(bundle.ForceDebug) - { - debugStatusReader.ForceDebug(); - } - if(bundle.ForceRelease) - { - debugStatusReader.ForceRelease(); - } - return bundle; - } } } \ No newline at end of file diff --git a/SquishIt.Framework/Base/BundleState.cs b/SquishIt.Framework/Base/BundleState.cs index a60b187..dd8c045 100644 --- a/SquishIt.Framework/Base/BundleState.cs +++ b/SquishIt.Framework/Base/BundleState.cs @@ -1,4 +1,7 @@ +using System; using System.Collections.Generic; +using System.Linq; +using SquishIt.Framework.Renderers; namespace SquishIt.Framework.Base { @@ -8,9 +11,22 @@ internal class BundleState internal Dictionary Attributes = new Dictionary(); internal IList Arbitrary = new List(); - public bool ForceDebug { get; set; } - public bool ForceRelease { get; set; } - public string Path { get; set; } + internal HashSet AllowedExtensions = new HashSet(); + internal IList Preprocessors = new List(); + internal List DependentFiles = new List(); + + internal string HashKeyName { get; set; } + internal string BaseOutputHref { get; set; } + + + internal bool Typeless { get; set; } + internal bool ShouldRenderOnlyIfOutputFileIsMissing { get; set; } + + internal bool ForceDebug { get; set; } + internal bool ForceRelease { get; set; } + internal string Path { get; set; } + + internal IRenderer ReleaseFileRenderer { get; set; } internal BundleState() { @@ -20,5 +36,17 @@ internal BundleState(Dictionary attributes) { Attributes = attributes; } + + internal void AddPreprocessor(IPreprocessor instance) + { + if(!Preprocessors.Any(ipp => ipp.GetType() == instance.GetType())) + { + foreach(var extension in instance.Extensions) + { + AllowedExtensions.Add(extension); + } + Preprocessors.Add(instance); + } + } } } \ No newline at end of file diff --git a/SquishIt.Framework/Css/CssBundle.cs b/SquishIt.Framework/Css/CssBundle.cs index 2bf5c38..6f0d50e 100644 --- a/SquishIt.Framework/Css/CssBundle.cs +++ b/SquishIt.Framework/Css/CssBundle.cs @@ -38,7 +38,7 @@ protected override IMinifier DefaultMinifier protected override IEnumerable allowedExtensions { - get { return instanceAllowedExtensions.Union(Bundle.AllowedGlobalExtensions.Union(Bundle.AllowedStyleExtensions)); } + get { return bundleState.AllowedExtensions.Union(Bundle.AllowedGlobalExtensions.Union(Bundle.AllowedStyleExtensions)); } } protected override IEnumerable disallowedExtensions @@ -53,7 +53,7 @@ protected override string defaultExtension protected override string tagFormat { - get { return typeless ? TAG_FORMAT.Replace(" type=\"text/css\"", "") : TAG_FORMAT; } + get { return bundleState.Typeless ? TAG_FORMAT.Replace(" type=\"text/css\"", "") : TAG_FORMAT; } } public CSSBundle() @@ -87,7 +87,7 @@ private string ProcessImport(string file, string outputFile, string css) { import = FileSystem.ResolveAppRelativePathToFileSystem(sourcePath + importPath); } - DependentFiles.Add(import); + bundleState.DependentFiles.Add(import); return ProcessCssFile(import, outputFile, true); }); } @@ -134,7 +134,7 @@ string ProcessCssFile(string file, string outputFile, bool asImport = false) if(ShouldAppendHashForAssets) { var fileResolver = new FileSystemResolver(); - fileHasher = new CssAssetsFileHasher(HashKeyName, fileResolver, hasher); + fileHasher = new CssAssetsFileHasher(bundleState.HashKeyName, fileResolver, hasher); } return CSSPathRewriter.RewriteCssPaths(outputFile, file, css, fileHasher, asImport); diff --git a/SquishIt.Framework/JavaScript/JavaScriptBundle.cs b/SquishIt.Framework/JavaScript/JavaScriptBundle.cs index b99d913..dac5b9e 100644 --- a/SquishIt.Framework/JavaScript/JavaScriptBundle.cs +++ b/SquishIt.Framework/JavaScript/JavaScriptBundle.cs @@ -23,7 +23,7 @@ protected override IMinifier DefaultMinifier protected override IEnumerable allowedExtensions { - get { return instanceAllowedExtensions.Union(Bundle.AllowedGlobalExtensions.Union(Bundle.AllowedScriptExtensions)); } + get { return bundleState.AllowedExtensions.Union(Bundle.AllowedGlobalExtensions.Union(Bundle.AllowedScriptExtensions)); } } protected override IEnumerable disallowedExtensions @@ -38,7 +38,7 @@ protected override string defaultExtension protected override string tagFormat { - get { return typeless ? TAG_FORMAT.Replace(" type=\"text/javascript\"", "") : TAG_FORMAT; } + get { return bundleState.Typeless ? TAG_FORMAT.Replace(" type=\"text/javascript\"", "") : TAG_FORMAT; } } public JavaScriptBundle() @@ -54,7 +54,7 @@ protected override string Template { get { - var val = typeless ? JS_TEMPLATE.Replace("type=\"text/javascript\" ", "") : JS_TEMPLATE; + var val = bundleState.Typeless ? JS_TEMPLATE.Replace("type=\"text/javascript\" ", "") : JS_TEMPLATE; return deferred ? val : val.Replace(" defer", ""); } } diff --git a/SquishIt.Framework/SquishIt.Framework.csproj b/SquishIt.Framework/SquishIt.Framework.csproj index 17b6071..83f873c 100644 --- a/SquishIt.Framework/SquishIt.Framework.csproj +++ b/SquishIt.Framework/SquishIt.Framework.csproj @@ -79,8 +79,8 @@ - - + + @@ -147,7 +147,6 @@ - PreserveNewest