public string Minify(string content, MelezeWebMinifierState state)
        {
            if (state.InsidePre)
            {
                if (string.IsNullOrEmpty(content))
                {
                    return(string.Empty);
                }
            }
            else
            {
                if (string.IsNullOrWhiteSpace(content))
                {
                    return(string.Empty);
                }
            }

            var builder = new StringBuilder(content.Length);

            content = Comments
              ? MinifyComments(content, builder, state)
              : MinifyHtml(content, builder, state);

            return(content);
        }
        public MelezeWebMinifierState AnalyseContent(string content, MelezeWebMinifierState state)
        {
            if (string.IsNullOrWhiteSpace(content))
            {
                return(state);
            }

            var previousIsWhiteSpace = char.IsWhiteSpace(content[content.Length - 1]);
            var previousTokenEndsWithBlockElement = EndsWithBlockElement(content);

            var insideScript    = IsInsideTag("<script", "</script>", state.InsideScript, content);
            var insidePre       = IsInsideTag("<pre", "</pre>", state.InsidePre, content);
            var insideComment   = IsInsideTag("<!--", "-->", state.InsideComment, content);
            var preserveComment = insideComment && state.PreserveComment;

            return(new MelezeWebMinifierState(previousIsWhiteSpace, previousTokenEndsWithBlockElement,
                                              insidePre, insideScript, insideComment, preserveComment));
        }
        /// <summary>
        /// Removes all the comments that are not Javascript or IE conditional comments.
        /// </summary>
        /// <param name="content"></param>
        /// <param name="builder"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        private string MinifyComments(string content, StringBuilder builder, MelezeWebMinifierState state)
        {
            ProcessItem("<!--", "-->", content, state.InsideComment,
                        insideComment =>
            {
                // There is a comment but it contains javascript or IE conditionals => we keep it
                if (CommentsMarkers.Any(insideComment.Contains))
                {
                    state.PreserveComment = true;
                }

                if (state.PreserveComment)
                {
                    builder.Append(insideComment);
                }
            },
                        outsideComment => MinifyHtml(outsideComment, builder, state));

            return(builder.ToString());
        }
        /// <summary>
        /// Minify all the white space. Only one space is kept between attributes and words.
        /// Whitespace is completly remove arround HTML block elements while only a single
        /// one is kept arround inline elements.
        /// </summary>
        /// <param name="content"></param>
        /// <param name="builder"></param>
        /// <returns></returns>
        private static string MinifyAggressivelyHtml(string content, StringBuilder builder, MelezeWebMinifierState state)
        {
            bool previousTokenEndsWithBlockElement = state.PreviousTokenEndsWithBlockElement;
            bool previousIsWhiteSpace = state.PreviousIsWhiteSpace;

            ProcessTag("script", content, state.InsideScript,
                       jsContent =>
            {
                previousIsWhiteSpace = MinifySafelyHtmlBlock(jsContent, builder, previousIsWhiteSpace, state.InsidePre);
            },
                       htmlContent => ProcessTag("pre", htmlContent, state.InsidePre,
                                                 preContent =>
            {
                builder.Append(preContent);
            },
                                                 htmlPreContent =>
            {
                var tokens = htmlPreContent.Split(WhiteSpaceSeparators, StringSplitOptions.RemoveEmptyEntries);
                previousTokenEndsWithBlockElement |= (htmlPreContent.Length > 0) && !char.IsWhiteSpace(htmlPreContent[0]);
                previousIsWhiteSpace = false;
                for (int i = 0; i < tokens.Length; i++)
                {
                    var token = tokens[i].Trim();
                    if (string.IsNullOrEmpty(token))
                    {
                        continue;
                    }
                    if (!previousTokenEndsWithBlockElement && !StartsWithBlockElement(token))
                    {
                        // We have to keep a white space between 2 texts or an inline element and a text or between 2 inline elements
                        builder.Append(' ');
                    }

                    builder.Append(token);

                    previousTokenEndsWithBlockElement = EndsWithBlockElement(tokens, i);
                }
                if (!previousTokenEndsWithBlockElement && char.IsWhiteSpace(htmlPreContent[htmlPreContent.Length - 1]))
                {
                    builder.Append(' ');
                    previousIsWhiteSpace = true;
                }
            }));

            content = builder.ToString();
            return(content);
        }
        /// <summary>
        /// Minify white space while keeping the HTML compatible with the given one.
        /// Blanks between tags on the same line are not minified.
        /// Just the line start/end are trimmed (the indentation).
        /// </summary>
        private static string MinifySafelyHtml(string content, StringBuilder builder, MelezeWebMinifierState state)
        {
            MinifySafelyHtmlBlock(content, builder, state.PreviousIsWhiteSpace, state.InsidePre);

            content = builder.ToString();
            return(content);
        }
 private string MinifyHtml(string content, StringBuilder builder, MelezeWebMinifierState state)
 {
     return(Aggressive
       ? MinifyAggressivelyHtml(content, builder, state)
       : MinifySafelyHtml(content, builder, state));
 }