from abc import ABC, abstractmethod from enum import IntEnum, auto from textwrap import dedent from types import SimpleNamespace from typing import Callable, Match, Union, List, Dict import re from .types import Converter class Directive: def __init__( self, pattern: str, replacement: Union[str, Callable[[Match], str]], name: Union[str, None] = None, flags: int = 0 ): self.pattern = pattern self.replacement = replacement self.name = name self.flags = flags # https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#cross-referencing-python-objects SPHINX_CROSS_REF_PYTHON = ( 'mod', 'func', 'data', 'const', 'class', 'meth', 'attr', 'exc', 'obj' ) # https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#cross-referencing-c-constructs SPHINX_CROSS_REF_C = ( 'member', 'data', 'func', 'macro', 'struct', 'union', 'enum', 'enumerator', 'type' ) # https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#cross-referencing SPHINX_CROSS_REF_CPP = ( 'any', 'class', 'struct', 'func', 'member', 'var', 'type', 'concept', 'enum', 'enumerator' ) # https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#the-javascript-domain SPHINX_CROSS_REF_JS = ( 'mod', 'func', 'meth', 'class', 'data', 'attr' ) # https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#the-restructuredtext-domain SPHINX_CROSS_REF_RST = ( 'dir', 'role' ) # https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html SPHINX_CROSS_REF_OTHER = ( 'any', # https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#cross-referencing-other-items-of-interest 'envvar', 'token', 'keyword', 'option', 'term', ) SPHINX_PARAM = ( 'param', 'parameter', 'arg', 'argument', 'key', 'keyword' ) SPHINX_RULES: List[Directive] = [ Directive( pattern=r':c:({}):`\.?(?P[^`]+?)`'.format('|'.join(SPHINX_CROSS_REF_C)), replacement=r'`\g`' ), Directive( pattern=r':cpp:({}):`\.?(?P[^`]+?)`'.format('|'.join(SPHINX_CROSS_REF_CPP)), replacement=r'`\g`' ), Directive( pattern=r':js:({}):`\.?(?P[^`]+?)`'.format('|'.join(SPHINX_CROSS_REF_JS)), replacement=r'`\g`' ), Directive( pattern=r'(:py)?:({}):`\.?(?P[^`]+?)`'.format('|'.join(SPHINX_CROSS_REF_PYTHON)), replacement=r'`\g`' ), Directive( pattern=r'(:rst)?:({}):`\.?(?P[^`]+?)`'.format('|'.join(SPHINX_CROSS_REF_RST)), replacement=r'`\g`' ), Directive( pattern=r':({}):`\.?(?P[^`]+?)`'.format('|'.join(SPHINX_CROSS_REF_OTHER)), replacement=r'`\g`' ), Directive( pattern=r'^\s*:({}) (?P\S+) (?P\S+):'.format('|'.join(SPHINX_PARAM)), replacement=r'- `\g` (`\g`):', flags=re.MULTILINE ), Directive( pattern=r'^\s*:({}) (?P\S+): (?P.*)(\n|\r\n?):type \2: (?P.*)$'.format('|'.join(SPHINX_PARAM)), replacement=r'- `\g` (\g): \g', flags=re.MULTILINE ), Directive( pattern=r'^\s*:({}) (?P\S+):'.format('|'.join(SPHINX_PARAM)), replacement=r'- `\g`:', flags=re.MULTILINE ), Directive( pattern=r'^\s*:type (?P\S+):', replacement=r' . Type: `\g`:', flags=re.MULTILINE ), Directive( pattern=r'^\s*:(return|returns):', replacement=r'- returns:', flags=re.MULTILINE ), Directive( pattern=r'^\s*:rtype: (?P\S+)', replacement=r'- return type: `\g`', flags=re.MULTILINE ), Directive( pattern=r'^\s*:(raises|raise|except|exception) (?P\S+):', replacement=r'- raises `\g`:', flags=re.MULTILINE ), ] class Admonition: def __init__(self, name: str, label: str, icon: str = ''): self.name = name self.label = label self.icon = icon @property def block_markdown(self): return f'{self.icon} **{self.label}**' @property def inline_markdown(self): return self.block_markdown + ':' ADMONITIONS = [ Admonition( name='caution', label='Caution', icon='⚠️ ' ), Admonition( name='attention', label='Attention', icon='⚠️ ' ), Admonition( name='danger', label='Danger', icon='⚠️ ' ), Admonition( name='hint', label='Hint', icon='🛈' ), Admonition( name='important', label='Important', icon='⚠️ ' ), Admonition( name='note', label='Note', icon='🛈' ), Admonition( name='tip', label='Tip', icon='🛈' ), Admonition( name='warning', label='Warning', icon='⚠️ ' ) ] ADMONITION_DIRECTIVES: List[Directive] = [ # https://docutils.sourceforge.io/docs/ref/rst/directives.html#admonitions Directive( pattern=rf'\.\. {admonition.name}::', replacement=admonition.inline_markdown ) for admonition in ADMONITIONS ] RST_DIRECTIVES: List[Directive] = [ Directive( pattern=r'\.\. versionchanged:: (?P\S+)(?P$|\n)', replacement=r'*Changed in \g*\g' ), Directive( pattern=r'\.\. versionadded:: (?P\S+)(?P$|\n)', replacement=r'*Added in \g*\g' ), Directive( pattern=r'\.\. deprecated:: (?P\S+)(?P$|\n)', replacement=r'*Deprecated since \g*\g' ), *ADMONITION_DIRECTIVES, Directive( pattern=r'\.\. seealso::(?P.*)(?P$|\n)', replacement=r'*See also*\g\g' ), Directive( pattern=r':ref:`(?P