diff --git a/autoapi/mappers/dotnet.py b/autoapi/mappers/dotnet.py index df5026c..2654600 100644 --- a/autoapi/mappers/dotnet.py +++ b/autoapi/mappers/dotnet.py @@ -35,12 +35,12 @@ DOC_COMMENT_PARAM_PATTERN = re.compile( # Comment member identities # From: https://msdn.microsoft.com/en-us/library/vstudio/fsbx0t7x(v=VS.100).aspx DOC_COMMENT_IDENTITIES = { - 'N': 'ns', - 'T': 'ref', # can be any type (class, delegate, enum, etc), so use ref - 'F': 'field', - 'P': 'prop', - 'M': 'meth', - 'E': 'event', + 'N': 'dn:ns', + 'T': 'any', # can be any type (class, delegate, enum, etc), so use any + 'F': 'dn:field', + 'P': 'dn:prop', + 'M': 'dn:meth', + 'E': 'dn:event', } @@ -378,24 +378,31 @@ class DotNetPythonMapper(PythonMapperBase): found = DOC_COMMENT_SEE_PATTERN.search(text) if found is None: break - ref = found.group('attr_value') - reftype = 'ref' + ref = (found.group('attr_value') + .replace('<', '\<') + .replace('`', '\`')) + + reftype = 'any' replacement = '' # Given the pattern of `\w:\w+`, inspect first letter of # reference for identity type if ref[1] == ':' and ref[0] in DOC_COMMENT_IDENTITIES: reftype = DOC_COMMENT_IDENTITIES[ref[:1]] ref = ref[2:] - replacement = ':dn:{reftype}:`{ref}`'.format( + replacement = ':{reftype}:`{ref}`'.format( reftype=reftype, ref=ref) elif ref[:2] == '!:': replacement = ref[2:] else: - replacement = ':dn:ref:`{ref}`'.format(ref=ref) + replacement = ':any:`{ref}`'.format(ref=ref) + + # Escape following text + text_end = text[found.end():] + text_start = text[:found.start()] + text_end = re.sub(r'^(\S)', r'\\\1', text_end) + text_start = re.sub(r'(\S)$', r'\1 ', text_start) - text = ''.join([text[:found.start()], - replacement, - text[found.end():]]) + text = ''.join([text_start, replacement, text_end]) text = DOC_COMMENT_PARAM_PATTERN.sub( '``\g``', text) except TypeError: diff --git a/tests/test_domains.py b/tests/test_domains.py index e3d42c7..5111941 100644 --- a/tests/test_domains.py +++ b/tests/test_domains.py @@ -95,7 +95,7 @@ class DomainTests(unittest.TestCase): '''XML doc comment parsing''' ret = dotnet.DotNetPythonMapper.transform_doc_comments( 'This is an example comment ') - self.assertEqual(ret, 'This is an example comment :dn:ref:`FOO`') + self.assertEqual(ret, 'This is an example comment :any:`FOO`') ret = dotnet.DotNetPythonMapper.transform_doc_comments( 'This is an example comment ') @@ -116,3 +116,13 @@ class DomainTests(unittest.TestCase): ret = dotnet.DotNetPythonMapper.transform_doc_comments( 'This is an example comment ') self.assertEqual(ret, 'This is an example comment ``FOO``') + + def test_xml_transform_escape(self): + """XML transform escaping""" + ret = dotnet.DotNetPythonMapper.transform_doc_comments( + 'Foo Bar') + self.assertEqual(ret, 'Foo :any:`Foo\\`1` Bar') + + ret = dotnet.DotNetPythonMapper.transform_doc_comments( + 'No space beforeor after') + self.assertEqual(ret, 'No space before :dn:meth:`Foo\\`1`\\or after') diff --git a/tests/test_objects.py b/tests/test_objects.py index 41c5167..ee72e1a 100644 --- a/tests/test_objects.py +++ b/tests/test_objects.py @@ -5,10 +5,13 @@ import os import unittest +from jinja2 import Environment, FileSystemLoader + from autoapi.mappers import dotnet +from autoapi.settings import TEMPLATE_DIR -class NamespaceTests(unittest.TestCase): +class DotNetTests(unittest.TestCase): def test_type(self): '''Test types of some of the objects''' @@ -112,3 +115,16 @@ class NamespaceTests(unittest.TestCase): self.assertEqual(cls.pathname, os.path.join('Foo', 'Bar')) cls = dotnet.DotNetClass({'id': u'Ащщ.юИфк'}) self.assertEqual(cls.pathname, os.path.join('Ashchshch', 'iuIfk')) + + def test_rendered_class_escaping(self): + """Rendered class escaping""" + jinja_env = Environment( + loader=FileSystemLoader([TEMPLATE_DIR]), + ) + cls = dotnet.DotNetClass( + { + 'id': 'Foo.Bar`1', + 'inheritance': ['Foo.Baz`1'], + }, + jinja_env=jinja_env) + self.assertIn('* :dn:cls:`Foo.Baz\\`1`\n', cls.render())