Example #1
0
        /// <summary>
        /// Calculates a absolute node coordinates
        /// </summary>
        /// <param name="baseNodeCoordinates">Base node coordinates</param>
        /// <param name="lineBreakCount">Number of line breaks</param>
        /// <param name="charRemainderCount">Number of characters left</param>
        /// <returns>Absolute node coordinates</returns>
        public static SourceCodeNodeCoordinates CalculateAbsoluteNodeCoordinates(
            SourceCodeNodeCoordinates baseNodeCoordinates, int lineBreakCount, int charRemainderCount)
        {
            int absoluteLineNumber;
            int absoluteColumnNumber;

            if (!baseNodeCoordinates.IsEmpty)
            {
                int baseLineNumber   = baseNodeCoordinates.LineNumber;
                int baseColumnNumber = baseNodeCoordinates.ColumnNumber;

                if (lineBreakCount > 0)
                {
                    absoluteLineNumber   = baseLineNumber + lineBreakCount;
                    absoluteColumnNumber = charRemainderCount + 1;
                }
                else
                {
                    absoluteLineNumber   = baseLineNumber;
                    absoluteColumnNumber = baseColumnNumber + charRemainderCount;
                }
            }
            else
            {
                absoluteLineNumber   = lineBreakCount + 1;
                absoluteColumnNumber = charRemainderCount + 1;
            }

            var absoluteNodeCoordinates = new SourceCodeNodeCoordinates(absoluteLineNumber, absoluteColumnNumber);

            return(absoluteNodeCoordinates);
        }
Example #2
0
        /// <summary>
        /// Gets a source fragment
        /// </summary>
        /// <param name="sourceCode">Source code</param>
        /// <param name="nodePosition">Current node position</param>
        /// <param name="tabSize">Number of spaces in the tab</param>
        /// <param name="maxFragmentLength">Maximum length of the source fragment</param>
        /// <returns>Source fragment</returns>
        public static string GetSourceFragment(string sourceCode, int nodePosition,
                                               byte tabSize = DEFAULT_TAB_SIZE, int maxFragmentLength = DEFAULT_MAX_FRAGMENT_LENGTH)
        {
            SourceCodeNodeCoordinates nodeCoordinates = CalculateNodeCoordinates(sourceCode, nodePosition);

            return(GetSourceFragment(sourceCode, nodeCoordinates, tabSize));
        }
        /// <summary>
        /// Constructs instance of HTML attribute
        /// </summary>
        /// <param name="name">Name</param>
        /// <param name="value">Value</param>
        /// <param name="type">Type</param>
        /// <param name="nameCoordinates">Coordinates of name</param>
        /// <param name="valueCoordinates">Coordinates of value</param>
        public HtmlAttribute(string name, string value, HtmlAttributeType type,
			SourceCodeNodeCoordinates nameCoordinates, SourceCodeNodeCoordinates valueCoordinates)
        {
            Name = name;
            Value = value;
            Type = type;
            NameCoordinates = nameCoordinates;
            ValueCoordinates = valueCoordinates;
        }
Example #4
0
        /// <summary>
        /// Calculates a node coordinates
        /// </summary>
        /// <param name="sourceCode">Source code</param>
        /// <param name="nodePosition">Current node position</param>
        /// <returns>Node coordinates</returns>
        public static SourceCodeNodeCoordinates CalculateNodeCoordinates(string sourceCode, int nodePosition)
        {
            if (string.IsNullOrEmpty(sourceCode) || nodePosition >= sourceCode.Length)
            {
                return(SourceCodeNodeCoordinates.Empty);
            }

            int fragmentLength = nodePosition + 1;
            int lineBreakCount;
            int charRemainderCount;

            CalculateLineBreakCount(sourceCode, 0, fragmentLength,
                                    out lineBreakCount, out charRemainderCount);

            var nodeCoordinates = new SourceCodeNodeCoordinates(lineBreakCount + 1, charRemainderCount + 1);

            return(nodeCoordinates);
        }
        /// <summary>
        /// Calculates a absolute node coordinates
        /// </summary>
        /// <param name="baseNodeCoordinates">Base node coordinates</param>
        /// <param name="relativeNodeCoordinates">Relative node coordinates</param>
        /// <returns>Absolute node coordinates</returns>
        public static SourceCodeNodeCoordinates CalculateAbsoluteNodeCoordinates(
			SourceCodeNodeCoordinates baseNodeCoordinates, SourceCodeNodeCoordinates relativeNodeCoordinates)
        {
            int relativeLineNumber = relativeNodeCoordinates.LineNumber;
            int relativeColumnNumber = relativeNodeCoordinates.ColumnNumber;

            int absoluteLineNumber;
            int absoluteColumnNumber;

            if (!baseNodeCoordinates.IsEmpty)
            {
                int baseLineNumber = baseNodeCoordinates.LineNumber;
                int baseColumnNumber = baseNodeCoordinates.ColumnNumber;

                absoluteLineNumber = baseLineNumber;
                absoluteColumnNumber = baseColumnNumber;

                if (relativeLineNumber > 0)
                {
                    if (relativeLineNumber == 1)
                    {
                        if (relativeColumnNumber > 0)
                        {
                            absoluteColumnNumber = baseColumnNumber + relativeColumnNumber - 1;
                        }
                    }
                    else
                    {
                        absoluteLineNumber = baseLineNumber + relativeLineNumber - 1;
                        absoluteColumnNumber = relativeColumnNumber;
                    }
                }
            }
            else
            {
                absoluteLineNumber = relativeLineNumber;
                absoluteColumnNumber = relativeColumnNumber;
            }

            var absoluteNodeCoordinates = new SourceCodeNodeCoordinates(absoluteLineNumber, absoluteColumnNumber);

            return absoluteNodeCoordinates;
        }
Example #6
0
        /// <summary>
        /// Calculates a absolute node coordinates
        /// </summary>
        /// <param name="baseNodeCoordinates">Base node coordinates</param>
        /// <param name="relativeNodeCoordinates">Relative node coordinates</param>
        /// <returns>Absolute node coordinates</returns>
        public static SourceCodeNodeCoordinates CalculateAbsoluteNodeCoordinates(
            SourceCodeNodeCoordinates baseNodeCoordinates, SourceCodeNodeCoordinates relativeNodeCoordinates)
        {
            int relativeLineNumber   = relativeNodeCoordinates.LineNumber;
            int relativeColumnNumber = relativeNodeCoordinates.ColumnNumber;

            int absoluteLineNumber;
            int absoluteColumnNumber;

            if (!baseNodeCoordinates.IsEmpty)
            {
                int baseLineNumber   = baseNodeCoordinates.LineNumber;
                int baseColumnNumber = baseNodeCoordinates.ColumnNumber;

                absoluteLineNumber   = baseLineNumber;
                absoluteColumnNumber = baseColumnNumber;

                if (relativeLineNumber > 0)
                {
                    if (relativeLineNumber == 1)
                    {
                        if (relativeColumnNumber > 0)
                        {
                            absoluteColumnNumber = baseColumnNumber + relativeColumnNumber - 1;
                        }
                    }
                    else
                    {
                        absoluteLineNumber   = baseLineNumber + relativeLineNumber - 1;
                        absoluteColumnNumber = relativeColumnNumber;
                    }
                }
            }
            else
            {
                absoluteLineNumber   = relativeLineNumber;
                absoluteColumnNumber = relativeColumnNumber;
            }

            var absoluteNodeCoordinates = new SourceCodeNodeCoordinates(absoluteLineNumber, absoluteColumnNumber);

            return(absoluteNodeCoordinates);
        }
