/// <summary>
    /// Returns a minified version of a given CSS.
    /// </summary>
    /// <param name="resource">CSS to be minified</param>
    /// <returns>Minified CSS</returns>
    public string Minify(string resource)
    {
        if (String.IsNullOrEmpty(resource))
        {
            return resource;
        }

        try
        {
            CssParser parser = new CssParser();

            // Parse the resource
            string parsed = parser.Parse(resource);
            if (!String.IsNullOrEmpty(parsed))
            {
                resource = parsed;
            }
        }
        catch (Exception ex)
        {
            // Parse throws null reference exception on some ocasions
            EventLogProvider.LogException("CSS Compression", "MINIFYCSS", ex);

            resource = "/* Minification failed: " + ex.Message + "*/\r\n\r\n" + resource;
        }

        return resource;
    }
 public string Compile(IEnumerable<string> files)
 {
     var sb = new StringBuilder();
     foreach (string file in files)
     {
         string compressed = new CssParser().Parse(File.ReadAllText(file));
         sb.Append(compressed);
         sb.Append(Environment.NewLine);
     }
     return sb.ToString();
 }
示例#3
0
        public override CombinedFileResult Parse(params string[] files)
        {
            var combined = CombineFiles(files);

            var razorResult = Razor.Parse(combined);

            var cssParser = new CssParser();
            cssParser.Settings.CommentMode = CssComment.Important;
            var minResult = cssParser.Parse(razorResult);

            string key = GenerateKey(minResult);

            return new CombinedFileResult {
                Content = minResult,
                Key = key,
            };
        }
        public void ProcessRequest(HttpContext context)
        {
            HttpRequest request = context.Request;

            // Read setName, contentType and version. All are required. They are
            // used as cache key
            string setName = request["s"] ?? string.Empty;
            string contentType = request["t"] ?? string.Empty;
            string version = request["v"] ?? string.Empty;

            // Decide if browser supports compressed response
            bool isCompressed = DO_GZIP && this.CanGZip(context.Request);

            // Response is written as UTF8 encoding. If you are using languages like
            // Arabic, you should change this to proper encoding
            UTF8Encoding encoding = new UTF8Encoding(false);

            // If the set has already been cached, write the response directly from
            // cache. Otherwise generate the response and cache it
            if (!this.WriteFromCache(context, setName, version, isCompressed, contentType)) {

                using (MemoryStream memoryStream = new MemoryStream(5000)) {

                    // Decide regular stream or GZipStream based on whether the response
                    // can be cached or not
                    using (Stream writer = isCompressed ?
                        (Stream)(new GZipStream(memoryStream, CompressionMode.Compress)) : memoryStream) {

                        // Load the files defined in and process each file
                        string setDefinition = GetFilelist(setName) ?? "";

                        string[] fileNames = setDefinition.Split(new char[] { ',' },
                            StringSplitOptions.RemoveEmptyEntries);

                        string minifiedString = string.Empty;
                        var minifier = new Minifier();
                        StringBuilder allScripts = new StringBuilder();

                        if (contentType == JS_TYPE) {
                            foreach (string fileName in fileNames) {
                                byte[] fileBytes = this.GetFileBytes(context, fileName.Trim(), encoding);
                                allScripts.Append(Encoding.UTF8.GetString(fileBytes));
                                //writer.Write(fileBytes, 0, fileBytes.Length);
                            }

                            var codeSettings = new CodeSettings();
                            codeSettings.MinifyCode = true;
                            codeSettings.OutputMode = OutputMode.SingleLine;
                            //codeSettings.OutputMode = OutputMode.MultipleLines;
                            codeSettings.InlineSafeStrings = true;
                            codeSettings.MacSafariQuirks = true;
                            codeSettings.RemoveUnneededCode = true;
                            codeSettings.LocalRenaming = LocalRenaming.CrunchAll;
                            codeSettings.EvalTreatment = EvalTreatment.MakeAllSafe;
                            //codeSettings.CombineDuplicateLiterals = true;
                            codeSettings.PreserveFunctionNames = false;
                            minifiedString = minifier.MinifyJavaScript(allScripts.ToString(), codeSettings);
                        }

                        if (contentType == CSS_TYPE) {
                            CssParser parser = new CssParser();
                            foreach (string fileName in fileNames) {
                                byte[] fileBytes = this.GetFileBytes(context, fileName.Trim(), encoding);
                                string crunchedStyles = parser.Parse(Encoding.UTF8.GetString(fileBytes));
                                allScripts.Append(crunchedStyles);
                            }

                            var cssSettings = new CssSettings();
                            cssSettings.CommentMode = CssComment.None;
                            cssSettings.ColorNames = CssColor.Strict;
                            //cssSettings.ExpandOutput = true;
                            cssSettings.TermSemicolons = true;
                            minifiedString = minifier.MinifyStyleSheet(allScripts.ToString(), cssSettings);
                        }

                        byte[] rikiki = Encoding.UTF8.GetBytes(minifiedString);
                        writer.Write(rikiki, 0, rikiki.Length);
                        writer.Close();
                    }

                    // Cache the combined response so that it can be directly written
                    // in subsequent calls
                    byte[] responseBytes = memoryStream.ToArray();
                    context.Cache.Insert(
                        GetCacheKey(setName, version, isCompressed),
                        responseBytes,
                        null,
                        Cache.NoAbsoluteExpiration,
                        CACHE_DURATION);

                    // Generate the response
                    this.WriteBytes(responseBytes, context, isCompressed, contentType);
                }
            }
        }
    /// <summary>
    /// Returns a minified version of a given CSS.
    /// </summary>
    /// <param name="resource">CSS to be minified</param>
    /// <returns>Minified CSS</returns>
    public string Minify(string resource)
    {
        if (String.IsNullOrEmpty(resource))
        {
            return resource;
        }

        // Reset error
        minificationError = null;

        try
        {
            CssParser parser = new CssParser();
            // Ignore error: 'An underscore is not a valid CSS1 or CSS2 identifier character'
            parser.Settings.IgnoreErrorList = "CSS1008";
            parser.Settings.AllowEmbeddedAspNetBlocks = true;
            parser.CssError += parser_CssError;

            // Parse the resource
            string parsed = parser.Parse(resource);
            if (!String.IsNullOrEmpty(parsed) && (minificationError == null))
            {
                resource = parsed;
            }
        }
        catch (CssException ex)
        {
            minificationError = ex;
        }

        if (minificationError != null)
        {
            if (LogMinifierParseError)
            {
                // Log exception to event log if allowed
                EventLogProvider.LogException("CSS Compression", "MINIFYCSS", minificationError);
            }

            // Add the error info to the end of non-minified resource
            resource += string.Format("\r\n\r\n/* Minification failed (line {0}, error number {1}): {2} */", minificationError.Line, minificationError.Error, minificationError.Message);
        }

        return resource;
    }
        /// <summary>
        /// Minifies the CSS stylesheet passes to it using the given settings, returning the minified results
        /// The ErrorList property will be set with any errors found during the minification process.
        /// </summary>
        /// <param name="source">CSS Source</param>
        /// <param name="settings">CSS minification settings</param>
        /// <param name="scriptSettings">JS minification settings to use for expression-minification</param>
        /// <returns>Minified StyleSheet</returns>
        public string MinifyStyleSheet(string source, CssSettings settings, CodeSettings scriptSettings)
        {
            // initialize some values, including the error list (which shoudl start off empty)
            string minifiedResults = string.Empty;
            m_errorList = new List<ContextError>();

            // create the parser object and if we specified some settings,
            // use it to set the Parser's settings object
            CssParser parser = new CssParser();
            parser.FileContext = FileName;

            if (settings != null)
            {
                parser.Settings = settings;
            }

            if (scriptSettings != null)
            {
                parser.JSSettings = scriptSettings;
            }

            // hook the error handler
            parser.CssError += new EventHandler<CssErrorEventArgs>(OnCssError);

            // try parsing the source and return the results
            try
            {
                minifiedResults = parser.Parse(source);
            }
            catch (Exception e)
            {
                m_errorList.Add(new ContextError(
                    true,
                    0,
                    null,
                    null,
                    null,
                    this.FileName,
                    0,
                    0,
                    0,
                    0,
                    e.Message));
                throw;
            }
            return minifiedResults;
        }
