From 20269d5d0a4e3c2f4ece8756e083525a48542302 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Thu, 21 Jan 2021 16:59:38 +0100 Subject: [PATCH 1/2] Replace document root detection method --- server/galaxyls/server.py | 4 ++- server/galaxyls/services/validation.py | 33 ++++++++++++++++++++++++ server/galaxyls/services/xml/document.py | 15 ----------- 3 files changed, 36 insertions(+), 16 deletions(-) create mode 100644 server/galaxyls/services/validation.py diff --git a/server/galaxyls/server.py b/server/galaxyls/server.py index 1646ef1..cf14074 100644 --- a/server/galaxyls/server.py +++ b/server/galaxyls/server.py @@ -33,6 +33,8 @@ ) from pygls.workspace import Document +from galaxyls.services.validation import DocumentValidator + from .config import CompletionMode, GalaxyToolsConfiguration from .features import AUTO_CLOSE_TAGS, CMD_GENERATE_COMMAND, CMD_GENERATE_TEST from .services.language import GalaxyToolLanguageService @@ -182,4 +184,4 @@ def _get_xml_document(document: Document) -> XmlDocument: def _is_document_supported(document: Document) -> bool: """Returns True if the given document is supported by the server.""" - return XmlDocument.has_valid_root(document) + return DocumentValidator().has_valid_root(document) diff --git a/server/galaxyls/services/validation.py b/server/galaxyls/services/validation.py new file mode 100644 index 0000000..06aa104 --- /dev/null +++ b/server/galaxyls/services/validation.py @@ -0,0 +1,33 @@ +import re + +from typing import Optional +from pygls.workspace import Document + +from galaxyls.services.xml.types import DocumentType + +MAX_PEEK_CONTENT = 100 +TAG_GROUP_NAME = "tag" +TAG_REGEX = rf"[\n\s]*?.*?[\n\s]*?<(?!\?)(?P<{TAG_GROUP_NAME}>[\w]*)" + + +class DocumentValidator: + """Provides some utilities to quickly check documents without completely parse them beforehand.""" + + def has_valid_root(self, document: Document) -> bool: + """Checks if the document's root element matches one of the supported types.""" + root = self._get_document_root_tag(document) + if root is not None: + root_tag = root.upper() + supported = [e.name for e in DocumentType if e != DocumentType.UNKNOWN] + return root_tag in supported + return False + + def _get_document_root_tag(self, document: Document) -> Optional[str]: + """Checks the first MAX_PEEK_CONTENT characters of the document for a root tag and + returns the name of the tag if found.""" + content_peek = document.source[:MAX_PEEK_CONTENT] + match = re.match(TAG_REGEX, content_peek) + if match: + group = match.group(TAG_GROUP_NAME) + return group + return None diff --git a/server/galaxyls/services/xml/document.py b/server/galaxyls/services/xml/document.py index 88aeedf..d8c7ee9 100644 --- a/server/galaxyls/services/xml/document.py +++ b/server/galaxyls/services/xml/document.py @@ -1,7 +1,6 @@ from typing import Dict, Optional from anytree.search import findall -from lxml import etree from pygls.types import Position, Range from pygls.workspace import Document @@ -118,17 +117,3 @@ def get_position_after(self, element: XmlElement) -> Position: if element.is_self_closed: return convert_document_offset_to_position(self.document, element.end) return convert_document_offset_to_position(self.document, element.end_offset) - - @staticmethod - def has_valid_root(document: Document) -> bool: - """Checks if the document's root element matches one of the supported types.""" - try: - xml = etree.parse(str(document.path)) - root = xml.getroot() - if root is not None and root.tag: - root_tag = root.tag.upper() - supported = [e.name for e in DocumentType if e != DocumentType.UNKNOWN] - return root_tag in supported - return False - except BaseException: - return False From 32ad7095b24e378d91f7f9c480b09e0e844bf780 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Thu, 21 Jan 2021 17:00:15 +0100 Subject: [PATCH 2/2] Add tests for document root detection --- server/galaxyls/tests/unit/test_validation.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/server/galaxyls/tests/unit/test_validation.py b/server/galaxyls/tests/unit/test_validation.py index b406be8..0bd9bd0 100644 --- a/server/galaxyls/tests/unit/test_validation.py +++ b/server/galaxyls/tests/unit/test_validation.py @@ -1,6 +1,8 @@ import pytest from lxml import etree +from galaxyls.services.validation import DocumentValidator + from ...services.xsd.constants import TOOL_XSD_FILE from ...services.xsd.validation import GalaxyToolValidationService from .sample_data import ( @@ -62,3 +64,34 @@ def test_validate_macro_file_returns_diagnostics_when_syntax_error(self, xsd_sch actual = service.validate_document(xml_document) assert len(actual) == 1 + + +class TestDocumentValidatorClass: + @pytest.mark.parametrize( + "source, expected", + [ + ("", True), + (" ", True), + ("\n", True), + ("\n ", True), + (" \n ", True), + ("unexpected ", True), + (" unexpected ", True), + ("\nunexpected\n ", True), + ('', True), + ('\n', True), + ("", True), + ('\n', True), + ("", False), + (" ", False), + ("test", False), + ("", False), + ], + ) + def test_has_valid_root_returns_expected(self, source: str, expected: bool) -> None: + document = TestUtils.to_document(source) + validator = DocumentValidator() + + actual = validator.has_valid_root(document) + + assert actual == expected