Example #7
0
        /// <summary>
        /// Calculates a absolute node coordinates
        /// </summary>
        /// <param name="baseNodeCoordinates">Base node coordinates</param>
        /// <param name="additionalContent">Additional content</param>
        /// <returns>Absolute node coordinates</returns>
        public static SourceCodeNodeCoordinates CalculateAbsoluteNodeCoordinates(
            SourceCodeNodeCoordinates baseNodeCoordinates, string additionalContent)
        {
            int lineBreakCount     = 0;
            int charRemainderCount = 0;

            if (!string.IsNullOrEmpty(additionalContent))
            {
                CalculateLineBreakCount(additionalContent, out lineBreakCount, out charRemainderCount);
            }

            int absoluteLineNumber;
            int absoluteColumnNumber;

            if (!baseNodeCoordinates.IsEmpty)
            {
                int baseLineNumber   = baseNodeCoordinates.LineNumber;
                int baseColumnNumber = baseNodeCoordinates.ColumnNumber;

                if (lineBreakCount > 0)
                {
                    absoluteLineNumber   = baseLineNumber + lineBreakCount;
                    absoluteColumnNumber = charRemainderCount + 1;
                }
                else
                {
                    absoluteLineNumber   = baseLineNumber;
                    absoluteColumnNumber = baseColumnNumber + charRemainderCount;
                }
            }
            else
            {
                absoluteLineNumber   = lineBreakCount + 1;
                absoluteColumnNumber = charRemainderCount + 1;
            }

            var absoluteNodeCoordinates = new SourceCodeNodeCoordinates(absoluteLineNumber, absoluteColumnNumber);

            return(absoluteNodeCoordinates);
        }
        /// <summary>
        /// Calculates a absolute node coordinates
        /// </summary>
        /// <param name="baseNodeCoordinates">Base node coordinates</param>
        /// <param name="additionalContent">Additional content</param>
        /// <returns>Absolute node coordinates</returns>
        public static SourceCodeNodeCoordinates CalculateAbsoluteNodeCoordinates(
			SourceCodeNodeCoordinates baseNodeCoordinates, string additionalContent)
        {
            int lineBreakCount = 0;
            int charRemainderCount = 0;

            if (!string.IsNullOrEmpty(additionalContent))
            {
                CalculateLineBreakCount(additionalContent, out lineBreakCount, out charRemainderCount);
            }

            int absoluteLineNumber;
            int absoluteColumnNumber;

            if (!baseNodeCoordinates.IsEmpty)
            {
                int baseLineNumber = baseNodeCoordinates.LineNumber;
                int baseColumnNumber = baseNodeCoordinates.ColumnNumber;

                if (lineBreakCount > 0)
                {
                    absoluteLineNumber = baseLineNumber + lineBreakCount;
                    absoluteColumnNumber = charRemainderCount + 1;
                }
                else
                {
                    absoluteLineNumber = baseLineNumber;
                    absoluteColumnNumber = baseColumnNumber + charRemainderCount;
                }
            }
            else
            {
                absoluteLineNumber = lineBreakCount + 1;
                absoluteColumnNumber = charRemainderCount + 1;
            }

            var absoluteNodeCoordinates = new SourceCodeNodeCoordinates(absoluteLineNumber, absoluteColumnNumber);

            return absoluteNodeCoordinates;
        }
        /// <summary>
        /// Initializes a new instance of the WebMarkupMin.Core.CodeProcessingException class
        /// with a specified error message, node coordinates, source fragment
        /// and reference to the inner exception that is the cause of this exception
        /// </summary>
        /// <param name="message">Error message that explains the reason for the exception</param>
        /// <param name="nodeCoordinates">Node coordinates</param>
        /// <param name="sourceFragment">Source fragment</param>
        /// <param name="innerException">Exception that is the cause of the current exception</param>
        protected CodeProcessingException(string message, SourceCodeNodeCoordinates nodeCoordinates,
			string sourceFragment, Exception innerException)
            : this(message, nodeCoordinates.LineNumber, nodeCoordinates.ColumnNumber,
				sourceFragment, innerException)
        {
        }
        /// <summary>
        /// Minify a Knockout binding expression
        /// </summary>
        /// <param name="context">Markup parsing context</param>
        /// <param name="expressionCoordinates">Coordinates of expression</param>
        /// <param name="expression">Binding expression</param>
        /// <returns>Minified binding expression</returns>
        private string MinifyKnockoutBindingExpression(MarkupParsingContext context,
			SourceCodeNodeCoordinates expressionCoordinates, string expression)
        {
            return MinifyKnockoutBindingExpression(context, SourceCodeNodeCoordinates.Empty, expressionCoordinates,
                expression);
        }
        /// <summary>
        /// Gets a source fragment
        /// </summary>
        /// <param name="sourceCode">Source code</param>
        /// <param name="nodeCoordinates">Node coordinates</param>
        /// <param name="tabSize">Number of spaces in the tab</param>
        /// <param name="maxFragmentLength">Maximum length of the source fragment</param>
        /// <returns>Source fragment</returns>
        public static string GetSourceFragment(string sourceCode,
			SourceCodeNodeCoordinates nodeCoordinates, byte tabSize = DEFAULT_TAB_SIZE,
			int maxFragmentLength = DEFAULT_MAX_FRAGMENT_LENGTH)
        {
            string sourceFragment = string.Empty;
            int lineNumber = nodeCoordinates.LineNumber;
            int columnNumber = nodeCoordinates.ColumnNumber;

            if (!string.IsNullOrEmpty(sourceCode))
            {
                int previousLineNumber = lineNumber - 1;
                int currentLineNumber = lineNumber;
                int nextLineNumber = lineNumber + 1;

                string previousLine = string.Empty;
                string currentLine = string.Empty;
                string nextLine = string.Empty;

                int lineCount = 0;
                int lineBreakPosition = int.MinValue;
                int lineBreakLength = 0;

                do
                {
                    string line;
                    int startLinePosition = (lineBreakPosition == int.MinValue) ? 0 : lineBreakPosition + lineBreakLength;

                    FindNextLineBreak(sourceCode, startLinePosition, out lineBreakPosition, out lineBreakLength);

                    if (lineBreakPosition != -1)
                    {
                        line = sourceCode.Substring(startLinePosition, lineBreakPosition - startLinePosition);
                    }
                    else
                    {
                        line = sourceCode.Substring(startLinePosition);
                    }

                    lineCount++;

                    if (lineCount == previousLineNumber)
                    {
                        previousLine = line;
                    }
                    else if (lineCount == currentLineNumber)
                    {
                        currentLine = line;
                    }
                    else if (lineCount == nextLineNumber)
                    {
                        nextLine = line;
                    }
                }
                while (lineBreakPosition != -1 && lineCount <= nextLineNumber);

                int lineNumberSize = (nextLineNumber).ToString(CultureInfo.InvariantCulture).Length;
                if (currentLineNumber == lineCount)
                {
                    lineNumberSize = currentLineNumber.ToString(CultureInfo.InvariantCulture).Length;
                }

                int fragmentStartPosition;
                int fragmentLength;

                CalculateCutPositions(currentLine, columnNumber, maxFragmentLength,
                    out fragmentStartPosition, out fragmentLength);

                StringBuilder sourceFragmentBuilder = StringBuilderPool.GetBuilder();

                if (currentLine.Length > 0)
                {
                    if (previousLine.Length > 0)
                    {
                        sourceFragmentBuilder.AppendLine(FormatSourceCodeLine(previousLine,
                            new SourceCodeNodeCoordinates(previousLineNumber, 0),
                            lineNumberSize, fragmentStartPosition, fragmentLength, tabSize));
                    }

                    sourceFragmentBuilder.AppendLine(FormatSourceCodeLine(currentLine,
                        new SourceCodeNodeCoordinates(currentLineNumber, columnNumber),
                        lineNumberSize, fragmentStartPosition, fragmentLength, tabSize));

                    if (nextLine.Length > 0)
                    {
                        sourceFragmentBuilder.AppendLine(FormatSourceCodeLine(nextLine,
                            new SourceCodeNodeCoordinates(nextLineNumber, 0),
                            lineNumberSize, fragmentStartPosition, fragmentLength, tabSize));
                    }
                }

                sourceFragment = sourceFragmentBuilder.ToString();
                StringBuilderPool.ReleaseBuilder(sourceFragmentBuilder);
            }

            return sourceFragment;
        }
        /// <summary>
        /// Calculates a node coordinates
        /// </summary>
        /// <param name="sourceCode">Source code</param>
        /// <param name="nodePosition">Current node position</param>
        /// <returns>Node coordinates</returns>
        public static SourceCodeNodeCoordinates CalculateNodeCoordinates(string sourceCode, int nodePosition)
        {
            if (string.IsNullOrEmpty(sourceCode) || nodePosition >= sourceCode.Length)
            {
                return SourceCodeNodeCoordinates.Empty;
            }

            int fragmentLength = nodePosition + 1;
            int lineBreakCount;
            int charRemainderCount;

            CalculateLineBreakCount(sourceCode, 0, fragmentLength,
                out lineBreakCount, out charRemainderCount);

            var nodeCoordinates = new SourceCodeNodeCoordinates(lineBreakCount + 1, charRemainderCount + 1);

            return nodeCoordinates;
        }
        /// <summary>
        /// XML declaration handler
        /// </summary>
        /// <param name="context">Markup parsing context</param>
        /// <param name="xmlDeclaration">XML declaration</param>
        private void XmlDeclarationHandler(MarkupParsingContext context, string xmlDeclaration)
        {
            _currentNodeType = HtmlNodeType.XmlDeclaration;

            WhitespaceMinificationMode whitespaceMinificationMode = _settings.WhitespaceMinificationMode;
            if (whitespaceMinificationMode != WhitespaceMinificationMode.None)
            {
                // Processing of whitespace, that followed before the document type declaration
                TrimEndLastBufferItem();
            }

            if (_settings.UseXhtmlSyntax)
            {
                XmlMinifier innerXmlMinifier = GetInnerXmlMinifierInstance();
                MarkupMinificationResult minificationResult = innerXmlMinifier.Minify(xmlDeclaration);

                if (minificationResult.Errors.Count == 0)
                {
                    _buffer.Add(minificationResult.MinifiedContent);
                }
                else
                {
                    string sourceCode = context.SourceCode;
                    var documentCoordinates = context.NodeCoordinates;

                    foreach (MinificationErrorInfo error in minificationResult.Errors)
                    {
                        var xmlNodeCoordinates = new SourceCodeNodeCoordinates(error.LineNumber, error.ColumnNumber);
                        var absoluteNodeCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(
                            documentCoordinates, xmlNodeCoordinates);

                        string sourceFragment = SourceCodeNavigator.GetSourceFragment(
                            sourceCode, absoluteNodeCoordinates);
                        string message = Strings.ErrorMessage_XmlDeclarationMinificationFailed;

                        WriteError(LogCategoryConstants.HtmlMinificationError, message, _fileContext,
                            absoluteNodeCoordinates.LineNumber, absoluteNodeCoordinates.ColumnNumber, sourceFragment);
                    }
                }
            }
            else
            {
                string sourceCode = context.SourceCode;
                SourceCodeNodeCoordinates xmlDeclarationCoordinates = context.NodeCoordinates;

                WriteWarning(LogCategoryConstants.HtmlMinificationWarning,
                    Strings.WarningMessage_XmlDeclarationNotAllowed, _fileContext,
                    xmlDeclarationCoordinates.LineNumber, xmlDeclarationCoordinates.ColumnNumber,
                    SourceCodeNavigator.GetSourceFragment(sourceCode, xmlDeclarationCoordinates));
            }
        }
        /// <summary>
        /// Processes a inline style content
        /// </summary>
        /// <param name="context">Markup parsing context</param>
        /// <param name="attribute">Attribute</param>
        /// <returns>Processed inline style content</returns>
        private string ProcessInlineStyleContent(MarkupParsingContext context, HtmlAttribute attribute)
        {
            string styleContent = attribute.Value;

            string result = styleContent;
            if (_settings.MinifyInlineCssCode && _cssMinifier.IsInlineCodeMinificationSupported)
            {
                CodeMinificationResult minificationResult = _cssMinifier.Minify(result, true);
                if (minificationResult.Errors.Count == 0)
                {
                    result = minificationResult.MinifiedContent ?? string.Empty;
                }

                if (minificationResult.Errors.Count > 0 || minificationResult.Warnings.Count > 0)
                {
                    string sourceCode = context.SourceCode;
                    SourceCodeNodeCoordinates tagCoordinates = context.NodeCoordinates;
                    SourceCodeNodeCoordinates attributeCoordinates = attribute.ValueCoordinates;

                    foreach (MinificationErrorInfo error in minificationResult.Errors)
                    {
                        var relativeErrorCoordinates = new SourceCodeNodeCoordinates(error.LineNumber, error.ColumnNumber);
                        SourceCodeNodeCoordinates absoluteErrorCoordinates = CalculateAbsoluteInlineCodeErrorCoordinates(
                            tagCoordinates, attributeCoordinates, relativeErrorCoordinates);
                        string sourceFragment = SourceCodeNavigator.GetSourceFragment(
                            sourceCode, absoluteErrorCoordinates);
                        string message = error.Message.Trim();

                        WriteError(LogCategoryConstants.CssMinificationError, message, _fileContext,
                            absoluteErrorCoordinates.LineNumber, absoluteErrorCoordinates.ColumnNumber, sourceFragment);
                    }

                    foreach (MinificationErrorInfo warning in minificationResult.Warnings)
                    {
                        var relativeErrorCoordinates = new SourceCodeNodeCoordinates(warning.LineNumber, warning.ColumnNumber);
                        SourceCodeNodeCoordinates absoluteErrorCoordinates = CalculateAbsoluteInlineCodeErrorCoordinates(
                            tagCoordinates, attributeCoordinates, relativeErrorCoordinates);
                        string sourceFragment = SourceCodeNavigator.GetSourceFragment(
                            sourceCode, absoluteErrorCoordinates);
                        string message = warning.Message.Trim();

                        WriteWarning(LogCategoryConstants.CssMinificationWarning, message, _fileContext,
                            absoluteErrorCoordinates.LineNumber, absoluteErrorCoordinates.ColumnNumber, sourceFragment);
                    }
                }
            }
            else
            {
                result = result.Trim();
            }

            result = Utils.RemoveEndingSemicolon(result);

            return result;
        }
        /// <summary>
        /// Processes a inline script content
        /// </summary>
        /// <param name="context">Markup parsing context</param>
        /// <param name="attribute">Attribute</param>
        /// <returns>Processed inline script content</returns>
        private string ProcessInlineScriptContent(MarkupParsingContext context, HtmlAttribute attribute)
        {
            string scriptContent = attribute.Value;
            bool forHrefAttribute = (attribute.Name == "href");

            string result = scriptContent;

            if (_settings.MinifyInlineJsCode && _jsMinifier.IsInlineCodeMinificationSupported)
            {
                bool isJavascriptProtocolRemoved = false;
                if (scriptContent.StartsWith(JS_PROTOCOL, StringComparison.OrdinalIgnoreCase))
                {
                    result = _jsProtocolRegex.Replace(result, string.Empty);
                    isJavascriptProtocolRemoved = true;
                }

                CodeMinificationResult minificationResult = _jsMinifier.Minify(result, true);
                if (minificationResult.Errors.Count == 0)
                {
                    result = minificationResult.MinifiedContent ?? string.Empty;
                }

                if (minificationResult.Errors.Count > 0 || minificationResult.Warnings.Count > 0)
                {
                    string sourceCode = context.SourceCode;
                    SourceCodeNodeCoordinates tagCoordinates = context.NodeCoordinates;
                    SourceCodeNodeCoordinates attributeCoordinates = attribute.ValueCoordinates;

                    foreach (MinificationErrorInfo error in minificationResult.Errors)
                    {
                        var relativeErrorCoordinates = new SourceCodeNodeCoordinates(error.LineNumber, error.ColumnNumber);
                        SourceCodeNodeCoordinates absoluteErrorCoordinates = CalculateAbsoluteInlineCodeErrorCoordinates(
                            tagCoordinates, attributeCoordinates, relativeErrorCoordinates);
                        string sourceFragment = SourceCodeNavigator.GetSourceFragment(
                            sourceCode, absoluteErrorCoordinates);
                        string message = error.Message.Trim();

                        WriteError(LogCategoryConstants.JsMinificationError, message, _fileContext,
                            absoluteErrorCoordinates.LineNumber, absoluteErrorCoordinates.ColumnNumber, sourceFragment);
                    }

                    foreach (MinificationErrorInfo warning in minificationResult.Warnings)
                    {
                        var relativeErrorCoordinates = new SourceCodeNodeCoordinates(warning.LineNumber, warning.ColumnNumber);
                        SourceCodeNodeCoordinates absoluteErrorCoordinates = CalculateAbsoluteInlineCodeErrorCoordinates(
                            tagCoordinates, attributeCoordinates, relativeErrorCoordinates);
                        string sourceFragment = SourceCodeNavigator.GetSourceFragment(
                            sourceCode, absoluteErrorCoordinates);
                        string message = warning.Message.Trim();

                        WriteWarning(LogCategoryConstants.JsMinificationWarning, message, _fileContext,
                            absoluteErrorCoordinates.LineNumber, absoluteErrorCoordinates.ColumnNumber, sourceFragment);
                    }
                }

                if (isJavascriptProtocolRemoved
                    && (forHrefAttribute || !_settings.RemoveJsProtocolFromAttributes))
                {
                    result = JS_PROTOCOL + result;
                }
            }
            else
            {
                result = result.Trim();

                if (!forHrefAttribute && _settings.RemoveJsProtocolFromAttributes)
                {
                    result = _jsProtocolRegex.Replace(result, string.Empty);
                }
            }

            result = Utils.RemoveEndingSemicolon(result);

            return result;
        }
        /// <summary>
        /// Processes a embedded SVG content
        /// </summary>
        /// <param name="context">Markup parsing context</param>
        /// <param name="svgContent">Embedded SVG content</param>
        /// <returns>Processed embedded SVG content</returns>
        private string ProcessEmbeddedSvgContent(MarkupParsingContext context, string svgContent)
        {
            string result = string.Empty;

            XmlMinifier innerXmlMinifier = GetInnerXmlMinifierInstance();
            MarkupMinificationResult minificationResult = innerXmlMinifier.Minify(svgContent);

            if (minificationResult.Errors.Count == 0)
            {
                result = minificationResult.MinifiedContent ?? string.Empty;
            }
            else
            {
                string sourceCode = context.SourceCode;
                var documentCoordinates = context.NodeCoordinates;

                foreach (MinificationErrorInfo error in minificationResult.Errors)
                {
                    var xmlNodeCoordinates = new SourceCodeNodeCoordinates(error.LineNumber, error.ColumnNumber);
                    var absoluteNodeCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(
                        documentCoordinates, xmlNodeCoordinates);

                    string sourceFragment = SourceCodeNavigator.GetSourceFragment(
                        sourceCode, absoluteNodeCoordinates);
                    string message = string.Format(Strings.ErrorMessage_MarkupMinificationFailed,
                        "SVG", error.Message);

                    WriteError(LogCategoryConstants.HtmlMinificationError, message, _fileContext,
                        absoluteNodeCoordinates.LineNumber, absoluteNodeCoordinates.ColumnNumber, sourceFragment);
                }
            }

            return result;
        }
        /// <summary>
        /// Processes a embedded style content
        /// </summary>
        /// <param name="context">Markup parsing context</param>
        /// <param name="content">Embedded style content</param>
        /// <param name="contentType">Content type (MIME type) of the style</param>
        /// <returns>Processed embedded style content</returns>
        private string ProcessEmbeddedStyleContent(MarkupParsingContext context, string content, string contentType)
        {
            string processedContentType = (!string.IsNullOrWhiteSpace(contentType)) ?
                contentType.Trim().ToLowerInvariant() : CSS_CONTENT_TYPE;
            bool minifyWhitespace = (_settings.WhitespaceMinificationMode != WhitespaceMinificationMode.None);
            bool removeHtmlComments = _settings.RemoveHtmlCommentsFromScriptsAndStyles;
            bool removeCdataSections = _settings.RemoveCdataSectionsFromScriptsAndStyles;

            string startPart = string.Empty;
            string endPart = string.Empty;
            string code;
            string beforeCodeContent = string.Empty;

            if (_styleBeginCdataSectionRegex.IsMatch(content))
            {
                beforeCodeContent = _styleBeginCdataSectionRegex.Match(content).Value;

                if (!removeCdataSections)
                {
                    startPart = "/*<![CDATA[*/";
                    endPart = "/*]]>*/";
                }

                code = _styleBeginCdataSectionRegex.Replace(content, string.Empty);
                code = _styleEndCdataSectionRegex.Replace(code, string.Empty);
            }
            else if (_styleBeginMaxCompatibleCdataSectionRegex.IsMatch(content))
            {
                beforeCodeContent = _styleBeginMaxCompatibleCdataSectionRegex.Match(content).Value;

                if (!removeCdataSections)
                {
                    startPart = "<!--/*--><![CDATA[/*><!--*/";
                    endPart = "/*]]>*/-->";
                }

                code = _styleBeginMaxCompatibleCdataSectionRegex.Replace(content, string.Empty);
                code = _styleEndMaxCompatibleCdataSectionRegex.Replace(code, string.Empty);
            }
            else if (_styleBeginHtmlCommentRegex.IsMatch(content))
            {
                beforeCodeContent = _styleBeginHtmlCommentRegex.Match(content).Value;

                if (!removeHtmlComments)
                {
                    startPart = "<!--";
                    endPart = "-->";
                }

                code = _styleBeginHtmlCommentRegex.Replace(content, string.Empty);
                code = _styleEndHtmlCommentRegex.Replace(code, string.Empty);
            }
            else
            {
                code = content;
            }

            if (processedContentType == CSS_CONTENT_TYPE && _settings.MinifyEmbeddedCssCode)
            {
                CodeMinificationResult minificationResult = _cssMinifier.Minify(code, false);
                if (minificationResult.Errors.Count == 0)
                {
                    code = minificationResult.MinifiedContent ?? string.Empty;
                }

                if (minificationResult.Errors.Count > 0 || minificationResult.Warnings.Count > 0)
                {
                    string sourceCode = context.SourceCode;
                    var documentNodeCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(
                        context.NodeCoordinates, beforeCodeContent);

                    foreach (MinificationErrorInfo error in minificationResult.Errors)
                    {
                        var embeddedContentNodeCoordinates = new SourceCodeNodeCoordinates(error.LineNumber, error.ColumnNumber);
                        var absoluteNodeCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(
                            documentNodeCoordinates, embeddedContentNodeCoordinates);
                        string sourceFragment = SourceCodeNavigator.GetSourceFragment(
                            sourceCode, absoluteNodeCoordinates);
                        string message = error.Message.Trim();

                        WriteError(LogCategoryConstants.CssMinificationError, message, _fileContext,
                            absoluteNodeCoordinates.LineNumber, absoluteNodeCoordinates.ColumnNumber, sourceFragment);
                    }

                    foreach (MinificationErrorInfo warning in minificationResult.Warnings)
                    {
                        var embeddedContentNodeCoordinates = new SourceCodeNodeCoordinates(warning.LineNumber, warning.ColumnNumber);
                        var absoluteNodeCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(
                            documentNodeCoordinates, embeddedContentNodeCoordinates);
                        string sourceFragment = SourceCodeNavigator.GetSourceFragment(
                            sourceCode, absoluteNodeCoordinates);
                        string message = warning.Message.Trim();

                        WriteWarning(LogCategoryConstants.CssMinificationWarning, message, _fileContext,
                            absoluteNodeCoordinates.LineNumber, absoluteNodeCoordinates.ColumnNumber, sourceFragment);
                    }
                }
            }

            if (minifyWhitespace && code.Length > 0)
            {
                code = code.Trim();
            }

            string processedStyleContent;
            if (startPart.Length > 0 || endPart.Length > 0)
            {
                processedStyleContent = string.Concat(startPart, code, endPart);
            }
            else
            {
                processedStyleContent = code;
            }

            return processedStyleContent;
        }
        /// <summary>
        /// Processes a embedded script content
        /// </summary>
        /// <param name="context">Markup parsing context</param>
        /// <param name="content">Embedded script content</param>
        /// <param name="contentType">Content type (MIME type) of the script</param>
        /// <returns>Processed embedded script content</returns>
        private string ProcessEmbeddedScriptContent(MarkupParsingContext context, string content, string contentType)
        {
            string processedScriptContent = content;
            string processedContentType = (!string.IsNullOrWhiteSpace(contentType)) ?
                contentType.Trim().ToLowerInvariant() : JS_CONTENT_TYPE;
            bool isJavaScript = _jsContentTypes.Contains(processedContentType);
            bool isVbScript = (processedContentType == VBS_CONTENT_TYPE);

            bool minifyWhitespace = (_settings.WhitespaceMinificationMode != WhitespaceMinificationMode.None);

            if (isJavaScript || isVbScript)
            {
                bool removeHtmlComments = _settings.RemoveHtmlCommentsFromScriptsAndStyles;
                bool removeCdataSections = _settings.RemoveCdataSectionsFromScriptsAndStyles;

                string startPart = string.Empty;
                string endPart = string.Empty;
                string newLine = Environment.NewLine;
                string code = content;
                string beforeCodeContent = string.Empty;

                if (isJavaScript)
                {
                    // Processing of JavaScript code
                    if (_scriptBeginCdataSectionRegex.IsMatch(content))
                    {
                        beforeCodeContent = _scriptBeginCdataSectionRegex.Match(content).Value;

                        if (!removeCdataSections)
                        {
                            startPart = "//<![CDATA[";
                            endPart = "//]]>";
                        }

                        code = _scriptBeginCdataSectionRegex.Replace(content, string.Empty);
                        code = _scriptEndCdataSectionRegex.Replace(code, string.Empty);
                    }
                    else if (_scriptBeginMaxCompatibleCdataSectionRegex.IsMatch(content))
                    {
                        beforeCodeContent = _scriptBeginMaxCompatibleCdataSectionRegex.Match(content).Value;

                        if (!removeCdataSections)
                        {
                            startPart = "<!--//--><![CDATA[//><!--";
                            endPart = "//--><!]]>";
                        }

                        code = _scriptBeginMaxCompatibleCdataSectionRegex.Replace(content, string.Empty);
                        code = _scriptEndMaxCompatibleCdataSectionRegex.Replace(code, string.Empty);
                    }
                    else if (_scriptBeginHtmlCommentRegex.IsMatch(content))
                    {
                        beforeCodeContent = _scriptBeginHtmlCommentRegex.Match(content).Value;

                        if (!removeHtmlComments)
                        {
                            startPart = "<!--";
                            endPart = "//-->";
                        }

                        code = _scriptBeginHtmlCommentRegex.Replace(content, string.Empty);
                        code = _scriptEndHtmlCommentRegex.Replace(code, string.Empty);
                    }

                    if (_settings.MinifyEmbeddedJsCode)
                    {
                        CodeMinificationResult minificationResult = _jsMinifier.Minify(code, false);
                        if (minificationResult.Errors.Count == 0)
                        {
                            code = minificationResult.MinifiedContent ?? string.Empty;
                        }

                        if (minificationResult.Errors.Count > 0 || minificationResult.Warnings.Count > 0)
                        {
                            string sourceCode = context.SourceCode;
                            var documentCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(
                                context.NodeCoordinates, beforeCodeContent);

                            foreach (MinificationErrorInfo error in minificationResult.Errors)
                            {
                                var relativeErrorCoordinates = new SourceCodeNodeCoordinates(error.LineNumber, error.ColumnNumber);
                                var absoluteErrorCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(
                                    documentCoordinates, relativeErrorCoordinates);
                                string sourceFragment = SourceCodeNavigator.GetSourceFragment(
                                    sourceCode, absoluteErrorCoordinates);
                                string message = error.Message.Trim();

                                WriteError(LogCategoryConstants.JsMinificationError, message, _fileContext,
                                    absoluteErrorCoordinates.LineNumber, absoluteErrorCoordinates.ColumnNumber, sourceFragment);
                            }

                            foreach (MinificationErrorInfo warning in minificationResult.Warnings)
                            {
                                var relativeErrorCoordinates = new SourceCodeNodeCoordinates(warning.LineNumber, warning.ColumnNumber);
                                var absoluteErrorCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(
                                    documentCoordinates, relativeErrorCoordinates);
                                string sourceFragment = SourceCodeNavigator.GetSourceFragment(
                                    sourceCode, absoluteErrorCoordinates);
                                string message = warning.Message.Trim();

                                WriteWarning(LogCategoryConstants.JsMinificationWarning, message, _fileContext,
                                    absoluteErrorCoordinates.LineNumber, absoluteErrorCoordinates.ColumnNumber, sourceFragment);
                            }
                        }
                    }
                }
                else
                {
                    // Processing of VBScript code
                    if (_scriptBeginCdataSectionRegex.IsMatch(content))
                    {
                        if (!removeCdataSections)
                        {
                            startPart = "<![CDATA[";
                            endPart = "]]>";
                        }

                        code = _scriptBeginCdataSectionRegex.Replace(content, string.Empty);
                        code = _scriptEndCdataSectionRegex.Replace(code, string.Empty);
                    }
                    else if (_scriptBeginHtmlCommentRegex.IsMatch(content))
                    {
                        if (!removeHtmlComments)
                        {
                            startPart = "<!--";
                            endPart = "-->";
                        }

                        code = _scriptBeginHtmlCommentRegex.Replace(content, string.Empty);
                        code = _scriptEndHtmlCommentRegex.Replace(code, string.Empty);
                    }
                }

                if (minifyWhitespace && code.Length > 0)
                {
                    code = code.Trim();
                }

                if (startPart.Length > 0 || endPart.Length > 0)
                {
                    processedScriptContent = string.Concat(startPart, newLine, code, newLine, endPart);
                }
                else
                {
                    processedScriptContent = code;
                }
            }
            else if (_processableScriptTypes.Contains(processedContentType))
            {
                // Processing of JavaScript template
                GenericHtmlMinifier innerHtmlMinifier = GetInnerHtmlMinifierInstance();
                MarkupMinificationResult minificationResult = innerHtmlMinifier.Minify(processedScriptContent, false);

                if (minificationResult.Errors.Count == 0)
                {
                    processedScriptContent = minificationResult.MinifiedContent ?? string.Empty;
                }

                if (minificationResult.Errors.Count > 0 || minificationResult.Warnings.Count > 0)
                {
                    string sourceCode = context.SourceCode;
                    var documentCoordinates = context.NodeCoordinates;

                    foreach (MinificationErrorInfo error in minificationResult.Errors)
                    {
                        var relativeErrorCoordinates = new SourceCodeNodeCoordinates(error.LineNumber, error.ColumnNumber);
                        var absoluteErrorCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(
                            documentCoordinates, relativeErrorCoordinates);
                        string sourceFragment = SourceCodeNavigator.GetSourceFragment(
                            sourceCode, absoluteErrorCoordinates);
                        string message = error.Message.Trim();

                        WriteError(LogCategoryConstants.JsTemplateMinificationError, message, _fileContext,
                            absoluteErrorCoordinates.LineNumber, absoluteErrorCoordinates.ColumnNumber, sourceFragment);
                    }

                    foreach (MinificationErrorInfo warning in minificationResult.Warnings)
                    {
                        var relativeErrorCoordinates = new SourceCodeNodeCoordinates(warning.LineNumber, warning.ColumnNumber);
                        var absoluteErrorCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(
                            documentCoordinates, relativeErrorCoordinates);
                        string sourceFragment = SourceCodeNavigator.GetSourceFragment(
                            sourceCode, absoluteErrorCoordinates);
                        string message = warning.Message.Trim();

                        WriteWarning(LogCategoryConstants.JsTemplateMinificationWarning, message, _fileContext,
                            absoluteErrorCoordinates.LineNumber, absoluteErrorCoordinates.ColumnNumber, sourceFragment);
                    }
                }

                if (minifyWhitespace && processedScriptContent.Length > 0)
                {
                    processedScriptContent = processedScriptContent.Trim();
                }
            }

            return processedScriptContent;
        }
        /// <summary>
        /// Minify a Knockout binding expression
        /// </summary>
        /// <param name="context">Markup parsing context</param>
        /// <param name="attributeCoordinates">Coordinates of attribute value</param>
        /// <param name="expressionCoordinates">Coordinates of expression</param>
        /// <param name="expression">Binding expression</param>
        /// <returns>Minified binding expression</returns>
        private string MinifyKnockoutBindingExpression(MarkupParsingContext context,
			SourceCodeNodeCoordinates attributeCoordinates, SourceCodeNodeCoordinates expressionCoordinates,
			string expression)
        {
            if (string.IsNullOrWhiteSpace(expression))
            {
                return string.Empty;
            }

            string result = expression;
            CrockfordJsMinifier innerCrockfordJsMinifier = GetInnerCrockfordJsMinifierInstance();
            CodeMinificationResult minificationResult = innerCrockfordJsMinifier.Minify(
                JsonHelpers.WrapStringInCurlyBraces(result), true);
            IList<MinificationErrorInfo> errors = minificationResult.Errors;

            if (errors.Count == 0)
            {
                result = minificationResult.MinifiedContent ?? string.Empty;
            }
            else
            {
                SourceCodeNodeCoordinates absoluteErrorCoordinates = CalculateAbsoluteInlineCodeErrorCoordinates(
                    context.NodeCoordinates, attributeCoordinates, expressionCoordinates);
                string sourceFragment = SourceCodeNavigator.GetSourceFragment(
                    context.SourceCode, absoluteErrorCoordinates);
                string errorMessage = errors[0].Message;

                WriteError(LogCategoryConstants.JsTemplateMinificationError,
                    string.Format(Strings.ErrorMessage_BindingExpressionMinificationFailed,
                        "Knockout", errorMessage.TrimEnd('.')),
                    _fileContext,
                    absoluteErrorCoordinates.LineNumber, absoluteErrorCoordinates.ColumnNumber,
                    sourceFragment);
            }

            result = JsonHelpers.UnwrapStringInCurlyBraces(result);

            return result;
        }
 /// <summary>
 /// Initializes a new instance of the WebMarkupMin.Core.CodeProcessingException class
 /// with a specified error message, node coordinates and source fragment
 /// </summary>
 /// <param name="message">Error message that explains the reason for the exception</param>
 /// <param name="nodeCoordinates">Node coordinates</param>
 /// <param name="sourceFragment">Source fragment</param>
 protected CodeProcessingException(string message, SourceCodeNodeCoordinates nodeCoordinates, string sourceFragment)
     : this(message, nodeCoordinates, sourceFragment, null)
 {
 }
        /// <summary>
        /// Calculates a absolute node coordinates
        /// </summary>
        /// <param name="baseNodeCoordinates">Base node coordinates</param>
        /// <param name="lineBreakCount">Number of line breaks</param>
        /// <param name="charRemainderCount">Number of characters left</param>
        /// <returns>Absolute node coordinates</returns>
        public static SourceCodeNodeCoordinates CalculateAbsoluteNodeCoordinates(
			SourceCodeNodeCoordinates baseNodeCoordinates, int lineBreakCount, int charRemainderCount)
        {
            int absoluteLineNumber;
            int absoluteColumnNumber;

            if (!baseNodeCoordinates.IsEmpty)
            {
                int baseLineNumber = baseNodeCoordinates.LineNumber;
                int baseColumnNumber = baseNodeCoordinates.ColumnNumber;

                if (lineBreakCount > 0)
                {
                    absoluteLineNumber = baseLineNumber + lineBreakCount;
                    absoluteColumnNumber = charRemainderCount + 1;
                }
                else
                {
                    absoluteLineNumber = baseLineNumber;
                    absoluteColumnNumber = baseColumnNumber + charRemainderCount;
                }
            }
            else
            {
                absoluteLineNumber = lineBreakCount + 1;
                absoluteColumnNumber = charRemainderCount + 1;
            }

            var absoluteNodeCoordinates = new SourceCodeNodeCoordinates(absoluteLineNumber, absoluteColumnNumber);

            return absoluteNodeCoordinates;
        }
        private static SourceCodeNodeCoordinates CalculateAbsoluteInlineCodeErrorCoordinates(
			SourceCodeNodeCoordinates tagCoordinates, SourceCodeNodeCoordinates attributeCoordinates,
			SourceCodeNodeCoordinates relativeErrorCoordinates)
        {
            SourceCodeNodeCoordinates absoluteErrorCoordinates;
            if (!attributeCoordinates.IsEmpty)
            {
                absoluteErrorCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(
                    attributeCoordinates, relativeErrorCoordinates);
            }
            else
            {
                absoluteErrorCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(
                    tagCoordinates, relativeErrorCoordinates);
            }

            return absoluteErrorCoordinates;
        }