示例#7
0
    /// <summary>
    /// Returns a minified version of a given CSS.
    /// </summary>
    /// <param name="resource">CSS to be minified</param>
    /// <returns>Minified CSS</returns>
    public string Minify(string resource)
    {
        if (String.IsNullOrEmpty(resource))
        {
            return resource;
        }

        // Reset error
        minificationError = null;

        try
        {
            CssParser parser = new CssParser();

            parser.CssError += parser_CssError;

            // Parse the resource
            string parsed = parser.Parse(resource);
            if (!String.IsNullOrEmpty(parsed) && (minificationError == null))
            {
                resource = parsed;
            }
        }
        catch (CssException ex)
        {
            minificationError = ex;
        }

        if (minificationError != null)
        {
            if (LogMinifierParseError)
            {
                // Log exception to event log if allowed
                EventLogProvider.LogException("CSS Compression", "MINIFYCSS", minificationError);
            }

            // Add error info in front of non-minified resource
            resource += "\r\n\r\n/* Minification failed (line " + minificationError.Line.ToString() + "): " + minificationError.Message + " */";
        }

        return resource;
    }
        /// <summary>
        /// Produces code minifiction of CSS content by using
        /// Microsoft Ajax CSS Minifier
        /// </summary>
        /// <param name="content">CSS content</param>
        /// <param name="isInlineCode">Flag whether the content is inline code</param>
        /// <param name="encoding">Text encoding</param>
        /// <returns>Minification result</returns>
        public CodeMinificationResult Minify(string content, bool isInlineCode, Encoding encoding)
        {
            if (string.IsNullOrWhiteSpace(content))
            {
                return new CodeMinificationResult(string.Empty);
            }

            string newContent;
            var errorReporter = new MsAjaxCssErrorReporter();

            var cssParser = new CssParser
            {
                Settings = isInlineCode ? GetInlineCssParserSettings() : GetEmbeddedCssParserSettings()
            };
            cssParser.CssError += errorReporter.CssMinificationErrorHandler;

            try
            {
                newContent = cssParser.Parse(content);
            }
            finally
            {
                cssParser.CssError -= errorReporter.CssMinificationErrorHandler;
            }

            return new CodeMinificationResult(newContent, errorReporter.Errors, errorReporter.Warnings);
        }
