1818from sphinx .util import logging
1919from sphinx .util .nodes import make_refnode
2020
21- from .schema import Schema , Object
21+ from .schema import Schema , Object , RefType , Indexer , LiteralIndexer
2222from .directives import AnyDirective
2323from .roles import AnyRole
2424from .indices import AnyIndex
@@ -49,9 +49,9 @@ class AnyDomain(Domain):
4949 roles : dict [str , RoleFunction ] = {}
5050 #: A list of Index subclasses
5151 indices : list [type [AnyIndex ]] = []
52- #: AnyDomain specific: type -> index class
52+ #: AnyDomain specific: reftype -> index class
5353 _indices_for_reftype : dict [str , type [AnyIndex ]] = {}
54- #: AnyDomain specific: type -> Schema instance
54+ #: AnyDomain specific: objtype -> Schema instance
5555 _schemas : dict [str , Schema ] = {}
5656
5757 initial_data : dict [str , Any ] = {
@@ -120,7 +120,7 @@ def resolve_xref(
120120 logger .debug ('[any] resolveing xref of %s' , (typ , target ))
121121
122122 reftype = RefType .parse (typ )
123- objtype , objfield , objidx = reftype .objtype , reftype .field , reftype .index
123+ objtype , objfield , objidx = reftype .objtype , reftype .field , reftype .indexer
124124 objids = set ()
125125 if objidx :
126126 pass # no need to lookup objds
@@ -142,10 +142,7 @@ def resolve_xref(
142142 if len (objids ) > 1 or objidx is not None :
143143 # Mulitple objects found or reference index explicitly,
144144 # create link to indices page.
145- (
146- todocname ,
147- anchor ,
148- ) = self ._get_index_anchor (typ , target )
145+ (todocname , anchor ) = self ._get_index_anchor (typ , target )
149146 if not has_explicit_title :
150147 newtitle = schema .render_ambiguous_reference (title )
151148 logger .debug (
@@ -181,43 +178,51 @@ def add_schema(cls, schema: Schema) -> None:
181178 # Add to schemas dict
182179 cls ._schemas [schema .objtype ] = schema
183180
184- # Generates reftypes for all referenceable fields
185- # For later use when generating roles and indices.
186- reftypes = [str (RefType (schema .objtype , None , None ))]
187- for name , field in schema .fields (all = False ):
188- if not field .ref :
189- continue
190-
191- # Field is unique , use ``:objtype.field:`` to reference.
192- if field .uniq :
193- reftype = str (RefType (schema .objtype , name , None ))
194- reftypes .append (reftype )
195- continue
196-
197- for name , field in schema .fields (all = False ):
198- # Field is not unique, link to index page.
199- for indexer in field .indexers :
200- reftype = str (RefType (schema .objtype , name , indexer .name ))
201- reftypes .append (reftype )
202-
203- # FIXME: name and content can not be index now
204- index = AnyIndex .derive (schema , name , indexer )
205- cls .indices .append (index )
206- cls ._indices_for_reftype [reftype ] = index
207-
208- for reftype in reftypes :
209- field = RefType .parse (reftype ).field
210- # Create role for referencing object by field
211- cls .roles [reftype ] = AnyRole .derive (schema , field )(
181+ def mkrole (reftype : RefType ):
182+ """Create and register role for referencing object."""
183+ role = AnyRole (
212184 # Emit warning when missing reference (node['refwarn'] = True)
213185 warn_dangling = True ,
214186 # Inner node (contnode) would be replaced in resolve_xref method,
215187 # so fix its class.
216188 innernodeclass = literal ,
217189 )
190+ cls .roles [str (reftype )] = role
191+ logger .debug (f'[any] make role { reftype } → { type (role )} ' )
192+
193+ def mkindex (reftype : RefType , indexer : Indexer ):
194+ """Create and register object index."""
195+ index = AnyIndex .derive (schema , reftype , indexer )
196+ cls .indices .append (index )
197+ cls ._indices_for_reftype [str (reftype )] = index
198+ logger .debug (f'[any] make index { reftype } → { type (index )} ' )
199+
200+ # Create all-in-one role and index (do not distinguish reference fields).
201+ reftypes = [RefType (schema .objtype )]
202+ mkrole (reftypes [0 ])
203+ mkindex (reftypes [0 ], LiteralIndexer ())
204+
205+ # Create {field,indexer}-specificed role and index.
206+ for name , field in schema .fields ():
207+ if field .ref :
208+ reftype = RefType (schema .objtype , field = name )
209+ reftypes .append (reftype )
210+ mkrole (reftype ) # create a role to reference object(s)
211+ # Create a fallback indexer, for possible ambiguous reference
212+ # (if field is not unique).
213+ mkindex (reftype , LiteralIndexer ())
214+
215+ for indexer in field .indexers :
216+ reftype = RefType (schema .objtype , field = name , indexer = indexer .name )
217+ reftypes .append (reftype )
218+ # Create role and index for reference objects by index.
219+ mkrole (reftype )
220+ mkindex (reftype , indexer )
218221
219222 # TODO: document
220- cls .object_types [schema .objtype ] = ObjType (schema .objtype , * reftypes )
223+ cls .object_types [schema .objtype ] = ObjType (
224+ schema .objtype , * [str (x ) for x in reftypes ]
225+ )
221226 # Generates directive for creating object.
222227 cls .directives [schema .objtype ] = AnyDirective .derive (schema )
223228
@@ -238,42 +243,9 @@ def warn_missing_reference(
238243 if domain and domain .name != AnyDomain .name :
239244 return None
240245
241- objtype = RefType .parse (node ['reftype' ]). objtype
246+ reftype = RefType .parse (node ['reftype' ])
242247 target = node ['reftarget' ]
243248
244- msg = f'undefined { objtype } : { target } '
245- logger .warning (msg , location = node , type = 'ref' , subtype = objtype )
249+ msg = f'undefined reftype { reftype } : { target } '
250+ logger .warning (msg , location = node , type = 'ref' , subtype = reftype . objtype )
246251 return True
247-
248-
249- class RefType (object ):
250- """Reference type, used as role name and node['reftype'] and
251- and *typ* argument of :meth:`AnyDomain.resolve_xref` method."""
252-
253- #: :attr:`ObjType.lname`
254- objtype : str
255- #: :attr:`.schema.Field.name`
256- field : str | None
257- #: :attr:`.schema.Indexer.name`
258- index : str | None
259-
260- def __init__ (self , objtype : str , field : str | None , index : str | None ):
261- self .objtype = objtype
262- self .field = field
263- self .index = index
264-
265- @classmethod
266- def parse (cls , reftype : str ):
267- v = reftype .split ('.' , maxsplit = 2 )
268- objtype = v [0 ]
269- field = v [1 ] if len (v ) > 1 else None
270- index = v [2 ][3 :] if len (v ) > 2 else None # skip "by-"
271- return cls (objtype , field , index )
272-
273- def __str__ (self ):
274- s = self .objtype
275- if self .field is not None :
276- s += '.' + self .field
277- if self .index is not None :
278- s += '.' + 'by-' + self .index
279- return s
0 commit comments