private string TryCompile(string text, IFileLookup lookup = null, bool reset = true) { Context context; Options opts; WriterMode mode; if (reset) { context = new Context(new FileCache()); opts = Options.None; mode = WriterMode.Minimize; } else { context = Current.InnerContext.Value; opts = Current.Options; mode = Current.WriterMode; } var fakeFile = "error-fake-file" + Interlocked.Increment(ref TryCompileNumber) + ".more"; var fileLookup = new TestLookup(new Dictionary<string, string>() { { fakeFile, text } }, lookup); var compiler = Compiler.Get(); compiler.Compile(Environment.CurrentDirectory, fakeFile, fakeFile + ".out", fileLookup, context, opts, mode); return fileLookup.WriteMap.ElementAt(0).Value; }
public TestLookup(Dictionary<string, string> map, IFileLookup inner) { ReadMap = map; InnerLookup = inner; }
public bool Compile(string currentDir, string inputFile, string outputFile, IFileLookup lookup, Context context, Options options, WriterMode writerMode) { Current.SetContext(context); Current.SetWriterMode(writerMode); Current.SetOptions(options); CompilationTask noop = (List <Block> blocks) => blocks; var tasks = new List <CompilationTask>() { Tasks.Using.Task, References.Task, Charsets.Task, Tasks.Import.Task, Reset.Task, Sprite.Task, Mixin.Task, UnrollNestedMedia.Task, UnrollNestedSelectors.Task, UnrollVerify.Task, Tasks.Media.Task, Includes.Task, ResetIncludes.Task, Evaluate.Task, Important.Task, NoOps.Task, FontFace.Task, ResetReOrder.Task, Verify.Task, Current.Options.HasFlag(Options.Minify) ? Minify.Task : noop, Collapse.Task, WriteSprites.Task, Current.Options.HasFlag(Options.GenerateCacheBreakers) ? CacheBreak.Task : noop, Current.Options.HasFlag(Options.AutomateVendorPrefixes) ? AutoPrefix.Task : noop, Write.Task }; try { Current.SetWorkingDirectory(currentDir); Current.SetFileLookup(lookup); inputFile = Path.IsPathRooted(inputFile) ? inputFile : inputFile.RebaseFile(); Current.SetInitialFile(inputFile); List <Block> blocks; using (var stream = lookup.Find(inputFile)) { blocks = Parse.Task(stream); } using (var output = lookup.OpenWrite(outputFile)) { Current.SetOutputStream(output); if (blocks == null) { return(false); } foreach (var task in tasks) { blocks = task(blocks); if (Current.HasErrors()) { return(false); } } } Current.Dependecies.FileCompiled(inputFile, blocks); return(true); } catch (StoppedCompilingException) { return(false); } }
public bool Compile(string currentDir, string inputFile, string outputFile, IFileLookup lookup, Context context, Options options, WriterMode writerMode) { Current.SetContext(context); Current.SetWriterMode(writerMode); Current.SetOptions(options); CompilationTask noop = (List<Block> blocks) => blocks; var tasks = new List<CompilationTask>() { Tasks.Using.Task, References.Task, Charsets.Task, Tasks.Import.Task, Reset.Task, Sprite.Task, Mixin.Task, Unroll.Task, Tasks.Media.Task, Includes.Task, ResetIncludes.Task, Evaluate.Task, Important.Task, NoOps.Task, FontFace.Task, ResetReOrder.Task, Verify.Task, Current.Options.HasFlag(Options.Minify) ? Minify.Task : noop, Collapse.Task, Write.Task, WriteSprites.Task }; try { Current.SetWorkingDirectory(currentDir); Current.SetFileLookup(lookup); inputFile = inputFile.RebaseFile(); Current.SetInitialFile(inputFile); List<Block> blocks; using (var stream = lookup.Find(inputFile)) { blocks = Parse.Task(stream); } using (var output = lookup.OpenWrite(outputFile)) { Current.SetOutputStream(output); if (blocks == null) return false; foreach (var task in tasks) { blocks = task(blocks); if (Current.HasErrors()) return false; } } return true; } catch (StoppedCompilingException) { return false; } }
private string TryCompile(string text, string fakeFile = null, IFileLookup lookup = null, bool minify = false, WriterMode mode = WriterMode.Minimize, bool cacheBreak = false, bool prefix = false) { if (mode == WriterMode.Minimize) { try { TryCompile(text, null, lookup, minify, WriterMode.Pretty); } catch (Exception e) { Assert.Fail("Pretty writing failed"); } } fakeFile = fakeFile ?? "compiler-fake-file " + Interlocked.Increment(ref TryCompileNumber) + ".more"; Options opts = Options.None; if (minify) { opts |= Options.Minify; } if (cacheBreak) { opts |= Options.GenerateCacheBreakers; } if (prefix) { opts |= Options.AutomateVendorPrefixes; } var fileLookup = new TestLookup(new Dictionary<string, string>() { { fakeFile, text } }, lookup); var compiler = Compiler.Get(); var ctx = new Context(new FileCache()); // it's hard to test minification steps if they all always run, so let's just go for a single pass in the "text comparison" cases // still do the full thing when we're doing our test "pretty pass" elsewhere to make sure it always terminates ctx.DisableMultipleMinificationPasses = mode != WriterMode.Pretty; compiler.Compile(Environment.CurrentDirectory, fakeFile, fakeFile + ".out", fileLookup, ctx, opts, mode); var ret = fileLookup.WriteMap.ElementAt(0).Value; return ret; }
public TestLookup(Dictionary <string, string> map, IFileLookup inner) { ReadMap = map; InnerLookup = inner; }
public static void SetFileLookup(IFileLookup fileLookup) { FileLookup = fileLookup; }
private static List <Block> EvaluateUsingsImpl(string initialFile, List <Block> initialStatements, IFileLookup lookup) { var imports = new List <Tuple <Model.Using, List <Block> > >(); imports.Add(Tuple.Create((Model.Using)null, initialStatements)); var unresolved = new List <Tuple <string, Model.Using> >(); unresolved.AddRange( initialStatements.OfType <Model.Using>().Select( u => Tuple.Create( u.RawPath.Replace('/', Path.DirectorySeparatorChar).RebaseFile(initialFile), u ) ) ); while (unresolved.Count > 0) { var allFiles = unresolved.Select(s => s.Item1); var loaded = Current.FileCache.Available( allFiles, delegate(string file) { var toResolve = unresolved.Single(w => w.Item1 == file); using (var @in = lookup.Find(file)) { var newParser = Parser.Parser.CreateParser(); var statements = Parse.CheckPostImport(newParser.Parse(file, @in)); if (statements == null) { Current.RecordError(ErrorType.Compiler, toResolve.Item2, "Could not resolve @using '" + toResolve.Item2.RawPath + "'"); return(null); } return(statements); } } ); var @using = unresolved.Single(s => s.Item1 == loaded.Item1); imports.Add(Tuple.Create(@using.Item2, loaded.Item2)); unresolved.RemoveAll(a => a.Item1 == loaded.Item1); if (loaded.Item2 != null) { var references = loaded.Item2.OfType <Model.Using>().Where(a => !imports.Any(x => x.Item1 == a)); foreach (var subRef in references) { unresolved.Add( Tuple.Create( subRef.RawPath.Replace('/', Path.DirectorySeparatorChar).RebaseFile(loaded.Item1), subRef ) ); } } } // Can't nest @media via @using foreach (var loaded in imports) { if (loaded.Item1 == null || (loaded.Item1.MediaQuery is MediaType && ((MediaType)loaded.Item1.MediaQuery).Type == Model.Media.all)) { continue; } if (loaded.Item2.OfType <MediaBlock>().Count() != 0) { Current.RecordError(ErrorType.Compiler, loaded.Item1, "Cannot nest @media rules via @imports"); } } // Can't continue if there's goofy nesting going on if (Current.HasErrors()) { throw new StoppedCompilingException(); } var ret = new List <Block>(); foreach (var loaded in imports.Where(w => w.Item1 == null || (w.Item1.MediaQuery is MediaType && ((MediaType)w.Item1.MediaQuery).Type == Model.Media.all))) { ret.AddRange(loaded.Item2); } foreach (var loaded in imports.Where(w => w.Item1 != null && !(w.Item1.MediaQuery is MediaType && ((MediaType)w.Item1.MediaQuery).Type == Model.Media.all))) { var statements = loaded.Item2; ret.AddRange(statements.OfType <MixinBlock>()); ret.AddRange(statements.OfType <KeyFramesBlock>()); ret.AddRange(statements.OfType <FontFaceBlock>()); var inner = statements.Where(w => !(w is MixinBlock || w is KeyFramesBlock || w is FontFaceBlock)); ret.Add(new MediaBlock(loaded.Item1.MediaQuery, inner.ToList(), loaded.Item1.Start, loaded.Item1.Stop, loaded.Item1.FilePath)); } // Record dependencies initialStatements .OfType <Model.Using>() .Each( u => Current.Dependecies.UsingResolved(initialFile, u.RawPath) ); return(ret); }
private static List<Block> EvaluateUsingsImpl(string initialFile, List<Block> initialStatements, IFileLookup lookup) { var imports = new List<Tuple<Model.Using, List<Block>>>(); imports.Add(Tuple.Create((Model.Using)null, initialStatements)); var unresolved = new List<Tuple<string, Model.Using>>(); unresolved.AddRange( initialStatements.OfType<Model.Using>().Select( u => Tuple.Create( u.RawPath.Replace('/', Path.DirectorySeparatorChar).RebaseFile(initialFile), u ) ) ); while (unresolved.Count > 0) { var allFiles = unresolved.Select(s => s.Item1); var loaded = Current.FileCache.Available( allFiles, delegate(string file) { var toResolve = unresolved.Single(w => w.Item1 == file); using (var @in = lookup.Find(file)) { var newParser = Parser.Parser.CreateParser(); var statements = Parse.CheckPostImport(newParser.Parse(file, @in)); if (statements == null) { Current.RecordError(ErrorType.Compiler, toResolve.Item2, "Could not resolve @using '" + toResolve.Item2.RawPath + "'"); return null; } return statements; } } ); var @using = unresolved.Single(s => s.Item1 == loaded.Item1); imports.Add(Tuple.Create(@using.Item2, loaded.Item2)); unresolved.RemoveAll(a => a.Item1 == loaded.Item1); if (loaded.Item2 != null) { var references = loaded.Item2.OfType<Model.Using>().Where(a => !imports.Any(x => x.Item1 == a)); foreach(var subRef in references) { unresolved.Add( Tuple.Create( subRef.RawPath.Replace('/', Path.DirectorySeparatorChar).RebaseFile(loaded.Item1), subRef ) ); } } } // Can't nest @media via @using foreach (var loaded in imports) { if (loaded.Item1 == null || (loaded.Item1.MediaQuery is MediaType && ((MediaType)loaded.Item1.MediaQuery).Type == Model.Media.all)) continue; if (loaded.Item2.OfType<MediaBlock>().Count() != 0) { Current.RecordError(ErrorType.Compiler, loaded.Item1, "Cannot nest @media rules via @imports"); } } // Can't continue if there's goofy nesting going on if (Current.HasErrors()) throw new StoppedCompilingException(); var ret = new List<Block>(); foreach (var loaded in imports.Where(w => w.Item1 == null || (w.Item1.MediaQuery is MediaType && ((MediaType)w.Item1.MediaQuery).Type == Model.Media.all))) { ret.AddRange(loaded.Item2); } foreach (var loaded in imports.Where(w => w.Item1 != null && !(w.Item1.MediaQuery is MediaType && ((MediaType)w.Item1.MediaQuery).Type == Model.Media.all))) { var statements = loaded.Item2; ret.AddRange(statements.OfType<MixinBlock>()); ret.AddRange(statements.OfType<KeyFramesBlock>()); ret.AddRange(statements.OfType<FontFaceBlock>()); var inner = statements.Where(w => !(w is MixinBlock || w is KeyFramesBlock || w is FontFaceBlock)); ret.Add(new MediaBlock(loaded.Item1.MediaQuery, inner.ToList(), loaded.Item1.Start, loaded.Item1.Stop, loaded.Item1.FilePath)); } // Record dependencies initialStatements .OfType<Model.Using>() .Each( u => Current.Dependecies.UsingResolved(initialFile, u.RawPath) ); return ret; }