from__future__importannotationsimportreimporttypingfromdataclassesimportdataclassfromdataclassesimportfieldfromtypingimportAnyfrom.lspimportLocationiftyping.TYPE_CHECKING:fromtypingimportCallablefromtypingimportTypeVarT=TypeVar("T")JsonLoader=Callable[[str,type[T]],T]MYST_ROLE:re.Pattern=re.compile(r""" ([^\w`]|^\s*) # roles cannot be preceeded by letter chars (?P<role> { # roles start with a '{' (?P<name>[:\w+-]+)? # roles have a name }? # roles end with a '}' ) (?P<target> ` # targets begin with a '`' character ((?P<alias>[^<`>]*?)<)? # targets may specify an alias (?P<modifier>[!~])? # targets may have a modifier (?P<label>[^<`>]*)? # targets contain a label >? # labels end with a '>' when there's an alias `? # targets end with a '`' character )? """,re.VERBOSE,)"""A regular expression to detect and parse parial and complete roles.I'm not sure if there are offical names for the components of a role, but thelanguage server breaks a role down into a number of parts:: vvvvvv label v modifier(optional) vvvvvvvv target {c:function}`!malloc` ^^^^^^^^^^^^ role ^^^^^^^^^^ nameThe language server sometimes refers to the above as a "plain" role, in that therole's target contains just the label of the object it is linking to. However it'salso possible to define "aliased" roles, where the link text in the final documentis overriden, for example:: vvvvvvvvvvvvvvvvvvvvvvvv alias vvvvvv label v modifier (optional) vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv target {c:function}`used to allocate memory <~malloc>` ^^^^^^^^^^^^ role ^^^^^^^^^^ name"""RST_ROLE=re.compile(r""" ([^\w:]|^\s*) # roles cannot be preceeded by letter chars (?P<role> : # roles begin with a ':' character (?!:) # the next character cannot be a ':' ((?P<name>\w([:\w+-]*\w)?):?)? # roles have a name ) (?P<target> ` # targets begin with a '`' character ((?P<alias>[^<`>]*?)<)? # targets may specify an alias (?P<modifier>[!~])? # targets may have a modifier (?P<label>[^<`>]*)? # targets contain a label >? # labels end with a '>' when there's an alias `? # targets end with a '`' character )? """,re.VERBOSE,)"""A regular expression to detect and parse parial and complete roles.I'm not sure if there are offical names for the components of a role, but thelanguage server breaks a role down into a number of parts:: vvvvvv label v modifier(optional) vvvvvvvv target :c:function:`!malloc` ^^^^^^^^^^^^ role ^^^^^^^^^^ nameThe language server sometimes refers to the above as a "plain" role, in that therole's target contains just the label of the object it is linking to. However it'salso possible to define "aliased" roles, where the link text in the final documentis overriden, for example:: vvvvvvvvvvvvvvvvvvvvvvvv alias vvvvvv label v modifier (optional) vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv target :c:function:`used to allocate memory <~malloc>` ^^^^^^^^^^^^ role ^^^^^^^^^^ name"""RST_DEFAULT_ROLE=re.compile(r""" (?<![:`]) (?P<target> ` # targets begin with a '`' character ((?P<alias>[^<`>]*?)<)? # targets may specify an alias (?P<modifier>[!~])? # targets may have a modifier (?P<label>[^<`>]*)? # targets contain a label >? # labels end with a '>' when there's an alias `? # targets end with a '`' character ) """,re.VERBOSE,)"""A regular expression to detect and parse parial and complete "default" roles.A "default" role is the target part of a normal role - but without the ``:name:`` part."""
[docs]@dataclassclassRole:"""Represents a role."""
[docs]@dataclassclassTargetProvider:"""A target provider instance."""name:str"""The name of the provider."""kwargs:dict[str,Any]=field(default_factory=dict)"""Arguments to pass to the target provider."""
name:str"""The name of the role, as the user would type in an rst file."""implementation:str|None"""The dotted name of the role's implementation."""location:Location|None=field(default=None)"""The location of the role's implementation, if known."""target_providers:list[TargetProvider]=field(default_factory=list)"""The list of target providers that can be used with this role."""
[docs]defto_db(self,dumps:Callable[[Any],str])->tuple[str,str|None,str|None,str|None]:"""Convert this role to its database representation."""iflen(self.target_providers)>0:providers=dumps(self.target_providers)else:providers=Nonelocation=dumps(self.location)ifself.locationisnotNoneelseNonereturn(self.name,self.implementation,location,providers)
[docs]@classmethoddeffrom_db(cls,load_as:JsonLoader,name:str,implementation:str|None,location:str|None,providers:str|None,)->Role:"""Create a role from its database representation."""loc=load_as(location,Location)iflocationisnotNoneelseNonetarget_providers=(load_as(providers,list[Role.TargetProvider])ifprovidersisnotNoneelse[])returncls(name=name,implementation=implementation,location=loc,target_providers=target_providers,)