Example #23
0
        /// <summary>
        /// Parses a start tag
        /// </summary>
        /// <param name="tagName">Tag name</param>
        /// <param name="tagNameInLowercase">Tag name in lowercase</param>
        /// <param name="attributesString">String representation of the attribute list</param>
        /// <param name="attributesCoordinates">Attributes coordinates</param>
        /// <param name="isEmptyTag">Flag that tag is empty</param>
        private void ParseStartTag(string tagName, string tagNameInLowercase, string attributesString,
			SourceCodeNodeCoordinates attributesCoordinates, bool isEmptyTag)
        {
            HtmlTagFlags tagFlags = GetTagFlagsByName(tagNameInLowercase);

            if (tagFlags.HasFlag(HtmlTagFlags.Optional))
            {
                HtmlTag lastStackedTag = _tagStack.LastOrDefault();
                if (lastStackedTag != null && lastStackedTag.NameInLowercase == tagNameInLowercase)
                {
                    ParseEndTag(lastStackedTag.Name, lastStackedTag.NameInLowercase);
                }
                else
                {
                    if (tagNameInLowercase == "body" && _tagStack.Any(t => t.NameInLowercase == "head"))
                    {
                        HtmlTag headTag = _tagStack.Single(t => t.NameInLowercase == "head");
                        ParseEndTag(headTag.Name, headTag.NameInLowercase);
                    }
                }
            }

            if (tagFlags.HasFlag(HtmlTagFlags.Empty))
            {
                isEmptyTag = true;
            }
            else if (isEmptyTag)
            {
                tagFlags |= HtmlTagFlags.Empty;
            }

            var attributes = ParseAttributes(tagName, tagNameInLowercase, tagFlags,
                attributesString, attributesCoordinates);
            var tag = new HtmlTag(tagName, tagNameInLowercase, attributes, tagFlags);

            if (!isEmptyTag)
            {
                if (_conditionalCommentOpened)
                {
                    HtmlConditionalComment lastConditionalComment = _conditionalCommentStack.Peek();
                    HtmlConditionalCommentType lastConditionalCommentType = lastConditionalComment.Type;

                    if (tagFlags.HasFlag(HtmlTagFlags.EmbeddedCode)
                        || lastConditionalCommentType == HtmlConditionalCommentType.RevealedValidating
                        || lastConditionalCommentType == HtmlConditionalCommentType.RevealedValidatingSimplified)
                    {
                        _tagStack.Add(tag);
                    }
                }
                else
                {
                    _tagStack.Add(tag);
                }
            }

            if (_handlers.StartTag != null)
            {
                _handlers.StartTag(_context, tag);
            }

            if (tagFlags.HasFlag(HtmlTagFlags.Xml) && !tagFlags.HasFlag(HtmlTagFlags.NonIndependent))
            {
                _xmlTagStack.Push(tagNameInLowercase);
            }
        }
 /// <summary>
 /// Constructs instance of inner markup parsing context
 /// </summary>
 /// <param name="sourceCode">Source code</param>
 public InnerMarkupParsingContext(string sourceCode)
 {
     _sourceCode = sourceCode;
     _position = 0;
     _nodeCoordinates = new SourceCodeNodeCoordinates(1, 1);
 }
        /// <summary>
        /// Formats a line of source code
        /// </summary>
        /// <param name="line">Line content</param>
        /// <param name="nodeCoordinates">Node coordinates</param>
        /// <param name="lineNumberSize">Number of symbols in the line number caption</param>
        /// <param name="fragmentStartPosition">Start position of source fragment</param>
        /// <param name="fragmentLength">Length of source fragment</param>
        /// <param name="tabSize">Number of spaces in the tab</param>
        /// <returns>Formatted line</returns>
        private static string FormatSourceCodeLine(string line, SourceCodeNodeCoordinates nodeCoordinates,
			int lineNumberSize, int fragmentStartPosition = 0, int fragmentLength = 0, byte tabSize = 4)
        {
            const string ellipsisSymbol = "…";
            const byte leftPaddingSize = 7;

            int lineNumber = nodeCoordinates.LineNumber;
            int columnNumber = nodeCoordinates.ColumnNumber;
            int lineLength = line.Length;

            string processedLine;
            if ((fragmentStartPosition == 0 && fragmentLength == lineLength))
            {
                processedLine = line;
            }
            else if (fragmentStartPosition >= lineLength)
            {
                processedLine = string.Empty;
            }
            else
            {
                int fragmentEndPosition = fragmentStartPosition + fragmentLength - 1;

                bool beginningCutOff = (fragmentStartPosition > 0);
                bool endingCutOff = (fragmentEndPosition <= lineLength);
                if (fragmentEndPosition + 1 == lineLength)
                {
                    endingCutOff = false;
                }

                if (fragmentEndPosition >= lineLength)
                {
                    endingCutOff = false;
                    fragmentEndPosition = lineLength - 1;
                    fragmentLength = fragmentEndPosition - fragmentStartPosition + 1;
                }

                processedLine = line.Substring(fragmentStartPosition, fragmentLength);
                if (beginningCutOff)
                {
                    processedLine = ellipsisSymbol + processedLine;
                }
                if (endingCutOff)
                {
                    processedLine = processedLine + ellipsisSymbol;
                }
            }

            string result = string.Format("Line {0}: {1}",
                lineNumber.ToString(CultureInfo.InvariantCulture).PadLeft(lineNumberSize),
                processedLine.TabsToSpaces(tabSize));
            if (columnNumber > 0)
            {
                int cursorOffset = columnNumber - fragmentStartPosition;
                if (fragmentStartPosition > 0)
                {
                    cursorOffset++;
                }

                result += Environment.NewLine + string.Empty
                    .PadRight(processedLine.Substring(0, cursorOffset - 1)
                    .TabsToSpaces(tabSize).Length + lineNumberSize + leftPaddingSize)
                    .Replace(" ", "-") + "^"
                    ;
            }

            return result;
        }
