/// <summary> /// Generates a detailed error message /// </summary> /// <param name="errorDetails">Error details</param> /// <param name="sourceCode">Source code</param> /// <param name="currentFilePath">Path to current EcmaScript2015-file</param> /// <returns>Detailed error message</returns> private static string FormatErrorDetails(JToken errorDetails, string sourceCode, string currentFilePath) { var message = errorDetails.Value <string>("message"); string file = currentFilePath; var lineNumber = errorDetails.Value <int>("lineNumber"); var columnNumber = errorDetails.Value <int>("columnNumber"); string sourceFragment = SourceCodeNavigator.GetSourceFragment(sourceCode, new SourceCodeNodeCoordinates(lineNumber, columnNumber)); var errorMessage = new StringBuilder(); errorMessage.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_Message, message); if (!string.IsNullOrWhiteSpace(file)) { errorMessage.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_File, file); } if (lineNumber > 0) { errorMessage.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_LineNumber, lineNumber.ToString(CultureInfo.InvariantCulture)); } if (columnNumber > 0) { errorMessage.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_ColumnNumber, columnNumber.ToString(CultureInfo.InvariantCulture)); } if (!string.IsNullOrWhiteSpace(sourceFragment)) { errorMessage.AppendFormatLine("{1}:{0}{0}{2}", Environment.NewLine, CoreStrings.ErrorDetails_SourceError, sourceFragment); } return(errorMessage.ToString()); }
public TutorialStepPresenter(IStepView view, string contentPath, Lifetime lifetime, ISolution solution, IPsiFiles psiFiles, TextControlManager textControlManager, IShellLocks shellLocks, IEditorManager editorManager, DocumentManager documentManager, IUIApplication environment, IActionManager actionManager, IPsiServices psiServices, IActionShortcuts shortcutManager) { _stepView = view; Lifetime = lifetime; Solution = solution; PsiFiles = psiFiles; TextControlManager = textControlManager; ShellLocks = shellLocks; EditorManager = editorManager; DocumentManager = documentManager; Environment = environment; ActionManager = actionManager; _contentPath = contentPath; _codeNavigator = new SourceCodeNavigator(lifetime, solution, psiFiles, textControlManager, shellLocks, editorManager, documentManager, environment); _steps = new Dictionary <int, TutorialStep>(); _steps = TutorialXmlReader.ReadTutorialSteps(contentPath); _currentStepId = TutorialXmlReader.ReadCurrentStep(contentPath); CurrentStep = _steps[_currentStepId]; lifetime.AddBracket( () => { _stepView.NextStep += GoNext; }, () => { _stepView.NextStep -= GoNext; }); ProcessStep(); }
/// <summary> /// Generates a detailed error message /// </summary> /// <param name="errorDetails">String representation of error</param> /// <param name="sourceCode">Source code</param> /// <param name="currentFilePath">Path to current CSS file</param> /// <rereturns>Detailed error message</rereturns> private static string FormatErrorDetails(string errorDetails, string sourceCode, string currentFilePath) { string errorMessage; Match errorStringMatch = _errorStringRegex.Match(errorDetails); if (errorStringMatch.Success) { GroupCollection errorStringGroups = errorStringMatch.Groups; string message = errorStringGroups["message"].Value; string errorCode = errorStringGroups["errorCode"].Value; const int severity = 0; string subcategory = errorStringGroups["subcategory"].Value; string file = currentFilePath; int lineNumber = int.Parse(errorStringGroups["lineNumber"].Value); int columnNumber = int.Parse(errorStringGroups["columnNumber"].Value) + 1; string sourceFragment = SourceCodeNavigator.GetSourceFragment(sourceCode, new SourceCodeNodeCoordinates(lineNumber, columnNumber)); var stringBuilderPool = StringBuilderPool.Shared; StringBuilder errorMessageBuilder = stringBuilderPool.Rent(); errorMessageBuilder.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_Message, message); errorMessageBuilder.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_ErrorCode, errorCode); errorMessageBuilder.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_Severity, severity.ToString(CultureInfo.InvariantCulture)); errorMessageBuilder.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_Subcategory, subcategory); if (!string.IsNullOrWhiteSpace(file)) { errorMessageBuilder.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_File, file); } if (lineNumber > 0) { errorMessageBuilder.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_LineNumber, lineNumber.ToString(CultureInfo.InvariantCulture)); } if (columnNumber > 0) { errorMessageBuilder.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_ColumnNumber, columnNumber.ToString(CultureInfo.InvariantCulture)); } if (!string.IsNullOrWhiteSpace(sourceFragment)) { errorMessageBuilder.AppendFormatLine("{1}:{0}{0}{2}", Environment.NewLine, CoreStrings.ErrorDetails_SourceError, sourceFragment); } errorMessage = errorMessageBuilder.ToString(); stringBuilderPool.Return(errorMessageBuilder); } else { errorMessage = errorDetails; } return(errorMessage); }
/// <summary> /// Generates a detailed error message /// </summary> /// <param name="errorDetails">Error details</param> /// <param name="isError">Flag indicating that this issue is a error</param> /// <param name="sourceCode">Source code</param> /// <param name="currentFilePath">Path to current JS file</param> /// <returns>Detailed error message</returns> private static string FormatErrorDetails(JToken errorDetails, bool isError, string sourceCode, string currentFilePath) { string message; string file = currentFilePath; int lineNumber = 0; int columnNumber = 0; var errorString = errorDetails.Value <string>("message"); Match errorStringMatch = _errorStringRegex.Match(errorString); if (errorStringMatch.Success) { GroupCollection errorStringGroups = errorStringMatch.Groups; message = errorStringGroups["message"].Value; lineNumber = int.Parse(errorStringGroups["lineNumber"].Value); columnNumber = int.Parse(errorStringGroups["columnNumber"].Value) + 1; } else { message = errorString; if (isError) { lineNumber = errorDetails.Value <int>("lineNumber"); columnNumber = errorDetails.Value <int>("columnNumber"); } } string sourceFragment = SourceCodeNavigator.GetSourceFragment(sourceCode, new SourceCodeNodeCoordinates(lineNumber, columnNumber)); var errorMessage = new StringBuilder(); errorMessage.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_ErrorType, isError ? CoreStrings.ErrorType_Error : CoreStrings.ErrorType_Warning); errorMessage.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_Message, message); if (!string.IsNullOrWhiteSpace(file)) { errorMessage.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_File, file); } if (lineNumber > 0) { errorMessage.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_LineNumber, lineNumber.ToString(CultureInfo.InvariantCulture)); } if (columnNumber > 0) { errorMessage.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_ColumnNumber, columnNumber.ToString(CultureInfo.InvariantCulture)); } if (!string.IsNullOrWhiteSpace(sourceFragment)) { errorMessage.AppendFormatLine("{1}:{0}{0}{2}", Environment.NewLine, CoreStrings.ErrorDetails_SourceError, sourceFragment); } return(errorMessage.ToString()); }
/// <summary> /// Process a start tag /// </summary> /// <returns>Result of processing (true - is processed; false - is not processed)</returns> private bool ProcessStartTag() { bool isProcessed = false; string content = _innerContext.SourceCode; Match startTagBeginPartMatch = _startTagBeginPartRegex.Match(content, _innerContext.Position, _innerContext.RemainderLength); if (startTagBeginPartMatch.Success) { string startTagName = startTagBeginPartMatch.Groups["tagName"].Value; List <XmlAttribute> attributes = null; bool isEmptyTag; _innerContext.IncreasePosition(startTagBeginPartMatch.Length); isProcessed = ProcessStartTagEndPart(out isEmptyTag); if (!isProcessed) { attributes = ProcessAttributes(); isProcessed = ProcessStartTagEndPart(out isEmptyTag); } if (isProcessed) { attributes = attributes ?? new List <XmlAttribute>(); if (isEmptyTag) { _handlers.EmptyTag?.Invoke(_context, startTagName, attributes); } else { _tagStack.Push(new StackedXmlTag(startTagName, _innerContext.NodeCoordinates)); _handlers.StartTag?.Invoke(_context, startTagName, attributes); } } else { int currentPosition = _innerContext.Position; int invalidCharPosition = SourceCodeNavigator.FindNextNonWhitespaceChar(content, currentPosition, _innerContext.RemainderLength); int invalidCharOffset = invalidCharPosition - currentPosition; if (invalidCharOffset > 0) { _innerContext.IncreasePosition(invalidCharOffset); } throw new MarkupParsingException( string.Format(Strings.ErrorMessage_InvalidCharactersInStartTag, startTagName), _innerContext.NodeCoordinates, _innerContext.GetSourceFragment()); } } return(isProcessed); }
/// <summary> /// Generates a detailed error message /// </summary> /// <param name="errorDetails">Error details</param> /// <param name="sourceCode">Source code</param> /// <param name="currentFilePath">Path to current LESS file</param> /// <returns>Detailed error message</returns> private string FormatErrorDetails(JToken errorDetails, string sourceCode, string currentFilePath) { var type = errorDetails.Value <string>("type"); var message = errorDetails.Value <string>("message"); var filePath = errorDetails.Value <string>("fileName"); if (string.IsNullOrWhiteSpace(filePath)) { filePath = currentFilePath; } var lineNumber = errorDetails.Value <int>("lineNumber"); var columnNumber = errorDetails.Value <int>("columnNumber"); string newSourceCode; if (string.Equals(filePath, currentFilePath, StringComparison.OrdinalIgnoreCase)) { newSourceCode = sourceCode; } else { newSourceCode = _virtualFileManager.ReadTextFile(filePath); } string sourceFragment = SourceCodeNavigator.GetSourceFragment(newSourceCode, new SourceCodeNodeCoordinates(lineNumber, columnNumber)); var errorMessage = new StringBuilder(); if (!string.IsNullOrWhiteSpace(type)) { errorMessage.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_ErrorType, type); } errorMessage.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_Message, message); if (!string.IsNullOrWhiteSpace(filePath)) { errorMessage.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_File, filePath); } if (lineNumber > 0) { errorMessage.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_LineNumber, lineNumber.ToString(CultureInfo.InvariantCulture)); } if (columnNumber > 0) { errorMessage.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_ColumnNumber, columnNumber.ToString(CultureInfo.InvariantCulture)); } if (!string.IsNullOrWhiteSpace(sourceFragment)) { errorMessage.AppendFormatLine("{1}:{0}{0}{2}", Environment.NewLine, CoreStrings.ErrorDetails_SourceError, sourceFragment); } return(errorMessage.ToString()); }
/// <summary> /// Process a start tag /// </summary> /// <returns>Result of processing (true - is processed; false - is not processed)</returns> private bool ProcessStartTag() { bool isProcessed = false; string content = _innerContext.SourceCode; Match startTagBeginPartMatch = _startTagBeginPartRegex.Match(content, _innerContext.Position, _innerContext.RemainderLength); if (startTagBeginPartMatch.Success) { string startTagName = startTagBeginPartMatch.Groups["tagName"].Value; string startTagNameInLowercase = startTagName; if (Utils.ContainsUppercaseCharacters(startTagName)) { startTagNameInLowercase = startTagName.ToLowerInvariant(); } List <HtmlAttribute> attributes = null; bool isEmptyTag; _innerContext.IncreasePosition(startTagBeginPartMatch.Length); isProcessed = ProcessStartTagEndPart(out isEmptyTag); if (!isProcessed) { attributes = ProcessAttributes(); isProcessed = ProcessStartTagEndPart(out isEmptyTag); } if (isProcessed) { attributes = attributes ?? new List <HtmlAttribute>(); ParseStartTag(startTagName, startTagNameInLowercase, attributes, isEmptyTag); } else { int currentPosition = _innerContext.Position; int invalidCharPosition = SourceCodeNavigator.FindNextNonWhitespaceChar(content, currentPosition, _innerContext.RemainderLength); int invalidCharOffset = invalidCharPosition - currentPosition; if (invalidCharOffset > 0) { _innerContext.IncreasePosition(invalidCharOffset); } throw new MarkupParsingException( string.Format(Strings.ErrorMessage_InvalidCharactersInStartTag, startTagName), _innerContext.NodeCoordinates, _innerContext.GetSourceFragment()); } } return(isProcessed); }
/// <summary> /// Process a end tag /// </summary> /// <returns>Result of processing (true - is processed; false - is not processed)</returns> private bool ProcessEndTag() { bool isProcessed = false; string content = _innerContext.SourceCode; int contentRemainderLength = _innerContext.RemainderLength; var match = _endTagRegex.Match(content, _innerContext.Position, contentRemainderLength); if (match.Success) { string endTag = match.Value; string endTagName = match.Groups["tagName"].Value; if (_tagStack.Count == 0) { throw new XmlParsingException( string.Format(Strings.ErrorMessage_StartTagNotDeclared, endTagName), _innerContext.NodeCoordinates, _innerContext.GetSourceFragment()); } StackedXmlTag stackedTag = _tagStack.Pop(); if (stackedTag.Name != endTagName) { if (_tagStack.Count(t => t.Name == endTagName) > 0) { throw new XmlParsingException( string.Format(Strings.ErrorMessage_NotClosedTag, stackedTag.Name), stackedTag.Coordinates, SourceCodeNavigator.GetSourceFragment(_innerContext.SourceCode, stackedTag.Coordinates)); } throw new XmlParsingException( string.Format(Strings.ErrorMessage_StartTagNotDeclared, endTagName), _innerContext.NodeCoordinates, _innerContext.GetSourceFragment()); } if (_handlers.EndTag != null) { _handlers.EndTag(_context, endTagName); } _innerContext.IncreasePosition(endTag.Length); isProcessed = true; } return(isProcessed); }
private ProcessingResult CreateProcessingResultFromJson(JObject resultJson, string content, string inputPath) { string processedContent = resultJson.Value <string>("processedContent"); string sourceMap = resultJson.Value <string>("sourceMap"); if (_options.SourceMap && string.IsNullOrWhiteSpace(sourceMap)) { sourceMap = SourceMapExtractor.ExtractSourceMap(processedContent); } var warnings = new List <ProblemInfo>(); var warningsJson = resultJson["warnings"] as JArray; if (warningsJson != null && warningsJson.Count > 0) { foreach (JObject warningJson in warningsJson) { var message = warningJson.Value <string>("message"); string description = warningJson.Value <string>("description"); string file = warningJson.Value <string>("file"); var lineNumber = warningJson.Value <int>("lineNumber"); var columnNumber = warningJson.Value <int>("columnNumber"); string sourceFragment = string.Empty; if (file == inputPath) { sourceFragment = SourceCodeNavigator.GetSourceFragment(content, new SourceCodeNodeCoordinates(lineNumber, columnNumber)); } warnings.Add(new ProblemInfo { Message = message, Description = description, File = file, LineNumber = lineNumber, ColumnNumber = columnNumber, SourceFragment = sourceFragment }); } } var processingResult = new ProcessingResult(processedContent, sourceMap, warnings); return(processingResult); }
/// <summary> /// Generates a detailed error message /// </summary> /// <param name="errorDetails">Error details</param> /// <param name="currentFilePath">Path to current TypeScript file</param> /// <returns>Detailed error message</returns> private string FormatErrorDetails(JToken errorDetails, string currentFilePath) { var message = errorDetails.Value <string>("message"); var filePath = errorDetails.Value <string>("fileName"); if (string.IsNullOrWhiteSpace(filePath)) { filePath = currentFilePath; } var lineNumber = errorDetails.Value <int>("lineNumber"); var columnNumber = errorDetails.Value <int>("columnNumber"); string newSourceCode = _virtualFileManager.ReadFile(filePath); string sourceFragment = SourceCodeNavigator.GetSourceFragment(newSourceCode, new SourceCodeNodeCoordinates(lineNumber, columnNumber)); var stringBuilderPool = StringBuilderPool.Shared; StringBuilder errorMessageBuilder = stringBuilderPool.Rent(); errorMessageBuilder.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_Message, message); if (!string.IsNullOrWhiteSpace(filePath)) { errorMessageBuilder.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_File, filePath); } if (lineNumber > 0) { errorMessageBuilder.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_LineNumber, lineNumber.ToString(CultureInfo.InvariantCulture)); } if (columnNumber > 0) { errorMessageBuilder.AppendFormatLine("{0}: {1}", CoreStrings.ErrorDetails_ColumnNumber, columnNumber.ToString(CultureInfo.InvariantCulture)); } if (!string.IsNullOrWhiteSpace(sourceFragment)) { errorMessageBuilder.AppendFormatLine("{1}:{0}{0}{2}", Environment.NewLine, CoreStrings.ErrorDetails_SourceError, sourceFragment); } string errorMessage = errorMessageBuilder.ToString(); stringBuilderPool.Return(errorMessageBuilder); return(errorMessage); }
/// <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; }
private AutoprefixerProcessingException CreateProcessingExceptionFromJson(JToken error, string content, string inputPath) { var message = error.Value <string>("message"); string description = error.Value <string>("description"); if (string.IsNullOrWhiteSpace(description)) { description = message; } string type = error.Value <string>("type"); string file = error.Value <string>("file"); if (string.IsNullOrWhiteSpace(file) && !string.IsNullOrWhiteSpace(inputPath)) { file = inputPath; } var lineNumber = error.Value <int>("lineNumber"); var columnNumber = error.Value <int>("columnNumber"); string sourceFragment = string.Empty; if (file == inputPath) { sourceFragment = SourceCodeNavigator.GetSourceFragment(content, new SourceCodeNodeCoordinates(lineNumber, columnNumber)); } var processingException = new AutoprefixerProcessingException(message) { Description = description, Type = type, File = file, LineNumber = lineNumber, ColumnNumber = columnNumber, SourceFragment = sourceFragment }; return(processingException); }
public TutorialStepPresenter(IStepView view, string contentPath, Lifetime lifetime, ISolution solution, IPsiFiles psiFiles, ChangeManager changeManager, TextControlManager textControlManager, IShellLocks shellLocks, IEditorManager editorManager, DocumentManager documentManager, IUIApplication environment, IActionManager actionManager) { _stepView = view; _lifetime = lifetime; Solution = solution; PsiFiles = psiFiles; ChangeManager = changeManager; TextControlManager = textControlManager; ShellLocks = shellLocks; EditorManager = editorManager; DocumentManager = documentManager; Environment = environment; ActionManager = actionManager; _codeNavigator = new SourceCodeNavigator(lifetime, solution, psiFiles, shellLocks, editorManager, documentManager); _steps = new Dictionary <int, TutorialStep>(); var tutorialXmlReader = new TutorialXmlReader(actionManager); _steps = tutorialXmlReader.ReadTutorialSteps(contentPath); Title = TutorialXmlReader.ReadTitle(contentPath); //TODO: get rid of _currentStepId _currentStepId = 1; CurrentStep = _steps[_currentStepId]; _stepView.StepCount = _steps.Count; lifetime.AddBracket( () => { _stepView.NextStep += StepOnStepIsDone; }, () => { _stepView.NextStep -= StepOnStepIsDone; }); ProcessCurrentStep(); }
private static CompilationResult EndCompile(SassContextBase context) { CompilationResult result; SassErrorInfo error = context.Error; if (error == null) { result = new CompilationResult { CompiledContent = context.OutputString, IncludedFilePaths = context.IncludedFiles.ToList(), SourceMap = context.SourceMapString }; } else { string message = error.Message.TrimEnd(); string sourceCode = error.Source; int lineNumber = error.Line; int columnNumber = error.Column; string sourceFragment = SourceCodeNavigator.GetSourceFragment(sourceCode, new SourceCodeNodeCoordinates(lineNumber, columnNumber)); throw new SassCompilationException(message) { ErrorCode = error.Status, Description = error.Text, File = error.File, LineNumber = lineNumber, ColumnNumber = columnNumber, SourceFragment = sourceFragment }; } return(result); }
/// <summary> /// Generates a detailed error message /// </summary> /// <param name="sassСompilationException">Sass compilation exception</param> /// <returns>Detailed error message</returns> public static string Format(SassСompilationException sassСompilationException) { string message = sassСompilationException.Text; string filePath = sassСompilationException.File; int lineNumber = sassСompilationException.LineNumber; int columnNumber = sassСompilationException.ColumnNumber; string sourceCode = sassСompilationException.Source; string sourceFragment = SourceCodeNavigator.GetSourceFragment(sourceCode, new SourceCodeNodeCoordinates(lineNumber, columnNumber)); var errorMessage = new StringBuilder(); errorMessage.AppendFormatLine("{0}: {1}", Strings.ErrorDetails_Message, message); if (!string.IsNullOrWhiteSpace(filePath)) { errorMessage.AppendFormatLine("{0}: {1}", Strings.ErrorDetails_File, filePath); } if (lineNumber > 0) { errorMessage.AppendFormatLine("{0}: {1}", Strings.ErrorDetails_LineNumber, lineNumber.ToString(CultureInfo.InvariantCulture)); } if (columnNumber > 0) { errorMessage.AppendFormatLine("{0}: {1}", Strings.ErrorDetails_ColumnNumber, columnNumber.ToString(CultureInfo.InvariantCulture)); } if (!string.IsNullOrWhiteSpace(sourceFragment)) { errorMessage.AppendFormatLine("{1}:{0}{0}{2}", Environment.NewLine, Strings.ErrorDetails_SourceFragment, sourceFragment); } return(errorMessage.ToString()); }
/// <summary> /// Gets a source fragment /// </summary> /// <returns>Source fragment</returns> public string GetSourceFragment() { return(SourceCodeNavigator.GetSourceFragment(_sourceCode, _nodeCoordinates)); }
/// <summary> /// Parses XML content /// </summary> /// <param name="content">XML content</param> public void Parse(string content) { int contentLength = content.Length; if (contentLength == 0) { return; } lock (_parsingSynchronizer) { _innerContext = new InnerMarkupParsingContext(content); _context = new MarkupParsingContext(_innerContext); _tagStack = new Stack <StackedXmlTag>(); int endPosition = contentLength - 1; int previousPosition = -1; try { while (_innerContext.Position <= endPosition) { bool isProcessed = false; if (content.CustomStartsWith("<", _innerContext.Position, StringComparison.Ordinal)) { if (content.CustomStartsWith("</", _innerContext.Position, StringComparison.Ordinal)) { // End tag isProcessed = ProcessEndTag(); } else if (content.CustomStartsWith("<!", _innerContext.Position, StringComparison.Ordinal)) { // XML comments isProcessed = ProcessComment(); if (!isProcessed) { // CDATA sections isProcessed = ProcessCdataSection(); } if (!isProcessed) { // Doctype declaration isProcessed = ProcessDoctype(); } } else if (content.CustomStartsWith("<?", _innerContext.Position, StringComparison.Ordinal)) { // XML declaration and processing instructions isProcessed = ProcessProcessingInstruction(); } else { // Start tag isProcessed = ProcessStartTag(); } } if (!isProcessed) { // Text ProcessText(); } if (_innerContext.Position == previousPosition) { throw new XmlParsingException( string.Format(Strings.ErrorMessage_MarkupParsingFailed, "XML"), _innerContext.NodeCoordinates, _innerContext.GetSourceFragment()); } previousPosition = _innerContext.Position; } // Check whether there were not closed tags if (_tagStack.Count > 0) { StackedXmlTag stackedTag = _tagStack.Pop(); throw new XmlParsingException( string.Format(Strings.ErrorMessage_NotClosedTag, stackedTag.Name), stackedTag.Coordinates, SourceCodeNavigator.GetSourceFragment(_innerContext.SourceCode, stackedTag.Coordinates)); } } catch (XmlParsingException) { throw; } finally { _tagStack.Clear(); _context = null; _innerContext = null; } } }
/// <summary> /// Parses XML content /// </summary> /// <param name="content">XML content</param> public void Parse(string content) { int contentLength = content.Length; if (contentLength == 0) { return; } lock (_parsingSynchronizer) { _innerContext = new InnerMarkupParsingContext(content); _context = new MarkupParsingContext(_innerContext); int endPosition = contentLength - 1; int previousPosition = -1; try { while (_innerContext.Position <= endPosition) { bool isProcessed = false; if (_innerContext.PeekCurrentChar() == '<') { switch (_innerContext.PeekNextChar()) { case char c when IsTagFirstChar(c): // Start tag isProcessed = ProcessStartTag(); break; case '/': if (IsTagFirstChar(_innerContext.PeekNextChar())) { // End tag isProcessed = ProcessEndTag(); } break; case '!': switch (_innerContext.PeekNextChar()) { case '-': if (_innerContext.PeekNextChar() == '-') { // XML comments isProcessed = ProcessComment(); } break; case '[': // CDATA sections isProcessed = ProcessCdataSection(); break; case 'D': // Doctype declaration isProcessed = ProcessDoctype(); break; } break; case '?': // XML declaration and processing instructions isProcessed = ProcessProcessingInstruction(); break; } } if (!isProcessed) { // Text ProcessText(); } if (_innerContext.Position == previousPosition) { throw new MarkupParsingException( string.Format(Strings.ErrorMessage_MarkupParsingFailed, "XML"), _innerContext.NodeCoordinates, _innerContext.GetSourceFragment()); } previousPosition = _innerContext.Position; } // Check whether there were not closed tags if (_tagStack.Count > 0) { StackedXmlTag stackedTag = _tagStack.Pop(); throw new MarkupParsingException( string.Format(Strings.ErrorMessage_NotClosedTag, stackedTag.Name), stackedTag.Coordinates, SourceCodeNavigator.GetSourceFragment(_innerContext.SourceCode, stackedTag.Coordinates)); } } catch (MarkupParsingException) { throw; } finally { _tagStack.Clear(); _context = null; _innerContext = null; } } }
/// <summary> /// Process a attributes /// </summary> /// <returns>List of attributes</returns> private List <HtmlAttribute> ProcessAttributes() { string content = _innerContext.SourceCode; int currentPosition = _innerContext.Position; SourceCodeNodeCoordinates currentCoordinates = _innerContext.NodeCoordinates; Match match = _attributeRegex.Match(content, currentPosition, _innerContext.RemainderLength); while (match.Success) { GroupCollection groups = match.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 = HtmlAttributeValueHelpers.Decode(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(content, currentPosition, attributeNamePosition - currentPosition, out lineBreakCount, out charRemainderCount); attributeNameCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates( currentCoordinates, lineBreakCount, charRemainderCount); currentPosition = attributeNamePosition; currentCoordinates = attributeNameCoordinates; } var attributeValueCoordinates = SourceCodeNodeCoordinates.Empty; int attributeValuePosition = -1; if (attributeValueGroup.Success) { attributeValuePosition = attributeValueGroup.Index; } if (attributeValuePosition != -1) { int lineBreakCount; int charRemainderCount; SourceCodeNavigator.CalculateLineBreakCount(content, currentPosition, attributeValuePosition - currentPosition, out lineBreakCount, out charRemainderCount); attributeValueCoordinates = SourceCodeNavigator.CalculateAbsoluteNodeCoordinates( currentCoordinates, lineBreakCount, charRemainderCount); currentPosition = attributeValuePosition; currentCoordinates = attributeValueCoordinates; } var attribute = new HtmlAttribute(attributeName, attributeNameInLowercase, attributeValue, HtmlAttributeType.Unknown, attributeNameCoordinates, attributeValueCoordinates); _tempAttributes.Add(attribute); _innerContext.IncreasePosition(match.Length); match = _attributeRegex.Match(content, _innerContext.Position, _innerContext.RemainderLength); } int attributeCount = _tempAttributes.Count; var attributes = new List <HtmlAttribute>(attributeCount); for (int attributeIndex = 0; attributeIndex < attributeCount; attributeIndex++) { attributes.Add(_tempAttributes[attributeIndex]); } _tempAttributes.Clear(); return(attributes); }
/// <summary> /// Process a XML declaration and processing instructions /// </summary> /// <returns>Result of processing (true - is processed; false - is not processed)</returns> private bool ProcessProcessingInstruction() { bool isProcessed = false; string content = _innerContext.SourceCode; Match processingInstructionBeginPartMatch = _processingInstructionBeginPartRegex.Match(content, _innerContext.Position, _innerContext.RemainderLength); if (processingInstructionBeginPartMatch.Success) { string instructionName = processingInstructionBeginPartMatch.Groups["instructionName"].Value; bool isXmlDeclaration = instructionName.Equals("xml", StringComparison.OrdinalIgnoreCase); List <XmlAttribute> attributes = null; _innerContext.IncreasePosition(processingInstructionBeginPartMatch.Length); isProcessed = ProcessProcessingInstructionEndPart(); if (!isProcessed) { attributes = ProcessAttributes(); isProcessed = ProcessProcessingInstructionEndPart(); } if (isProcessed) { attributes = attributes ?? new List <XmlAttribute>(); if (isXmlDeclaration) { _handlers.XmlDeclaration?.Invoke(_context, attributes); } else { _handlers.ProcessingInstruction?.Invoke(_context, instructionName, attributes); } } else { int currentPosition = _innerContext.Position; int invalidCharPosition = SourceCodeNavigator.FindNextNonWhitespaceChar(content, currentPosition, _innerContext.RemainderLength); int invalidCharOffset = invalidCharPosition - currentPosition; if (invalidCharOffset > 0) { _innerContext.IncreasePosition(invalidCharOffset); } string errorMessage = isXmlDeclaration ? Strings.ErrorMessage_InvalidCharactersInXmlDeclaration : string.Format(Strings.ErrorMessage_InvalidCharactersInProcessingInstruction, instructionName) ; throw new MarkupParsingException(errorMessage, _innerContext.NodeCoordinates, _innerContext.GetSourceFragment()); } } return(isProcessed); }