diff --git a/src/WebCompiler/Compile/SassCompiler.cs b/src/WebCompiler/Compile/SassCompiler.cs
index b25208cd..27134df9 100644
--- a/src/WebCompiler/Compile/SassCompiler.cs
+++ b/src/WebCompiler/Compile/SassCompiler.cs
@@ -33,6 +33,9 @@ public CompilerResult Compile(Config config)
OriginalContent = content,
};
+ if (config.GlobalMatch && string.IsNullOrWhiteSpace(content) || Path.GetFileName(config.InputFile).StartsWith("_"))
+ return result;
+
try
{
RunCompilerProcess(config, info);
diff --git a/src/WebCompiler/Config/Config.cs b/src/WebCompiler/Config/Config.cs
index c2465e23..7ddd7038 100644
--- a/src/WebCompiler/Config/Config.cs
+++ b/src/WebCompiler/Config/Config.cs
@@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
using Newtonsoft.Json;
+using WebCompiler.Helpers;
namespace WebCompiler
{
@@ -56,6 +57,8 @@ public class Config
internal string Output { get; set; }
+ internal bool GlobalMatch { get; set; }
+
///
/// Converts the relative input file to an absolute file path.
///
@@ -188,5 +191,49 @@ private static bool DictionaryEqual(
}
return true;
}
+
+ internal Config Match(string folder, string sourceFile)
+ {
+ if (sourceFile == null)
+ return null;
+
+ string inputFile = Path.Combine(folder, this.InputFile);
+
+ if (!GlobHelper.IsGlobPattern(this.InputFile))
+ return sourceFile.Equals(inputFile.Replace('/', '\\'), System.StringComparison.OrdinalIgnoreCase)
+ ? this : null;
+
+ if (GlobHelper.Glob(sourceFile, inputFile))
+ return MakeMatchedConfig(sourceFile);
+
+ return null;
+ }
+
+ Config MakeMatchedConfig(string sourceFile)
+ {
+ string compileExtension = CompileHelper.GetCompiledExtension(sourceFile);
+ return new Config()
+ {
+ InputFile = sourceFile,
+ OutputFile = Path.ChangeExtension(sourceFile, compileExtension),
+ FileName = this.FileName,
+ IncludeInProject = this.IncludeInProject,
+ Minify = this.Minify,
+ Options = this.Options,
+ Output = this.Output,
+ SourceMap = this.SourceMap
+ };
+ }
+
+ internal IEnumerable Match(string folder)
+ {
+ return Directory.EnumerateFiles(folder, this.InputFile, SearchOption.AllDirectories)
+ .Select(s =>
+ {
+ Config config = MakeMatchedConfig(s);
+ config.GlobalMatch = true;
+ return config;
+ });
+ }
}
-}
+}
\ No newline at end of file
diff --git a/src/WebCompiler/Config/ConfigFileProcessor.cs b/src/WebCompiler/Config/ConfigFileProcessor.cs
index aedc8dda..5fa719a6 100644
--- a/src/WebCompiler/Config/ConfigFileProcessor.cs
+++ b/src/WebCompiler/Config/ConfigFileProcessor.cs
@@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
using System.Text;
+using WebCompiler.Helpers;
namespace WebCompiler
{
@@ -21,7 +22,7 @@ public class ConfigFileProcessor
/// Optional configuration items in the config file
/// Forces compilation of all config items.
/// A list of compiler results.
- public IEnumerable Process(string configFile, IEnumerable configs = null, bool force = false)
+ public IEnumerable Process(string configFile, Config[] configs = null, bool force = false)
{
if (_processing.Contains(configFile))
return Enumerable.Empty();
@@ -32,18 +33,30 @@ public IEnumerable Process(string configFile, IEnumerable 0)
+ OnConfigProcessed(configs.First(), 0, configs.Length);
+ int i = 0;
foreach (Config config in configs)
{
+ ++i;
+
if (force || config.CompilationRequired())
{
- var result = ProcessConfig(info.Directory.FullName, config);
- list.Add(result);
- OnConfigProcessed(config, list.Count, configs.Count());
+ if (GlobHelper.IsGlobPattern(config.InputFile))
+ {
+ foreach (Config matchedConfig in config.Match(directory))
+ list.Add(ProcessConfig(directory, matchedConfig));
+ }
+ else
+ {
+ list.Add(ProcessConfig(directory, config));
+ }
+
+ OnConfigProcessed(config, i, configs.Length);
}
}
}
@@ -112,12 +125,11 @@ private IEnumerable SourceFileChanged(string configFile,
// Compile if the file if it's referenced directly in compilerconfig.json
foreach (Config config in configs)
{
- string input = Path.Combine(folder, config.InputFile.Replace("/", "\\"));
-
- if (input.Equals(sourceFile, StringComparison.OrdinalIgnoreCase))
+ Config matchingConfig = config.Match(folder, sourceFile);
+ if (matchingConfig != null)
{
- list.Add(ProcessConfig(folder, config));
- compiledFiles.Add(input.ToLowerInvariant());
+ list.Add(ProcessConfig(folder, matchingConfig));
+ compiledFiles.Add(matchingConfig.InputFile.ToLowerInvariant());
}
}
@@ -191,7 +203,7 @@ private CompilerResult ProcessConfig(string baseFolder, Config config)
var result = compiler.Compile(config);
- if (result.Errors.Any(e => !e.IsWarning))
+ if (result.Errors.Any(e => !e.IsWarning) || string.IsNullOrWhiteSpace(result.CompiledContent))
return result;
if (Path.GetExtension(config.OutputFile).Equals(".css", StringComparison.OrdinalIgnoreCase) && AdjustRelativePaths(config))
diff --git a/src/WebCompiler/Config/ConfigHandler.cs b/src/WebCompiler/Config/ConfigHandler.cs
index 5b827bde..7ee7d47d 100644
--- a/src/WebCompiler/Config/ConfigHandler.cs
+++ b/src/WebCompiler/Config/ConfigHandler.cs
@@ -95,16 +95,15 @@ public void CreateDefaultsFile(string fileName)
///
/// A relative or absolute file path to the configuration file.
/// A list of Config objects.
- public static IEnumerable GetConfigs(string fileName)
+ public static Config[] GetConfigs(string fileName)
{
FileInfo file = new FileInfo(fileName);
if (!file.Exists)
- return Enumerable.Empty();
+ return new Config[0];
string content = File.ReadAllText(fileName);
- var configs = JsonConvert.DeserializeObject>(content);
- string folder = Path.GetDirectoryName(file.FullName);
+ Config[] configs = JsonConvert.DeserializeObject(content);
foreach (Config config in configs)
{
diff --git a/src/WebCompiler/Helpers/CompileHelper.cs b/src/WebCompiler/Helpers/CompileHelper.cs
new file mode 100644
index 00000000..9e0b8852
--- /dev/null
+++ b/src/WebCompiler/Helpers/CompileHelper.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace WebCompiler.Helpers
+{
+ public static class CompileHelper
+ {
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static string GetCompiledExtension(string filename)
+ {
+ string extension = Path.GetExtension(filename).ToLowerInvariant();
+ switch (extension)
+ {
+ case ".coffee":
+ case ".iced":
+ case ".litcoffee":
+ case ".jsx":
+ case ".es6":
+ case ".hbs":
+ case ".handlebars":
+ return ".js";
+
+ case ".js":
+ return ".es5.js";
+
+ default:
+ return ".css";
+ }
+ }
+ }
+}
diff --git a/src/WebCompiler/Helpers/GlobHelper.cs b/src/WebCompiler/Helpers/GlobHelper.cs
new file mode 100644
index 00000000..41039797
--- /dev/null
+++ b/src/WebCompiler/Helpers/GlobHelper.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace WebCompiler.Helpers
+{
+ ///
+ /// Utils for glob matching
+ ///
+ public static class GlobHelper
+ {
+ ///
+ /// Returns true if the input text contains a basic glob character: *?
+ ///
+ ///
+ ///
+ public static bool IsGlobPattern(string text)
+ {
+ return text != null && text.LastIndexOfAny(new char[] { '*', '?' }) >= 0;
+ }
+
+ ///
+ /// String matching including basic glob patterns: *?
+ ///
+ /// string to be matched
+ /// pattern to match against
+ ///
+ public static bool Glob(this string text, string pattern)
+ {
+ StringBuilder sb = new StringBuilder(pattern, pattern.Length + 10);
+ sb.Replace('*', (char)1).Replace('?', (char)2).Replace('/', '\\');
+
+ pattern = Regex.Escape(sb.ToString());
+
+ sb.Clear().Append('^').Append(pattern).Replace("\u0001", ".*").Replace("\u0002", ".").Append('$');
+
+ return Regex.IsMatch(text, sb.ToString(), RegexOptions.IgnoreCase);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/WebCompiler/Program.cs b/src/WebCompiler/Program.cs
index 068d49db..e06cafe7 100644
--- a/src/WebCompiler/Program.cs
+++ b/src/WebCompiler/Program.cs
@@ -50,7 +50,7 @@ private static void EventHookups(ConfigFileProcessor processor, string configPat
FileMinifier.AfterWritingGzipFile += (s, e) => { Console.WriteLine($" \x1B[32mGZipped"); };
}
- private static IEnumerable GetConfigs(string configPath, string file)
+ private static Config[] GetConfigs(string configPath, string file)
{
var configs = ConfigHandler.GetConfigs(configPath);
@@ -60,9 +60,9 @@ private static IEnumerable GetConfigs(string configPath, string file)
if (file != null)
{
if (file.StartsWith("*"))
- configs = configs.Where(c => Path.GetExtension(c.InputFile).Equals(file.Substring(1), StringComparison.OrdinalIgnoreCase));
+ configs = configs.Where(c => Path.GetExtension(c.InputFile).Equals(file.Substring(1), StringComparison.OrdinalIgnoreCase)).ToArray();
else
- configs = configs.Where(c => c.InputFile.Equals(file, StringComparison.OrdinalIgnoreCase));
+ configs = configs.Where(c => c.InputFile.Equals(file, StringComparison.OrdinalIgnoreCase)).ToArray();
}
return configs;
diff --git a/src/WebCompilerTest/Config/ConfigHandlerTest.cs b/src/WebCompilerTest/Config/ConfigHandlerTest.cs
index eb809266..7109c69e 100644
--- a/src/WebCompilerTest/Config/ConfigHandlerTest.cs
+++ b/src/WebCompilerTest/Config/ConfigHandlerTest.cs
@@ -45,11 +45,9 @@ public void AddConfig()
[TestMethod, TestCategory("Config")]
public void NonExistingConfigFileShouldReturnEmptyList()
{
- var expectedResult = Enumerable.Empty();
-
var result = ConfigHandler.GetConfigs("../NonExistingFile.config");
- Assert.AreEqual(expectedResult, result);
+ Assert.AreEqual(0, result.Length);
}
}
}
diff --git a/src/WebCompilerTest/Minify/artifacts/css/minify.less b/src/WebCompilerTest/Minify/artifacts/css/minify.less
index 46800d16..64d2da4f 100644
--- a/src/WebCompilerTest/Minify/artifacts/css/minify.less
+++ b/src/WebCompilerTest/Minify/artifacts/css/minify.less
@@ -1,2 +1,3 @@
body {
+ background: black
}
diff --git a/src/WebCompilerVsix/Adornments/AdornmentProvider.cs b/src/WebCompilerVsix/Adornments/AdornmentProvider.cs
index 11ba935b..cf6bfa61 100644
--- a/src/WebCompilerVsix/Adornments/AdornmentProvider.cs
+++ b/src/WebCompilerVsix/Adornments/AdornmentProvider.cs
@@ -9,6 +9,7 @@
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Utilities;
+using WebCompiler.Helpers;
namespace WebCompilerVsix
{
@@ -101,6 +102,11 @@ private void CreateAdornments(ITextDocument document, IWpfTextView textView)
foreach (Config config in configs)
{
+ if (GlobHelper.IsGlobPattern(config.InputFile))
+ {
+ continue;
+ }
+
if (config.GetAbsoluteOutputFile().FullName.Equals(normalizedFilePath, StringComparison.OrdinalIgnoreCase))
{
GeneratedAdornment generated = new GeneratedAdornment(textView, _isVisible, _initOpacity);
diff --git a/src/WebCompilerVsix/Commands/CreateConfig.cs b/src/WebCompilerVsix/Commands/CreateConfig.cs
index b01b632f..d32c3998 100644
--- a/src/WebCompilerVsix/Commands/CreateConfig.cs
+++ b/src/WebCompilerVsix/Commands/CreateConfig.cs
@@ -7,6 +7,7 @@
using EnvDTE80;
using Microsoft.VisualStudio.Shell;
using WebCompiler;
+using WebCompiler.Helpers;
namespace WebCompilerVsix
{
@@ -163,16 +164,7 @@ private static Config CreateConfigFile(string inputfile, string outputFile)
private static string GetOutputFileName(string inputFile)
{
- string extension = Path.GetExtension(inputFile).ToLowerInvariant();
- string ext = ".css";
-
- if (extension == ".coffee" || extension == ".iced" || extension == ".litcoffee" || extension == ".jsx" || extension == ".es6" || extension == ".hbs" || extension == ".handlebars")
- ext = ".js";
-
- if (extension == ".js")
- ext = ".es5.js";
-
- return Path.ChangeExtension(inputFile, ext);
+ return Path.ChangeExtension(inputFile, CompileHelper.GetCompiledExtension(inputFile));
}
}
}
diff --git a/src/WebCompilerVsix/CompilerService.cs b/src/WebCompilerVsix/CompilerService.cs
index 4246b9c2..d876a27c 100644
--- a/src/WebCompilerVsix/CompilerService.cs
+++ b/src/WebCompilerVsix/CompilerService.cs
@@ -51,7 +51,7 @@ private static void ConfigProcessed(object sender, ConfigProcessedEventArgs e)
_dte.StatusBar.Progress(true, "Compiling...", e.AmountProcessed, e.Total);
}
- public static void Process(string configFile, IEnumerable configs = null, bool force = false)
+ public static void Process(string configFile, Config[] configs = null, bool force = false)
{
ThreadPool.QueueUserWorkItem((o) =>
{