diff --git a/CssSorter.dll b/CssSorter.dll index d3d17c9ed..232eba337 100644 Binary files a/CssSorter.dll and b/CssSorter.dll differ diff --git a/EditorExtensions/Commands/Code/IntellisenseWriter.cs b/EditorExtensions/Commands/Code/IntellisenseWriter.cs index 7260639ae..7dd262920 100644 --- a/EditorExtensions/Commands/Code/IntellisenseWriter.cs +++ b/EditorExtensions/Commands/Code/IntellisenseWriter.cs @@ -20,7 +20,7 @@ public static void Write(IEnumerable objects, string file) else WriteJavaScript(objects, sb); - WriteFileToDisk(file, sb); + File.WriteAllText(file, sb.ToString()); } private static string CamelCasePropertyName(string name) @@ -158,19 +158,5 @@ private static void WriteTSInterfaceDefinition(StringBuilder sb, string prefix, sb.Append(prefix).Append("}"); } - - private static void WriteFileToDisk(string fileName, StringBuilder sb) - { - //string current = string.Empty; - //if (File.Exists(fileName)) - //{ - // current = File.ReadAllText(fileName); - //} - - //if (current != sb.ToString()) - //{ - File.WriteAllText(fileName, sb.ToString(), Encoding.UTF8); - //} - } } } \ No newline at end of file diff --git a/EditorExtensions/Commands/IFileSaveListener.cs b/EditorExtensions/Commands/IFileSaveListener.cs index b2e34e3d2..79311dddd 100644 --- a/EditorExtensions/Commands/IFileSaveListener.cs +++ b/EditorExtensions/Commands/IFileSaveListener.cs @@ -5,6 +5,6 @@ namespace MadsKristensen.EditorExtensions.Commands ///A listener called when files are saved in the editor, as well as for compiled files on save or build. public interface IFileSaveListener { - void FileSaved(IContentType contentType, string path, bool forceSave); + void FileSaved(IContentType contentType, string path, bool forceSave, bool minifyInPlace); } } diff --git a/EditorExtensions/Commands/Shared/MinifySelectionCommandTarget.cs b/EditorExtensions/Commands/Shared/MinifySelectionCommandTarget.cs index bcffa2cbb..f17a86e39 100644 --- a/EditorExtensions/Commands/Shared/MinifySelectionCommandTarget.cs +++ b/EditorExtensions/Commands/Shared/MinifySelectionCommandTarget.cs @@ -8,7 +8,6 @@ namespace MadsKristensen.EditorExtensions { internal class MinifySelection : CommandTargetBase { - public MinifySelection(IVsTextView adapter, IWpfTextView textView) : base(adapter, textView, MinifyCommandId.MinifySelection) { diff --git a/EditorExtensions/Commands/Shared/PasteImageCommandTarget.cs b/EditorExtensions/Commands/Shared/PasteImageCommandTarget.cs index 380eac561..7ffdb7328 100644 --- a/EditorExtensions/Commands/Shared/PasteImageCommandTarget.cs +++ b/EditorExtensions/Commands/Shared/PasteImageCommandTarget.cs @@ -29,11 +29,9 @@ protected override bool Execute(VSConstants.VSStd97CmdID commandId, uint nCmdexe { IDataObject data = Clipboard.GetDataObject(); - // This is to check if the image is text copied from PowerPoint etc. - bool trueBitmap = data.GetFormats().Contains("DeviceIndependentBitmap"); bool hasBitmap = data.GetDataPresent("System.Drawing.Bitmap") || data.GetDataPresent(DataFormats.FileDrop); - if (!hasBitmap || !trueBitmap || !IsValidTextBuffer()) + if (!hasBitmap || !IsValidTextBuffer()) return false; string fileName = null; diff --git a/EditorExtensions/Commands/Shared/TextCreationListener.cs b/EditorExtensions/Commands/Shared/TextCreationListener.cs index 12efb5c84..57a7ed612 100644 --- a/EditorExtensions/Commands/Shared/TextCreationListener.cs +++ b/EditorExtensions/Commands/Shared/TextCreationListener.cs @@ -45,7 +45,7 @@ public void VsTextViewCreated(IVsTextView textViewAdapter) return; foreach (var listener in saveListeners) - listener.FileSaved(document.TextBuffer.ContentType, e.FilePath, false); + listener.FileSaved(document.TextBuffer.ContentType, e.FilePath, false, false); }; document.FileActionOccurred += saveHandler; diff --git a/EditorExtensions/Compilers/CompilerRunner.cs b/EditorExtensions/Compilers/CompilerRunner.cs index 4a8b6a631..3347357b1 100644 --- a/EditorExtensions/Compilers/CompilerRunner.cs +++ b/EditorExtensions/Compilers/CompilerRunner.cs @@ -73,10 +73,15 @@ public static bool ShouldCompile(string sourcePath) ///Gets the default save location for the compiled results of the specified file, based on user settings. public string GetTargetPath(string sourcePath) { + var ext = TargetExtension; + + if (Settings.MinifyInPlace && WESettings.Instance.ForContentType(TargetContentType).AutoMinify) + ext = ".min" + ext; + if (string.IsNullOrEmpty(Settings.OutputDirectory)) - return Path.ChangeExtension(sourcePath, TargetExtension); + return Path.ChangeExtension(sourcePath, ext); - string compiledFileName = Path.GetFileName(Path.ChangeExtension(sourcePath, TargetExtension)); + string compiledFileName = Path.GetFileName(Path.ChangeExtension(sourcePath, ext)); string sourceDir = Path.GetDirectoryName(sourcePath); // If the output path is not project-relative, combine it directly. @@ -112,7 +117,7 @@ public async Task CompileAsync(string sourcePath, string targetP ProjectHelpers.AddFileToProject(targetPath, targetPath + ".map"); foreach (var listener in _listeners) - listener.FileSaved(TargetContentType, result.TargetFileName, true); + listener.FileSaved(TargetContentType, result.TargetFileName, true, Settings.MinifyInPlace); } return result; diff --git a/EditorExtensions/Compilers/EditorCompilerInvoker.cs b/EditorExtensions/Compilers/EditorCompilerInvoker.cs index 224ba28ae..e59dc5955 100644 --- a/EditorExtensions/Compilers/EditorCompilerInvoker.cs +++ b/EditorExtensions/Compilers/EditorCompilerInvoker.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Linq; using EnvDTE; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Text; diff --git a/EditorExtensions/Compilers/LESS/LessCompiler.cs b/EditorExtensions/Compilers/LESS/LessCompiler.cs index d769dc3d0..6c6dec7d7 100644 --- a/EditorExtensions/Compilers/LESS/LessCompiler.cs +++ b/EditorExtensions/Compilers/LESS/LessCompiler.cs @@ -16,11 +16,10 @@ public class LessCompiler : CssCompilerBase public override string TargetExtension { get { return ".css"; } } public override string ServiceName { get { return "LESS"; } } - protected override string CompilerPath { get { return _compilerPath; } } protected override Regex ErrorParsingPattern { get { return _errorParsingPattern; } } - public override bool GenerateSourceMap { get { return WESettings.Instance.Less.GenerateSourceMaps; } } + protected override string GetArguments(string sourceFileName, string targetFileName) { var args = new StringBuilder("--no-color --relative-urls "); diff --git a/EditorExtensions/Compilers/NodeExecutorBase.cs b/EditorExtensions/Compilers/NodeExecutorBase.cs index e6edc5528..48fa5dcbe 100644 --- a/EditorExtensions/Compilers/NodeExecutorBase.cs +++ b/EditorExtensions/Compilers/NodeExecutorBase.cs @@ -31,7 +31,6 @@ public async Task CompileAsync(string sourceFileName, string tar if (RequireMatchingFileName && Path.GetFileName(targetFileName) != Path.GetFileNameWithoutExtension(sourceFileName) + TargetExtension) throw new ArgumentException(ServiceName + " cannot compile to a targetFileName with a different name. Only the containing directory can be different.", "targetFileName"); - var scriptArgs = GetArguments(sourceFileName, targetFileName); var errorOutputFile = Path.GetTempFileName(); @@ -51,8 +50,8 @@ public async Task CompileAsync(string sourceFileName, string tar try { - ProjectHelpers.CheckOutFileFromSourceControl(targetFileName); + if (GenerateSourceMap) ProjectHelpers.CheckOutFileFromSourceControl(targetFileName + ".map"); @@ -80,7 +79,13 @@ private CompilerResult ProcessResult(Process process, string errorText, string s if (result.IsSuccess) { - result.Result = PostProcessResult(result.Result, sourceFileName, targetFileName); + var renewedResult = PostProcessResult(result.Result, sourceFileName, targetFileName); + + if (!ReferenceEquals(result.Result, renewedResult)) + { + File.WriteAllText(targetFileName, renewedResult); + result.Result = renewedResult; + } } else { diff --git a/EditorExtensions/Compilers/SASS/SassCompiler.cs b/EditorExtensions/Compilers/SASS/SassCompiler.cs index eafc38b5c..172f40878 100644 --- a/EditorExtensions/Compilers/SASS/SassCompiler.cs +++ b/EditorExtensions/Compilers/SASS/SassCompiler.cs @@ -16,11 +16,10 @@ public class SassCompiler : CssCompilerBase public override string ServiceName { get { return "SASS"; } } public override string TargetExtension { get { return ".css"; } } - protected override string CompilerPath { get { return _compilerPath; } } protected override Regex ErrorParsingPattern { get { return _errorParsingPattern; } } - public override bool GenerateSourceMap { get { return WESettings.Instance.Sass.GenerateSourceMaps; } } + protected override string GetArguments(string sourceFileName, string targetFileName) { var args = new StringBuilder(); diff --git a/EditorExtensions/Compilers/TypeScriptCompilationNotifier.cs b/EditorExtensions/Compilers/TypeScriptCompilationNotifier.cs index 9d84dfc8d..654725fbc 100644 --- a/EditorExtensions/Compilers/TypeScriptCompilationNotifier.cs +++ b/EditorExtensions/Compilers/TypeScriptCompilationNotifier.cs @@ -126,8 +126,9 @@ private void FileTouched(object sender, FileSystemEventArgs e) if (File.Exists(TargetFilePath)) { RaiseReady(); + foreach (var listener in _listeners) - listener.FileSaved(ContentTypeManager.GetContentType("JavaScript"), TargetFilePath, false); + listener.FileSaved(ContentTypeManager.GetContentType("JavaScript"), TargetFilePath, false, false); } _isReady = false; } diff --git a/EditorExtensions/DropTargets/HtmlImageDrop.cs b/EditorExtensions/DropTargets/HtmlImageDrop.cs index e30644792..2b6e890c4 100644 --- a/EditorExtensions/DropTargets/HtmlImageDrop.cs +++ b/EditorExtensions/DropTargets/HtmlImageDrop.cs @@ -29,7 +29,7 @@ public IDropHandler GetAssociatedDropHandler(IWpfTextView wpfTextView) public class HtmlImageDropHandler : IDropHandler { - const string HtmlTemplate = "\"\""; + const string HtmlTemplate = "\"\""; const string MarkdownTemplate = "![{0}]({1})"; static readonly HashSet _imageExtensions = new HashSet(StringComparer.OrdinalIgnoreCase) { ".jpg", ".jpeg", ".bmp", ".png", ".gif", ".svg", ".tif", ".tiff" }; diff --git a/EditorExtensions/Helpers/ProjectHelpers.cs b/EditorExtensions/Helpers/ProjectHelpers.cs index c6e7f6a21..592f97601 100644 --- a/EditorExtensions/Helpers/ProjectHelpers.cs +++ b/EditorExtensions/Helpers/ProjectHelpers.cs @@ -1,11 +1,10 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using EnvDTE; using EnvDTE80; -using Microsoft.CSS.Core; using Microsoft.VisualStudio; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.Editor; @@ -439,8 +438,9 @@ internal static ProjectItem GetProjectItem(string fileName) public static ProjectItem AddFileToProject(string parentFileName, string fileName) { - if (!File.Exists(fileName)) + if (Path.GetFullPath(parentFileName) == Path.GetFullPath(fileName) || !File.Exists(fileName)) return null; + fileName = Path.GetFullPath(fileName); // WAP projects don't like paths with forward slashes var item = ProjectHelpers.GetProjectItem(parentFileName); @@ -459,9 +459,15 @@ public static ProjectItem AddFileToProject(string parentFileName, string fileNam if (item == null) return null; - var addedItem = item.ProjectItems.AddFromFile(fileName); + ProjectItem addedItem = null; + + try + { + addedItem = item.ProjectItems.AddFromFile(fileName); + } + catch (COMException) { } - if (Path.GetDirectoryName(parentFileName) == Path.GetDirectoryName(fileName)) + if (addedItem != null && Path.GetDirectoryName(parentFileName) == Path.GetDirectoryName(fileName)) { // create nesting var dependentUponProperty = addedItem.Properties.Item("DependentUpon"); @@ -472,11 +478,19 @@ public static ProjectItem AddFileToProject(string parentFileName, string fileNam } else if (item.ContainingProject.GetType().Name != "OAProject" && item.ProjectItems != null && Path.GetDirectoryName(parentFileName) == Path.GetDirectoryName(fileName)) { // WAP - return item.ProjectItems.AddFromFile(fileName); + try + { + return item.ProjectItems.AddFromFile(fileName); + } + catch (COMException) { } } else if (Path.GetFullPath(fileName).StartsWith(GetRootFolder(item.ContainingProject), StringComparison.OrdinalIgnoreCase)) { // Website - return item.ContainingProject.ProjectItems.AddFromFile(fileName); + try + { + return item.ContainingProject.ProjectItems.AddFromFile(fileName); + } + catch (COMException) { } } return null; diff --git a/EditorExtensions/MenuItems/MinifyFile.cs b/EditorExtensions/MenuItems/MinifyFile.cs index 6f872d6c2..90f740764 100644 --- a/EditorExtensions/MenuItems/MinifyFile.cs +++ b/EditorExtensions/MenuItems/MinifyFile.cs @@ -68,6 +68,7 @@ private void Execute() { MinificationService.CreateMinFile(ContentType, file); } + CheckEnableSync(); } diff --git a/EditorExtensions/Optimization/Minification/IFileMinifier.cs b/EditorExtensions/Optimization/Minification/IFileMinifier.cs index 4bb6159cc..d250bbe41 100644 --- a/EditorExtensions/Optimization/Minification/IFileMinifier.cs +++ b/EditorExtensions/Optimization/Minification/IFileMinifier.cs @@ -62,6 +62,7 @@ public override string MinifyString(string source) var minifier = new HtmlMinifier(settings); MarkupMinificationResult result = minifier.Minify(source, generateStatistics: true); + if (result.Errors.Count == 0) { EditorExtensionsPackage.DTE.StatusBar.Text = "Web Essentials: HTML minified by " + result.Statistics.SavedInPercent + "%"; @@ -83,6 +84,7 @@ public class CssFileMinifer : InMemoryMinifier public override string MinifyString(string source) { Minifier minifier = new Minifier(); + var settings = new Microsoft.Ajax.Utilities.CssSettings { CommentMode = WESettings.Instance.General.KeepImportantComments ? CssComment.Hacks : CssComment.Important @@ -97,6 +99,7 @@ public override string MinifyString(string source) public class JavaScriptFileMinifer : InMemoryMinifier { public override bool GenerateSourceMap { get { return WESettings.Instance.JavaScript.GenerateSourceMaps; } } + static CodeSettings CreateSettings() { return new CodeSettings() @@ -106,6 +109,7 @@ static CodeSettings CreateSettings() PreserveImportantComments = WESettings.Instance.General.KeepImportantComments }; } + public override string MinifyString(string source) { return new Minifier().MinifyJavaScript(source, CreateSettings()); @@ -118,6 +122,7 @@ public override bool MinifyFile(string sourcePath, string targetPath) else return base.MinifyFile(sourcePath, targetPath); } + private static bool MinifyFileWithSourceMap(string file, string minFile) { string mapPath = minFile + ".map"; @@ -137,6 +142,7 @@ private static bool MinifyFileWithSourceMap(string file, string minFile) return result; } } + private static bool MinifyFile(string file, string minFile, CodeSettings settings) { Minifier minifier = new Minifier(); diff --git a/EditorExtensions/Optimization/Minification/MinificationSaveListener.cs b/EditorExtensions/Optimization/Minification/MinificationSaveListener.cs index d88f6349d..71784dffe 100644 --- a/EditorExtensions/Optimization/Minification/MinificationSaveListener.cs +++ b/EditorExtensions/Optimization/Minification/MinificationSaveListener.cs @@ -13,14 +13,20 @@ namespace MadsKristensen.EditorExtensions.Optimization.Minification [ContentType("JavaScript")] class MinificationSaveListener : IFileSaveListener { - public void FileSaved(IContentType contentType, string path, bool forceSave) + public void FileSaved(IContentType contentType, string path, bool forceSave, bool minifyInPlace) { // This will also be called for derived ContentTypes like LESS & Markdown. Ignore those. var settings = WESettings.Instance.ForContentType(contentType); + if (settings == null || !settings.AutoMinify) return; - ReMinify(contentType, path, forceSave, settings); + + if (minifyInPlace) + MinifyFile(contentType, path, path, settings); + else + ReMinify(contentType, path, forceSave, settings); } + ///Minifies an existing file if it should be minified. public void ReMinify(IContentType contentType, string path, bool forceSave, IMinifierSettings settings = null) { @@ -28,15 +34,19 @@ public void ReMinify(IContentType contentType, string path, bool forceSave, IMin if (!ShouldMinify(path)) return; - if (!forceSave && !File.Exists(GetMinFileName(path))) + string minPath = GetMinFileName(path); + + if (!forceSave && !File.Exists(minPath)) return; - MinifyFile(contentType, path, settings ?? WESettings.Instance.ForContentType(contentType)); + MinifyFile(contentType, path, minPath, settings ?? WESettings.Instance.ForContentType(contentType)); } + public static string GetMinFileName(string path) { return path.Insert(path.Length - Path.GetExtension(path).Length, ".min"); } + public static bool ShouldMinify(string path) { var baseName = Path.GetFileNameWithoutExtension(path); @@ -47,36 +57,22 @@ public static bool ShouldMinify(string path) public void CreateMinFile(IContentType contentType, string sourcePath) { var settings = WESettings.Instance.ForContentType(contentType); - MinifyFile(contentType, sourcePath, settings); - var minPath = GetMinFileName(sourcePath); - ProjectHelpers.AddFileToProject(sourcePath, minPath); - - if (File.Exists(minPath + ".map")) - { - string mapPath = minPath + ".map"; - ProjectHelpers.AddFileToProject(minPath, mapPath); - } + MinifyFile(contentType, sourcePath, minPath, settings); if (settings.GzipMinifiedFiles) ProjectHelpers.AddFileToProject(minPath, minPath + ".gzip"); } - private static void MinifyFile(IContentType contentType, string sourcePath, IMinifierSettings settings) + private static void MinifyFile(IContentType contentType, string sourcePath, string minPath, IMinifierSettings settings) { IFileMinifier minifier = Mef.GetImport(contentType); - string minPath = GetMinFileName(sourcePath); bool minExist = File.Exists(minPath); bool changed = minifier.MinifyFile(sourcePath, minPath); - if (!minExist) - ProjectHelpers.AddFileToProject(sourcePath, minPath); - if (settings.GzipMinifiedFiles && (changed || !File.Exists(minPath + ".gzip"))) - { FileHelpers.GzipFile(minPath); - } } } } diff --git a/EditorExtensions/Settings/WESettings.cs b/EditorExtensions/Settings/WESettings.cs index 397d18f61..c39f161b7 100644 --- a/EditorExtensions/Settings/WESettings.cs +++ b/EditorExtensions/Settings/WESettings.cs @@ -26,6 +26,7 @@ public sealed class WESettings : SettingsBase public CoffeeScriptSettings CoffeeScript { get; private set; } public MarkdownSettings Markdown { get; private set; } } + public sealed class GeneralSettings : SettingsBase, IMarginSettings { [Category("Minification")] @@ -54,6 +55,7 @@ public sealed class GeneralSettings : SettingsBase, IMarginSett bool IMarginSettings.ShowPreviewPane { get { return SvgPreviewPane; } } } + public sealed class BrowserLinkSettings : SettingsBase { [Category("Browser Link")] @@ -77,6 +79,7 @@ public sealed class BrowserLinkSettings : SettingsBase [DefaultValue(true)] public bool ShowMenu { get; set; } } + public sealed class CodeGenSettings : SettingsBase { [DisplayName("Use LowerCamelCase for property names")] @@ -96,6 +99,7 @@ public interface ILinterSettings bool LintOnBuild { get; } TaskErrorCategory LintResultLocation { get; } } + public class LinterSettings : SettingsBase, ILinterSettings where T : LinterSettings { [Category("Linter")] @@ -115,6 +119,7 @@ public class LinterSettings : SettingsBase, ILinterSettings where T : Lint [DefaultValue(TaskErrorCategory.Message)] public TaskErrorCategory LintResultLocation { get; set; } } + public sealed class TypeScriptSettings : LinterSettings, IMarginSettings { [Category("Editor")] @@ -141,6 +146,7 @@ public sealed class HtmlSettings : SettingsBase, IMinifierSettings [Description("Update any .min.html file when saving the corresponding .html file. To create a .min.html file, right-click a .html file.")] [DefaultValue(false)] public bool AutoMinify { get; set; } + [Category("Minification")] [DisplayName("Create gzipped files")] [Description("Also save separate gzipped files when minifying. This option has no effect when Minify on save is disabled.")] @@ -162,6 +168,7 @@ protected override void ResetCustom() ImageDropFormats.Add(new ImageDropFormat("Inline CSS", @"
")); } } + public sealed class ImageDropFormat : SettingsBase { public ImageDropFormat() { } @@ -173,6 +180,7 @@ public ImageDropFormat(string name, string htmlFormat) public string Name { get; set; } public string HtmlFormat { get; set; } } + public sealed class JavaScriptSettings : LinterSettings, IMinifierSettings { #region Minification @@ -201,6 +209,7 @@ public sealed class JavaScriptSettings : LinterSettings, IMi [DefaultValue(true)] public bool BlockCommentCompletion { get; set; } } + public sealed class CssSettings : SettingsBase, IMinifierSettings { #region Minification @@ -294,6 +303,7 @@ public abstract class CompilationSettings : SettingsBase, ICompilerInvocat [Description("Compile files when saving them, if a compiled file already exists.")] [DefaultValue(true)] public bool CompileOnSave { get; set; } + [Category("Compilation")] [DisplayName("Compile files on build")] [Description("Compile all files that have matching compiled files when building the project.")] @@ -311,6 +321,12 @@ public abstract class CompilationSettings : SettingsBase, ICompilerInvocat [Description("Generate source map files when minifying. This option has no effect when Minify is disabled.")] [DefaultValue(true)] public bool GenerateSourceMaps { get; set; } + + [Category("Compilation")] + [DisplayName("Don't save raw compilation output")] + [Description("Don't save separate unminified compiler output. This option has no effect when Minify On Save is disabled for the output format.")] + [DefaultValue(false)] + public bool MinifyInPlace { get; set; } } public sealed class SassSettings : CompilationSettings { } @@ -387,6 +403,13 @@ public sealed class MarkdownSettings : SettingsBase, ICompiler [DefaultValue(false)] public bool StrictBoldItalic { get; set; } string IMarkdownOptions.EmptyElementSuffix { get { return GenerateXHTML ? " />" : ">"; } } + + [Category("Compilation")] + [DisplayName("Don't save raw compilation output")] + [Description("Don't save separate unminified compiler output. This option has no effect when Minify On Save is disabled for HTML.")] + [DefaultValue(false)] + public bool MinifyInPlace { get; set; } + } public interface IMarginSettings @@ -399,6 +422,7 @@ public interface ICompilerInvocationSettings bool CompileOnSave { get; } bool CompileOnBuild { get; } string OutputDirectory { get; } + bool MinifyInPlace { get; } } public interface IMinifierSettings { diff --git a/WebEssentialsTests/IntegrationTests/Completion/JsIntelliSenseTest.cs b/WebEssentialsTests/IntegrationTests/Completion/JsIntelliSenseTest.cs index c2f879d97..f36c423ab 100644 --- a/WebEssentialsTests/IntegrationTests/Completion/JsIntelliSenseTest.cs +++ b/WebEssentialsTests/IntegrationTests/Completion/JsIntelliSenseTest.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using FluentAssertions; -using MadsKristensen.EditorExtensions; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace WebEssentialsTests.IntegrationTests.Compilation