示例#9
0
        /// <summary>
        /// In addition to combining, also minifies the given CSS.
        /// </summary>
        /// <returns>The combined and minified CSS code for this bundle.</returns>
        public override string Combine()
        {
            var combined = base.Combine();

            // Step 1: Bubble the @import directives to the top

            var pattern = @"@import url\(.*?\);";
            var importList = new StringBuilder();

            combined = Regex.Replace(combined, pattern, m =>
            {
                var url = m.Groups[0].Value;
                url = url.Substring(12, url.Length - 13).Replace("\"", "").Replace("'", "");

                if (url.Contains(" "))
                    importList.Append("@import url('" + url + "');\r\n");
                else
                    importList.Append("@import url(" + url + ");\r\n");

                return string.Empty;
            }, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled);

            combined = importList.ToString() + combined;

            // Step 2: The actual CSS minification

            var result = string.Empty;
            var errorLines = string.Empty;
            var hasError = false;

            try
            {
                var cssParser = new CssParser();

                cssParser.Settings.CommentMode = CssComment.None;
                cssParser.Settings.MinifyExpressions = true;
                cssParser.Settings.OutputMode = OutputMode.SingleLine;
                cssParser.Settings.TermSemicolons = false;

                cssParser.CssError += delegate(object sender, CssErrorEventArgs args)
                {
                    // The 0 severity means errors.
                    // We can safely ignore the rest.
                    if (args.Error.Severity == 0)
                    {
                        hasError = true;
                        errorLines += string.Format("\r\n/* CSS Parse error when processing the bundle.\r\nLine {0} column {1}.\r\nError message: {2}, severity: {3} */",
                            args.Error.StartLine,
                            args.Error.StartColumn,
                            args.Error.Message,
                            args.Error.Severity);
                    }
                };

                result = cssParser.Parse(combined);
            }
            catch (Exception exc)
            {
                hasError = true;
                Logger.WriteException(exc);
            }

            // If there were errors, use the non-minified version and append the errors to the bottom,
            // so that the portal builder can debug it.
            if (hasError)
                result = combined + "\r\n\r\n" + errorLines;

            return result;
        }