Example #26
0
 /// <summary>
 /// Constructs instance of stacked XML tag
 /// </summary>
 /// <param name="name">Name</param>
 /// <param name="coordinates">Coordinates of tag</param>
 public StackedXmlTag(string name, SourceCodeNodeCoordinates coordinates)
 {
     Name = name;
     Coordinates = coordinates;
 }
Example #27
0
        /// <summary>
        /// Parses a attributes
        /// </summary>
        /// <param name="tagName">Tag name</param>
        /// <param name="tagNameInLowercase">Tag name in lowercase</param>
        /// <param name="tagFlags">Tag flags</param>
        /// <param name="attributesString">String representation of the attribute list</param>
        /// <param name="attributesCoordinates">Attributes coordinates</param>
        /// <returns>List of attributes</returns>
        private IList<HtmlAttribute> ParseAttributes(string tagName, string tagNameInLowercase, HtmlTagFlags tagFlags,
			string attributesString, SourceCodeNodeCoordinates attributesCoordinates)
        {
            var attributes = new List<HtmlAttribute>();
            if (string.IsNullOrWhiteSpace(attributesString))
            {
                return attributes;
            }

            SourceCodeNodeCoordinates currentAttributesCoordinates = attributesCoordinates;
            int currentPosition = 0;
            MatchCollection attributeMatches = _attributeRegex.Matches(attributesString);

            foreach (Match attributeMatch in attributeMatches)
            {
                GroupCollection groups = attributeMatch.Groups;
                Group attributeNameGroup = groups["attributeName"];
                Group attributeEqualSignGroup = groups["attributeEqualSign"];
                Group attributeValueGroup = groups["attributeValue"];

                string attributeName = attributeNameGroup.Value;
                string attributeNameInLowercase = attributeName;
                if (Utils.ContainsUppercaseCharacters(attributeName))
                {
                    attributeNameInLowercase = attributeName.ToLowerInvariant();
                }
                string attributeValue = null;

                if (attributeEqualSignGroup.Success)
                {
                    if (attributeValueGroup.Success)
                    {
                        attributeValue = attributeValueGroup.Value;
                        if (!string.IsNullOrWhiteSpace(attributeValue))
                        {
                            attributeValue = HtmlAttribute.HtmlAttributeDecode(attributeValue);
                        }
                    }
                    else
                    {
                        attributeValue = string.Empty;
                    }
                }

                var attributeNameCoordinates = SourceCodeNodeCoordinates.Empty;
                int attributeNamePosition = -1;
                if (attributeNameGroup.Success)
                {
                    attributeNamePosition = attributeNameGroup.Index;
                }

                if (attributeNamePosition != -1)
                {
                    int lineBreakCount;
                    int charRemainderCount;

                    SourceCodeNavigator.CalculateLineBreakCount(attributesString, currentPosition,
                        attributeNamePosition - currentPosition, out lineBreakCount, out charRemainderCount);
                    attributeNameCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(
                        currentAttributesCoordinates, lineBreakCount, charRemainderCount);

                    currentAttributesCoordinates = attributeNameCoordinates;
                    currentPosition = attributeNamePosition;
                }

                var attributeValueCoordinates = SourceCodeNodeCoordinates.Empty;
                int attributeValuePosition = -1;
                if (attributeValueGroup.Success)
                {
                    attributeValuePosition = attributeValueGroup.Index;
                }

                if (attributeValuePosition != -1)
                {
                    int lineBreakCount;
                    int charRemainderCount;

                    SourceCodeNavigator.CalculateLineBreakCount(attributesString, currentPosition,
                        attributeValuePosition - currentPosition, out lineBreakCount, out charRemainderCount);
                    attributeValueCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(
                        currentAttributesCoordinates, lineBreakCount, charRemainderCount);

                    currentAttributesCoordinates = attributeValueCoordinates;
                    currentPosition = attributeValuePosition;
                }

                HtmlAttributeType attributeType = GetAttributeType(tagNameInLowercase, tagFlags,
                    attributeNameInLowercase, attributes);

                attributes.Add(new HtmlAttribute(attributeName, attributeNameInLowercase, attributeValue,
                    attributeType, attributeNameCoordinates, attributeValueCoordinates));
            }

            return attributes;
        }
        /// <summary>
        /// Minify a Angular binding expression
        /// </summary>
        /// <param name="context">Markup parsing context</param>
        /// <param name="attributeCoordinates">Coordinates of attribute value</param>
        /// <param name="expression">Binding expression</param>
        /// <returns>Minified binding expression</returns>
        private string MinifyAngularBindingExpression(MarkupParsingContext context,
			SourceCodeNodeCoordinates attributeCoordinates, string expression)
        {
            return MinifyAngularBindingExpression(context, attributeCoordinates, SourceCodeNodeCoordinates.Empty,
                expression);
        }
        /// <summary>
        /// Increases a current parsing position
        /// </summary>
        /// <param name="increment">Increment</param>
        public void IncreasePosition(int increment)
        {
            int oldPosition = _position;
            int newPosition = oldPosition + increment;

            int fragmentStartPosition = oldPosition;
            int fragmentLength = increment;

            int lineBreakCount;
            int charRemainderCount;

            SourceCodeNavigator.CalculateLineBreakCount(_sourceCode, fragmentStartPosition, fragmentLength,
                out lineBreakCount, out charRemainderCount);
            SourceCodeNodeCoordinates currentNodeCoordinates = _nodeCoordinates;

            _nodeCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(currentNodeCoordinates,
                lineBreakCount, charRemainderCount);
            _position = newPosition;
        }
