Example #1
0
        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;
        }
Example #2
0
 public TestLookup(Dictionary<string, string> map, IFileLookup inner)
 {
     ReadMap = map;
     InnerLookup = inner;
 }
Example #3
0
        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);
            }
        }
Example #4
0
        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;
            }
        }
Example #5
0
        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;
        }
Example #6
0
 public TestLookup(Dictionary <string, string> map, IFileLookup inner)
 {
     ReadMap     = map;
     InnerLookup = inner;
 }
Example #7
0
 public static void SetFileLookup(IFileLookup fileLookup)
 {
     FileLookup = fileLookup;
 }
Example #8
0
        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);
        }
Example #9
0
 public static void SetFileLookup(IFileLookup fileLookup)
 {
     FileLookup = fileLookup;
 }
Example #10
0
        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;
        }