示例#10
0
        private int ProcessCssFile(string sourceFileName, string encodingName, ResourceStrings resourceStrings, StringBuilder outputBuilder, ref long sourceLength)
        {
            int retVal = 0;

            // blank line before
            WriteProgress();

            try
            {
                // read the input file
                var source = ReadInputFile(sourceFileName, encodingName, ref sourceLength);

                // process input source...
                CssParser parser = new CssParser();
                parser.CssError += new EventHandler<CssErrorEventArgs>(OnCssError);
                parser.FileContext = string.IsNullOrEmpty(sourceFileName) ? "stdin" : sourceFileName;

                parser.Settings.CommentMode = m_cssComments;
                parser.Settings.ExpandOutput = m_prettyPrint;
                parser.Settings.IndentSpaces = m_indentSize;
                parser.Settings.TermSemicolons = m_terminateWithSemicolon;
                parser.Settings.ColorNames = m_colorNames;
                parser.Settings.MinifyExpressions = m_minifyExpressions;
                parser.Settings.AllowEmbeddedAspNetBlocks = m_allowAspNet;
                parser.ValueReplacements = resourceStrings;

                // if the kill switch was set to 1 (don't preserve important comments), then
                // we just want to set the comment mode to none, regardless of what the actual comment
                // mode may be.
                if ((m_killSwitch & 1) != 0)
                {
                    parser.Settings.CommentMode = CssComment.None;
                }

                // crunch the source and output to the string builder we were passed
                string crunchedStyles = parser.Parse(source);
                if (crunchedStyles != null)
                {
                    Debug.WriteLine(crunchedStyles);
                }
                else
                {
                    // there was an error and no output was generated
                    retVal = 1;
                }

                if (m_echoInput)
                {
                    // just echo the input to the output
                    outputBuilder.Append(source);
                }
                else if (!string.IsNullOrEmpty(crunchedStyles))
                {
                    // send the crunched styles to the output
                    outputBuilder.Append(crunchedStyles);
                }
            }
            catch (IOException e)
            {
                // probably an error with the input file
                retVal = 1;
                System.Diagnostics.Debug.WriteLine(e.ToString());
                WriteError("AM-IO", e.Message);
            }

            return retVal;
        }
		private void InnerMinify(IAsset asset, CssParser cssParser)
		{
			string newContent;
			string assetUrl = asset.Url;

			cssParser.FileContext = assetUrl;
			cssParser.CssError += ParserErrorHandler;

			try
			{
				newContent = cssParser.Parse(asset.Content);
			}
			catch (MicrosoftAjaxParsingException e)
			{
				throw new AssetMinificationException(
					string.Format(CoreStrings.Minifiers_MinificationSyntaxError,
						CODE_TYPE, assetUrl, MINIFIER_NAME, e.Message), e);
			}
			catch (Exception e)
			{
				throw new AssetMinificationException(
					string.Format(CoreStrings.Minifiers_MinificationFailed,
						CODE_TYPE, assetUrl, MINIFIER_NAME, e.Message), e);
			}
			finally
			{
				cssParser.CssError -= ParserErrorHandler;
				cssParser.FileContext = null;
			}

			asset.Content = newContent;
			asset.Minified = true;
		}
		/// <summary>
		/// Produces a code minifiction of CSS-assets by using Microsoft Ajax Minifier
		/// </summary>
		/// <param name="assets">Set of CSS-assets</param>
		/// <returns>Set of CSS-assets with minified text content</returns>
		public override IList<IAsset> Minify(IList<IAsset> assets)
		{
			if (assets == null)
			{
				throw new ArgumentException(CoreStrings.Common_ValueIsEmpty, "assets");
			}

			if (assets.Count == 0)
			{
				return assets;
			}

			var assetsToProcessing = assets.Where(a => a.IsStylesheet && !a.Minified).ToList();
			if (assetsToProcessing.Count == 0)
			{
				return assets;
			}

			var cssParser = new CssParser
			{
			    Settings = _cssParserConfiguration
			};

			foreach (var asset in assetsToProcessing)
			{
				InnerMinify(asset, cssParser);
			}

			return assets;
		}
		/// <summary>
		/// Produces a code minifiction of CSS-asset by using Microsoft Ajax Minifier
		/// </summary>
		/// <param name="asset">CSS-asset</param>
		/// <returns>CSS-asset with minified text content</returns>
		public override IAsset Minify(IAsset asset)
		{
			if (asset == null)
			{
				throw new ArgumentException(CoreStrings.Common_ValueIsEmpty, "asset");
			}

			if (asset.Minified)
			{
				return asset;
			}

			var cssParser = new CssParser
			{
			    Settings = _cssParserConfiguration
			};

			InnerMinify(asset, cssParser);

			return asset;
		}