Example #30
0
        /// <summary>
        /// Gets a source fragment
        /// </summary>
        /// <param name="sourceCode">Source code</param>
        /// <param name="nodeCoordinates">Node coordinates</param>
        /// <param name="tabSize">Number of spaces in the tab</param>
        /// <param name="maxFragmentLength">Maximum length of the source fragment</param>
        /// <returns>Source fragment</returns>
        public static string GetSourceFragment(string sourceCode,
                                               SourceCodeNodeCoordinates nodeCoordinates, byte tabSize = DEFAULT_TAB_SIZE,
                                               int maxFragmentLength = DEFAULT_MAX_FRAGMENT_LENGTH)
        {
            string sourceFragment = string.Empty;
            int    lineNumber     = nodeCoordinates.LineNumber;
            int    columnNumber   = nodeCoordinates.ColumnNumber;

            if (!string.IsNullOrEmpty(sourceCode))
            {
                int previousLineNumber = lineNumber - 1;
                int currentLineNumber  = lineNumber;
                int nextLineNumber     = lineNumber + 1;

                string previousLine = string.Empty;
                string currentLine  = string.Empty;
                string nextLine     = string.Empty;

                int lineCount         = 0;
                int lineBreakPosition = int.MinValue;
                int lineBreakLength   = 0;

                do
                {
                    string line;
                    int    startLinePosition = (lineBreakPosition == int.MinValue) ? 0 : lineBreakPosition + lineBreakLength;

                    FindNextLineBreak(sourceCode, startLinePosition, out lineBreakPosition, out lineBreakLength);

                    if (lineBreakPosition != -1)
                    {
                        line = sourceCode.Substring(startLinePosition, lineBreakPosition - startLinePosition);
                    }
                    else
                    {
                        line = sourceCode.Substring(startLinePosition);
                    }

                    lineCount++;

                    if (lineCount == previousLineNumber)
                    {
                        previousLine = line;
                    }
                    else if (lineCount == currentLineNumber)
                    {
                        currentLine = line;
                    }
                    else if (lineCount == nextLineNumber)
                    {
                        nextLine = line;
                    }
                }while (lineBreakPosition != -1 && lineCount <= nextLineNumber);

                int lineNumberSize = (nextLineNumber).ToString(CultureInfo.InvariantCulture).Length;
                if (currentLineNumber == lineCount)
                {
                    lineNumberSize = currentLineNumber.ToString(CultureInfo.InvariantCulture).Length;
                }

                int fragmentStartPosition;
                int fragmentLength;

                CalculateCutPositions(currentLine, columnNumber, maxFragmentLength,
                                      out fragmentStartPosition, out fragmentLength);

                var sourceFragmentBuilder = new StringBuilder();

                if (currentLine.Length > 0)
                {
                    if (previousLine.Length > 0)
                    {
                        sourceFragmentBuilder.AppendLine(FormatSourceCodeLine(previousLine,
                                                                              new SourceCodeNodeCoordinates(previousLineNumber, 0),
                                                                              lineNumberSize, fragmentStartPosition, fragmentLength, tabSize));
                    }

                    sourceFragmentBuilder.AppendLine(FormatSourceCodeLine(currentLine,
                                                                          new SourceCodeNodeCoordinates(currentLineNumber, columnNumber),
                                                                          lineNumberSize, fragmentStartPosition, fragmentLength, tabSize));

                    if (nextLine.Length > 0)
                    {
                        sourceFragmentBuilder.AppendLine(FormatSourceCodeLine(nextLine,
                                                                              new SourceCodeNodeCoordinates(nextLineNumber, 0),
                                                                              lineNumberSize, fragmentStartPosition, fragmentLength, tabSize));
                    }
                }

                sourceFragment = sourceFragmentBuilder.ToString();
            }

            return(sourceFragment);
        }
		/// <summary>
		/// Initializes a new instance of the <see cref="MarkupParsingException"/> class
		/// with a specified error message, node coordinates and source fragment
		/// </summary>
		/// <param name="message">Error message that explains the reason for the exception</param>
		/// <param name="nodeCoordinates">Node coordinates</param>
		/// <param name="sourceFragment">Source fragment</param>
		public MarkupParsingException(string message, SourceCodeNodeCoordinates nodeCoordinates, string sourceFragment)
			: base(message, nodeCoordinates, sourceFragment)
		{ }
