public void Process(BundleContext context, BundleResponse bundle) { context.HttpContext.Response.Cache.SetLastModifiedFromFileDependencies(); var lessParser = new Parser(); ILessEngine lessEngine = CreateLessEngine(lessParser); var content = new StringBuilder(); var bundleFiles = new List<BundleFile>(); foreach (var bundleFile in bundle.Files) { bundleFiles.Add(bundleFile); SetCurrentFilePath(lessParser, bundleFile.VirtualFile.VirtualPath); using (var reader = new StreamReader(VirtualPathProvider.OpenFile(bundleFile.VirtualFile.VirtualPath))) { content.Append(lessEngine.TransformToCss(reader.ReadToEnd(), bundleFile.VirtualFile.VirtualPath)); content.AppendLine(); bundleFiles.AddRange(GetFileDependencies(lessParser)); } } if (BundleTable.EnableOptimizations) { // include imports in bundle files to register cache dependencies bundle.Files = bundleFiles.Distinct().ToList(); } bundle.ContentType = "text/css"; bundle.Content = content.ToString(); }
/// <summary> /// Processes the specified bundle of LESS files. /// </summary> /// <param name="context"> </param> /// <param name="bundle">The LESS bundle.</param> public void Process(BundleContext context, BundleResponse bundle) { if (bundle == null) throw new ArgumentNullException("bundle"); context.HttpContext.Response.Cache.SetLastModifiedFromFileDependencies(); var parser = new Parser(); var engine = new LessEngine(parser); var content = new StringBuilder(); foreach (var file in bundle.Files) { // set current file path SetCurrentFilePath(parser, file.FullName); var text = File.ReadAllText(file.FullName); var css = engine.TransformToCss(text, file.FullName); content.AppendLine(css); // content.Append(engine.TransformToCss(text, file.FullName)); // content.AppendLine(); AddFileDependencies(parser); } bundle.Content = content.ToString(); bundle.ContentType = "text/css"; }
private ILessEngine GetEngine() { var importer = new Importer(new FileReader(new CustomPathResolver(filePath))); var parser = new Parser(new PlainStylizer(), importer); var engine = new LessEngine(parser); return engine; }
/// <summary> /// Informs the LESS parser about the path to the currently processed file. /// This is done by using custom <see cref="IPathResolver"/> implementation. /// </summary> /// <param name="lessParser">The LESS parser.</param> /// <param name="currentFilePath">The path to the currently processed file.</param> private void SetCurrentFilePath(dotless.Core.Parser.Parser lessParser, string currentFilePath) { var importer = lessParser.Importer as Importer; if (importer != null) { var fileReader = importer.FileReader as FileReader; if (fileReader == null) { importer.FileReader = fileReader = new FileReader(); } var pathResolver = fileReader.PathResolver as ImportedFilePathResolver; if (pathResolver != null) { pathResolver.CurrentFilePath = currentFilePath; } else { fileReader.PathResolver = new ImportedFilePathResolver(currentFilePath); } } else { throw new InvalidOperationException("Unexpected importer type on dotless parser"); } }
public void Process(BundleContext context, BundleResponse bundle) { if (bundle == null) { throw new ArgumentNullException("bundle"); } context.HttpContext.Response.Cache.SetLastModifiedFromFileDependencies(); var lessParser = new dotless.Core.Parser.Parser(); ILessEngine lessEngine = CreateLessEngine(lessParser); var content = new StringBuilder(bundle.Content.Length); foreach (FileInfo file in bundle.Files) { SetCurrentFilePath(lessParser, file.FullName); string source = File.ReadAllText(file.FullName); content.Append(lessEngine.TransformToCss(source, file.FullName)); content.AppendLine(); AddFileDependencies(lessParser); } bundle.ContentType = "text/css"; bundle.Content = content.ToString(); }
ILessEngine CreateLessEngine(string path) { var importer = new Importer(new MulderFileReader(fileSystem, path)); var parser = new Parser(new PlainStylizer(), importer); var engine = new LessEngine(parser) { Compress = true }; return engine; }
// // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // public NodeList Primary(Parser parser) { Node node; var root = new NodeList(); NodeList comments = null; GatherComments(parser); while (node = MixinDefinition(parser) || Rule(parser) || PullComments() || Ruleset(parser) || MixinCall(parser) || Directive(parser)) { if (comments = PullComments()) { root.AddRange(comments); } comments = node as NodeList; if (comments) { foreach (Comment c in comments) { c.IsPreSelectorComment = true; } root.AddRange(comments); } else root.Add(node); GatherComments(parser); } return root; }
public void Process(BundleContext context, BundleResponse bundle) { if (bundle == null) { throw new ArgumentNullException("bundle"); } context.HttpContext.Response.Cache.SetLastModifiedFromFileDependencies(); var lessParser = new Parser(); ILessEngine lessEngine = CreateLessEngine(lessParser); var content = new StringBuilder(bundle.Content.Length); foreach (FileInfo file in bundle.Files) { SetCurrentFilePath(lessParser, file.FullName); string source = File.ReadAllText(file.FullName); content.Append(lessEngine.TransformToCss(source, file.FullName)); content.AppendLine(); AddFileDependencies(lessParser); } bundle.ContentType = "text/css"; bundle.Content = content.ToString(); }
public string TransformToCss(string source, string fileName) { var sb = new StringBuilder(); var parameters = parameterSource.GetParameters() .Where(ValueIsNotNullOrEmpty); var parser = new Parser.Parser(); sb.Append(source); foreach (var parameter in parameters) { sb.AppendLine(); var variableDeclaration = string.Format("@{0}: {1};", parameter.Key, parameter.Value); try { // Attempt to evaluate the generated variable to see if it's OK parser.Parse(variableDeclaration, "").ToCSS(new Env()); sb.Append(variableDeclaration); } catch (ParserException) { // Result wasn't valid LESS, output a comment instead sb.AppendFormat("/* Omitting variable '{0}'. The expression '{1}' is not valid. */", parameter.Key, parameter.Value); } } return Underlying.TransformToCss(sb.ToString(), fileName); }
private ILessEngine GetEngine() { var importer = new Importer(new CustomFileReader(fileSystem, filePath)); var parser = new Parser(new PlainStylizer(), importer); var engine = new LessEngine(parser) { Compress = true }; return engine; }
private ILessEngine GetLessEngine(string physicalPath) { var basePath = Path.GetDirectoryName(physicalPath); var stylizer = new PlainStylizer(); var importer = new Importer(new FileReader(new BasePathResolver(basePath))); var parser = new Parser(stylizer, importer) { NodeProvider = new RawUrlNodeProvider() }; var lessEngine = new LessEngine(parser); return lessEngine; }
public ILessEngine GetEngine(IFileSystem fileSystem, string directory) { IStylizer stylizer = new HtmlStylizer(); IPathResolver pathResolver = new TestPathResolver(directory); IFileReader reader = new TestFileReader(fileSystem, pathResolver); var importer = new Importer(reader); var parser = new Parser(stylizer, importer); ILogger logger = new ConsoleLogger(LogLevel.Error); return new LessEngine(parser, logger, true, true); }
/// <summary> /// Adds imported files to the collection of files on which the current response is dependent. /// </summary> /// <param name="lessParser">The LESS parser.</param> private void AddFileDependencies(dotless.Core.Parser.Parser lessParser) { IPathResolver pathResolver = GetPathResolver(lessParser); foreach (string importedFilePath in lessParser.Importer.Imports) { string fullPath = pathResolver.GetFullPath(importedFilePath); HttpContext.Current.Response.AddFileDependency(fullPath); } lessParser.Importer.Imports.Clear(); }
/// <summary> /// Adds imported files to the collection of files on which the current response is dependent. /// </summary> /// <param name="lessParser">The LESS parser.</param> private void AddFileDependencies(Parser lessParser) { IPathResolver pathResolver = GetPathResolver(lessParser); foreach (string importedFilePath in lessParser.Importer.Imports) { string fullPath = pathResolver.GetFullPath(importedFilePath); HttpContext.Current.Response.AddFileDependency(fullPath); } lessParser.Importer.Imports.Clear(); }
// // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // public List<Node> Primary(Parser parser) { Node node; var root = new List<Node>(); while (node = MixinDefinition(parser) || Rule(parser) || Ruleset(parser) || MixinCall(parser) || Comment(parser) || Directive(parser)) { root.Add(node); } return root; }
// We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. public Comment Comment(Parser parser) { var index = parser.Tokenizer.Location.Index; string comment = parser.Tokenizer.GetComment(); if (comment != null) { return NodeProvider.Comment(comment, comment.StartsWith("//"), index); } return null; }
public LessEngine(Parser.Parser parser, ILogger logger, bool compress, bool debug, bool disableVariableRedefines, bool disableColorCompression, bool keepFirstSpecialComment, bool strictMath, IEnumerable<IPluginConfigurator> plugins) { Parser = parser; Logger = logger; Compress = compress; Debug = debug; DisableVariableRedefines = disableVariableRedefines; Plugins = plugins; KeepFirstSpecialComment = keepFirstSpecialComment; DisableColorCompression = disableColorCompression; StrictMath = strictMath; }
public static string Generate(string fileName, string less, string color1, string color2) { var reader = new CustomFileReader(color1, color2); var importer = new Importer(reader); var parser = new Parser(new PlainStylizer(), importer, false); var lessEngine = new LessEngine(parser, NullLogger.Instance, true, false); less = Regex.Replace(less, "\\.theme-color\\(([a-z-]+),? ?", Evaluate); lessEngine.CurrentDirectory = Path.GetDirectoryName(fileName); return lessEngine.TransformToCss(less, Path.GetFileName(fileName)); }
/// <summary> /// The process. /// </summary> /// <param name="context"> /// The context. /// </param> /// <param name="bundle"> /// The bundle. /// </param> /// <exception cref="ArgumentNullException"> /// Argument NULL Exception /// </exception> public void Process(BundleContext context, BundleResponse bundle) { if (context == null) { throw new ArgumentNullException("context"); } if (bundle == null) { throw new ArgumentNullException("bundle"); } context.HttpContext.Response.Cache.SetLastModifiedFromFileDependencies(); var lessParser = new Parser(); var lessEngine = this.CreateLessEngine(lessParser); var content = new StringBuilder(bundle.Content.Length); var bundleFiles = new List<BundleFile>(); foreach (var bundleFile in bundle.Files) { bundleFiles.Add(bundleFile); var filePath = bundleFile.IncludedVirtualPath; filePath = filePath.Replace('\\', '/'); if (filePath.StartsWith("~")) { filePath = VirtualPathUtility.ToAbsolute(filePath); } if (filePath.StartsWith("/")) { filePath = HostingEnvironment.MapPath(filePath); } this.SetCurrentFilePath(lessParser, filePath); var source = File.ReadAllText(filePath); content.Append(lessEngine.TransformToCss(source, filePath)); content.AppendLine(); bundleFiles.AddRange(this.GetFileDependencies(lessParser, bundleFile.VirtualFile)); } if (BundleTable.EnableOptimizations) { // include imports in bundle files to register cache dependencies bundle.Files = bundleFiles.Distinct(); } bundle.ContentType = "text/css"; bundle.Content = content.ToString(); }
/// <summary> /// Construct LESS Parser /// </summary> /// <param name="file"></param> /// <param name="config"></param> /// <returns></returns> private static Parser GetParser(string file, DotlessConfiguration config) { var fullPath = HttpContext.Current.Server.MapPath(file); var parser = new Parser(); var fileReader = new WebFileReader(new WebPathResolver(fullPath)); var importer = new WebImporter(fileReader, config.DisableUrlRewriting, config.InlineCssFiles, config.ImportAllFilesAsLess); parser.Importer = importer; return parser; }
protected override string ReadFileContent(string fileSystemPath, bool minify) { var directory = Path.GetDirectoryName(fileSystemPath); var pathResolver = new AbsolutePathResolver(directory); var fileReader = new FileReader { PathResolver = pathResolver }; var importer = new Importer { FileReader = fileReader }; var parser = new Parser { Importer = importer }; var lessEngine = new LessEngine { Parser = parser }; var rawFileContent = base.ReadFileContent(fileSystemPath, false); return lessEngine.TransformToCss(rawFileContent, fileSystemPath); }
/// <summary> /// Returns an <see cref="IPathResolver"/> instance used by the specified LESS lessParser. /// </summary> /// <param name="lessParser">The LESS prser.</param> private IPathResolver GetPathResolver(Parser lessParser) { var importer = lessParser.Importer as Importer; if (importer != null) { var fileReader = importer.FileReader as FileReader; if (fileReader != null) { return fileReader.PathResolver; } } return null; }
/// <summary> /// Returns an <see cref="IPathResolver"/> instance used by the specified LESS lessParser. /// </summary> /// <param name="lessParser">The LESS prser.</param> private IPathResolver GetPathResolver(dotless.Core.Parser.Parser lessParser) { var importer = lessParser.Importer as Importer; if (importer != null) { var fileReader = importer.FileReader as FileReader; if (fileReader != null) { return(fileReader.PathResolver); } } return(null); }
public CompileResult Compile(string source, CompileContext context) { var sourceFile = context.RootDirectory.GetFile(context.SourceFilePath); importedFilePaths = new HashedSet<string>(); var parser = new Parser { Importer = new Importer(new CassetteLessFileReader(sourceFile.Directory, importedFilePaths)) }; var errorLogger = new ErrorLogger(); var engine = new LessEngine( parser, errorLogger, configuration.MinifyOutput, configuration.Debug, configuration.DisableVariableRedefines, configuration.DisableColorCompression, configuration.KeepFirstSpecialComment, configuration.Plugins); string css; try { css = engine.TransformToCss(source, sourceFile.FullPath); } catch (Exception ex) { throw new LessCompileException( string.Format("Error compiling {0}{1}{2}", context.SourceFilePath, Environment.NewLine, ex.Message), ex ); } if (errorLogger.HasErrors) { var exceptionMessage = string.Format( "Error compiling {0}{1}{2}", context.SourceFilePath, Environment.NewLine, errorLogger.ErrorMessage ); throw new LessCompileException(exceptionMessage); } else { return new CompileResult(css, importedFilePaths); } }
// We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. public Node Comment(Parser parser) { if (parser.Tokenizer.CurrentChar != '/') return null; var index = parser.Tokenizer.Location.Index; var comment = parser.Tokenizer.Match(@"//.*"); if(comment) return NodeProvider.Comment(comment.Value, true, index); comment = parser.Tokenizer.Match(@"/\*(?:[^*]|\*+[^\/*])*\*+/\n?"); if (comment) return NodeProvider.Comment(comment.Value, index); return null; }
public string Compile(string source, IFile sourceFile) { var parser = new Parser { Importer = new Importer(new CassetteLessFileReader(sourceFile.Directory)) }; var errorLogger = new ErrorLogger(); var engine = new LessEngine(parser, errorLogger, false); var css = engine.TransformToCss(source, sourceFile.FullPath); if (errorLogger.HasErrors) { throw new LessCompileException(errorLogger.ErrorMessage); } else { return css; } }
/// <summary> /// Transforms the content of the given string from Less into CSS. /// </summary> /// <param name="input">The input string to transform.</param> /// <param name="path">The path to the given input string to transform.</param> /// <param name="cruncher">The cruncher that is running the transform.</param> /// <returns>The transformed string.</returns> public string Transform(string input, string path, CruncherBase cruncher) { // The standard engine returns a FileNotFoundExecption so I've rolled my own path resolver. Parser parser = new Parser(); DotLessPathResolver dotLessPathResolver = new DotLessPathResolver(path); FileReader fileReader = new FileReader(dotLessPathResolver); parser.Importer = new Importer(fileReader); ILessEngine lessEngine = new LessEngine(parser); try { string result = lessEngine.TransformToCss(input, path); if (cruncher.Options.CacheFiles) { // Add each import as a file dependency so that the cache will clean itself. IEnumerable<string> imports = lessEngine.GetImports(); IList<string> enumerable = imports as IList<string> ?? imports.ToList(); if (enumerable.Any()) { foreach (string import in enumerable) { if (!import.Contains(Uri.SchemeDelimiter)) { string filePath = HostingEnvironment.MapPath(VirtualPathUtility.Combine(dotLessPathResolver.CurrentFileDirectory, import)); cruncher.AddFileMonitor(filePath, "not empty"); } } } } return result; } catch (Exception ex) { throw new LessCompilingException(ex.Message, ex.InnerException); } }
/// <summary> /// Transforms some LESS source code (and any related files) to CSS. /// </summary> /// <param name="source">The LESS code to transform.</param> /// <param name="file">The context file system.</param> public string Compile(string source, IFile file) { var parser = new Parser {Importer = new Importer(new LessFileReader(file.Directory))}; var engine = new LessEngine(parser, _logger, false, false); string css = null; try { css = engine.TransformToCss(source, file.Name); } catch (FileNotFoundException ex) { _logger.Error("The file you are trying to import '{0}' cannot be found.".FormatWith(ex.FileName)); } if (_logger.HasErrors) throw new LessCompileException(_logger.ErrorMessage); return css; }
public override dotless.Core.Parser.Infrastructure.Nodes.Node Execute(dotless.Core.Parser.Infrastructure.Nodes.Node node, out bool visitDeeper) { visitDeeper = true; if (node is Rule) { var rule = node as Rule; if (rule.Variable) { if (_variables.ContainsKey(rule.Name.TrimStart(Convert.ToChar("@")))) { var overrideValue = _variables[rule.Name.TrimStart(Convert.ToChar("@"))]; if (!string.IsNullOrEmpty(overrideValue)) { var parse = new Parser(); var ruleset = parse.Parse(rule.Name + ": " + overrideValue + ";", "variableoverrideplugin.less"); return ruleset.Rules[0] as Rule; } } } } return node; }
public LessEngine(Parser.Parser parser, ILogger logger, bool compress, bool debug, bool disableVariableRedefines) : this(parser, logger, compress, debug, disableVariableRedefines, false, false, null) { }
public LessEngine(Parser.Parser parser, ILogger logger, dotless.Core.configuration.DotlessConfiguration config) : this(parser, logger, config.MinifyOutput, config.Debug, config.DisableVariableRedefines, config.DisableColorCompression, config.KeepFirstSpecialComment, config.Plugins) { }
/// <summary> /// Informs the LESS parser about the path to the currently processed file. /// This is done by using a custom <see cref="IPathResolver"/> implementation. /// </summary> /// <param name="lessParser">The LESS parser.</param> /// <param name="currentFilePath">The path to the currently processed file.</param> private void SetCurrentFilePath(Parser lessParser, string currentFilePath) { var importer = lessParser.Importer as Importer; if (importer == null) { throw new InvalidOperationException("Unexpected dotless importer type."); } var fileReader = importer.FileReader as FileReader; if (fileReader == null || !(fileReader.PathResolver is ImportedFilePathResolver)) { fileReader = new FileReader(new ImportedFilePathResolver(currentFilePath)); importer.FileReader = fileReader; } }
/// <summary> /// Gets the file dependencies (@imports) of the LESS file being parsed. /// </summary> /// <param name="lessParser">The LESS parser.</param> /// <param name="virtualFile">The virtual file</param> /// <returns>An array of file references to the dependent file references.</returns> private IEnumerable<BundleFile> GetFileDependencies(Parser lessParser, VirtualFile virtualFile) { var pathResolver = this.GetPathResolver(lessParser); foreach (var importPath in lessParser.Importer.Imports) { yield return new BundleFile(pathResolver.GetFullPath(importPath), virtualFile); } lessParser.Importer.Imports.Clear(); }
/// <summary> /// Creates an instance of LESS engine. /// </summary> /// <param name="lessParser"> /// The LESS parser. /// </param> /// <returns> /// The <see cref="ILessEngine"/>. /// </returns> private ILessEngine CreateLessEngine(Parser lessParser) { var logger = new AspNetTraceLogger(LogLevel.Debug, new Http()); return new LessEngine(lessParser, logger, true, false); }
private IEnumerable<VirtualFile> GetFileDependencies(Parser lessParser) { var pathResolver = this.GetPathResolver(lessParser); foreach (var importPath in lessParser.Importer.Imports) { yield return HostingEnvironment.VirtualPathProvider.GetFile(pathResolver.GetFullPath(importPath)); } }
public void Process(BundleContext context, BundleResponse bundle) { context.HttpContext.Response.Cache.SetLastModifiedFromFileDependencies(); var content = new StringBuilder(); var bundleFiles = new List<BundleFile>(); foreach (var bundleFile in bundle.Files) { var lessParser = new Parser(); ILessEngine lessEngine = this.CreateLessEngine(lessParser); bool foundMinimizedVersion = false; bundleFiles.Add(bundleFile); if (BundleTable.EnableOptimizations) { var ext = Path.GetExtension(bundleFile.VirtualFile.VirtualPath); if (ext != null && ext.Equals(".less", StringComparison.InvariantCultureIgnoreCase)) { var filepath = bundleFile.VirtualFile.VirtualPath; var minimizedFileName = string.Format( "{0}.min.css", filepath.Substring(0, filepath.LastIndexOf(ext, StringComparison.Ordinal))); var virtualPathProvider = HostingEnvironment.VirtualPathProvider; if (virtualPathProvider.FileExists(minimizedFileName)) { var minimizedFile = virtualPathProvider.GetFile(minimizedFileName); foundMinimizedVersion = true; using (var reader = new StreamReader(minimizedFile.Open())) { content.Append(reader.ReadToEnd()); content.AppendLine(); bundleFiles.Add(new BundleFile(minimizedFile.VirtualPath, minimizedFile)); } } } } if (!foundMinimizedVersion) { this.SetCurrentFilePath(lessParser, bundleFile.VirtualFile.VirtualPath); using (var reader = new StreamReader(VirtualPathProvider.OpenFile(bundleFile.VirtualFile.VirtualPath))) { var fileContent = reader.ReadToEnd(); content.Append(lessEngine.TransformToCss(fileContent, bundleFile.VirtualFile.VirtualPath)); content.AppendLine(); bundleFiles.AddRange(this.GetFileDependencies(lessParser).Select(f => new BundleFile(f.VirtualPath, f))); } } } if (BundleTable.EnableOptimizations) { // include imports in bundle files to register cache dependencies bundle.Files = bundleFiles.Distinct().ToList(); } bundle.ContentType = "text/css"; bundle.Content = content.ToString(); }
public LessEngine(Parser.Parser parser, ILogger logger, bool compress) { Parser = parser; Logger = logger; Compress = compress; }
public LessEngine(Parser.Parser parser, ILogger logger, bool compress, bool debug, bool disableVariableRedefines, bool disableColorCompression, bool keepFirstSpecialComment, IEnumerable <IPluginConfigurator> plugins) : this(parser, logger, compress, debug, disableVariableRedefines, disableColorCompression, keepFirstSpecialComment, false, plugins) { }
/// <summary> /// Creates an instance of LESS engine. /// </summary> /// <param name="lessParser">The LESS parser.</param> private ILessEngine CreateLessEngine(dotless.Core.Parser.Parser lessParser) { var logger = new AspNetTraceLogger(LogLevel.Debug, new Http()); return(new LessEngine(lessParser, logger, true, false)); }
public LessEngine(Parser.Parser parser, ILogger logger, bool compress, bool debug) : this(parser, logger, compress, debug, false, false, false, null) { }
public LessEngine(Parser.Parser parser) : this(parser, new ConsoleLogger(LogLevel.Error), false, false, false, false, false, null) { }