Example #32
0
        /// <summary>
        /// Formats a line of source code
        /// </summary>
        /// <param name="line">Line content</param>
        /// <param name="nodeCoordinates">Node coordinates</param>
        /// <param name="lineNumberSize">Number of symbols in the line number caption</param>
        /// <param name="fragmentStartPosition">Start position of source fragment</param>
        /// <param name="fragmentLength">Length of source fragment</param>
        /// <param name="tabSize">Number of spaces in the tab</param>
        /// <returns>Formatted line</returns>
        private static string FormatSourceCodeLine(string line, SourceCodeNodeCoordinates nodeCoordinates,
                                                   int lineNumberSize, int fragmentStartPosition = 0, int fragmentLength = 0, byte tabSize = 4)
        {
            const string ellipsisSymbol  = "…";
            const byte   leftPaddingSize = 7;

            int lineNumber   = nodeCoordinates.LineNumber;
            int columnNumber = nodeCoordinates.ColumnNumber;
            int lineLength   = line.Length;

            string processedLine;

            if ((fragmentStartPosition == 0 && fragmentLength == lineLength))
            {
                processedLine = line;
            }
            else if (fragmentStartPosition >= lineLength)
            {
                processedLine = string.Empty;
            }
            else
            {
                int fragmentEndPosition = fragmentStartPosition + fragmentLength - 1;

                bool beginningCutOff = (fragmentStartPosition > 0);
                bool endingCutOff    = (fragmentEndPosition <= lineLength);
                if (fragmentEndPosition + 1 == lineLength)
                {
                    endingCutOff = false;
                }

                if (fragmentEndPosition >= lineLength)
                {
                    endingCutOff        = false;
                    fragmentEndPosition = lineLength - 1;
                    fragmentLength      = fragmentEndPosition - fragmentStartPosition + 1;
                }

                processedLine = line.Substring(fragmentStartPosition, fragmentLength);
                if (beginningCutOff)
                {
                    processedLine = ellipsisSymbol + processedLine;
                }
                if (endingCutOff)
                {
                    processedLine = processedLine + ellipsisSymbol;
                }
            }

            string result = string.Format("Line {0}: {1}",
                                          lineNumber.ToString(CultureInfo.InvariantCulture).PadLeft(lineNumberSize),
                                          processedLine.TabsToSpaces(tabSize));

            if (columnNumber > 0)
            {
                int cursorOffset = columnNumber - fragmentStartPosition;
                if (fragmentStartPosition > 0)
                {
                    cursorOffset++;
                }

                result += Environment.NewLine + string.Empty
                          .PadRight(processedLine.Substring(0, cursorOffset - 1)
                                    .TabsToSpaces(tabSize).Length + lineNumberSize + leftPaddingSize)
                          .Replace(" ", "-") + "^"
                ;
            }

            return(result);
        }
        /// <summary>
        /// Initializes a new instance of the WebMarkupMin.Core.Parsers.XmlParsingException class
        /// with a specified error message, node coordinates, source fragment
        /// and reference to the inner exception that is the cause of this exception
        /// </summary>
        /// <param name="message">Error message that explains the reason for the exception</param>
        /// <param name="nodeCoordinates">Node coordinates</param>
        /// <param name="sourceFragment">Source fragment</param>
        /// <param name="innerException">Exception that is the cause of the current exception</param>
        public XmlParsingException(string message, SourceCodeNodeCoordinates nodeCoordinates,
			string sourceFragment, Exception innerException)
            : base(message, nodeCoordinates, sourceFragment, innerException)
        {
        }
        /// <summary>
        /// Processes a embedded style content
        /// </summary>
        /// <param name="context">Markup parsing context</param>
        /// <param name="content">Embedded style content</param>
        /// <param name="contentType">Content type (MIME type) of the style</param>
        private void ProcessEmbeddedStyleContent(MarkupParsingContext context, string content, string contentType)
        {
            string code;
            bool isNotEmpty = false;
            string processedContentType = !string.IsNullOrWhiteSpace(contentType) ?
                contentType.Trim().ToLowerInvariant() : CSS_CONTENT_TYPE;
            bool minifyWhitespace = _settings.WhitespaceMinificationMode != WhitespaceMinificationMode.None;
            bool removeHtmlComments = _settings.RemoveHtmlCommentsFromScriptsAndStyles;
            bool removeCdataSections = _settings.RemoveCdataSectionsFromScriptsAndStyles;

            string startPart = string.Empty;
            string endPart = string.Empty;
            string newLine = string.Empty;
            string beforeCodeContent = string.Empty;

            if (_beginCdataSectionRegex.IsMatch(content))
            {
                beforeCodeContent = _beginCdataSectionRegex.Match(content).Value;
                startPart = "<![CDATA[";
                endPart = "]]>";
                newLine = Environment.NewLine;
                code = Utils.RemovePrefixAndPostfix(content, _beginCdataSectionRegex, _endCdataSectionRegex);
            }
            else if (_styleBeginCdataSectionRegex.IsMatch(content))
            {
                beforeCodeContent = _styleBeginCdataSectionRegex.Match(content).Value;

                if (!removeCdataSections)
                {
                    startPart = "/*<![CDATA[*/";
                    endPart = "/*]]>*/";
                }

                code = Utils.RemovePrefixAndPostfix(content, _styleBeginCdataSectionRegex, _styleEndCdataSectionRegex);
            }
            else if (_styleBeginMaxCompatibleCdataSectionRegex.IsMatch(content))
            {
                beforeCodeContent = _styleBeginMaxCompatibleCdataSectionRegex.Match(content).Value;

                if (!removeCdataSections)
                {
                    startPart = "<!--/*--><![CDATA[/*><!--*/";
                    endPart = "/*]]>*/-->";
                }

                code = Utils.RemovePrefixAndPostfix(content, _styleBeginMaxCompatibleCdataSectionRegex,
                    _styleEndMaxCompatibleCdataSectionRegex);
            }
            else if (_beginHtmlCommentRegex.IsMatch(content))
            {
                beforeCodeContent = _beginHtmlCommentRegex.Match(content).Value;

                if (!removeHtmlComments)
                {
                    startPart = "<!--";
                    endPart = "-->";
                }

                code = Utils.RemovePrefixAndPostfix(content, _beginHtmlCommentRegex, _endHtmlCommentRegex);
            }
            else
            {
                code = content;
            }

            if (processedContentType == CSS_CONTENT_TYPE && _settings.MinifyEmbeddedCssCode)
            {
                CodeMinificationResult minificationResult = _cssMinifier.Minify(code, false);
                if (minificationResult.Errors.Count == 0)
                {
                    code = minificationResult.MinifiedContent ?? string.Empty;
                }

                if (minificationResult.Errors.Count > 0 || minificationResult.Warnings.Count > 0)
                {
                    string sourceCode = context.SourceCode;
                    var documentNodeCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(
                        context.NodeCoordinates, beforeCodeContent);

                    foreach (MinificationErrorInfo error in minificationResult.Errors)
                    {
                        var embeddedContentNodeCoordinates = new SourceCodeNodeCoordinates(error.LineNumber, error.ColumnNumber);
                        var absoluteNodeCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(
                            documentNodeCoordinates, embeddedContentNodeCoordinates);
                        string sourceFragment = SourceCodeNavigator.GetSourceFragment(
                            sourceCode, absoluteNodeCoordinates);
                        string message = error.Message.Trim();

                        WriteError(LogCategoryConstants.CssMinificationError, message, _fileContext,
                            absoluteNodeCoordinates.LineNumber, absoluteNodeCoordinates.ColumnNumber, sourceFragment);
                    }

                    foreach (MinificationErrorInfo warning in minificationResult.Warnings)
                    {
                        var embeddedContentNodeCoordinates = new SourceCodeNodeCoordinates(warning.LineNumber, warning.ColumnNumber);
                        var absoluteNodeCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates(
                            documentNodeCoordinates, embeddedContentNodeCoordinates);
                        string sourceFragment = SourceCodeNavigator.GetSourceFragment(
                            sourceCode, absoluteNodeCoordinates);
                        string message = warning.Message.Trim();

                        WriteWarning(LogCategoryConstants.CssMinificationWarning, message, _fileContext,
                            absoluteNodeCoordinates.LineNumber, absoluteNodeCoordinates.ColumnNumber, sourceFragment);
                    }
                }
            }

            if (minifyWhitespace && code.Length > 0)
            {
                code = code.Trim();
            }

            if (startPart.Length > 0)
            {
                _buffer.Add(startPart);
                if (newLine.Length > 0)
                {
                    _buffer.Add(newLine);
                }
                isNotEmpty = true;
            }
            if (code.Length > 0)
            {
                _buffer.Add(code);
                isNotEmpty = true;
            }
            if (endPart.Length > 0)
            {
                if (newLine.Length > 0)
                {
                    _buffer.Add(newLine);
                }
                _buffer.Add(endPart);
                isNotEmpty = true;
            }

            _currentText = isNotEmpty ? EMBEDDED_CODE_PLACEHOLDER : string.Empty;
        }