Commits

Anonymous committed c7d5955

JavaScript domain supports now references, also :class:`JSObject`s are now indexed.

Comments (0)

Files changed (1)

sphinx/domains/javascript.py

 from sphinx.directives import ObjectDescription
 from sphinx.domains.python import py_paramlist_re as js_paramlist_re
 from sphinx.roles import XRefRole
+from sphinx.util.nodes import make_refnode
 
 js_sig_re = re.compile(
     r'''([^ .]+\.)? # object name
         ([^ .]+\s*) # name
-        \((.*)\)$ # arguments
+        \((.*)\)$   # arguments
 ''', re.VERBOSE)
 
 class JSObject(ObjectDescription):
     """
     Description of a JavaScript object.
     """
+    #: If set to ``True`` this object is callable and a `desc_parameterlist` is
+    #: added
     has_arguments = False
 
     def handle_signature(self, sig, signode):
         nameprefix, name, arglist = match.groups()
 
         objectname = self.env.temp_data.get('js:object')
-        if objectname and nameprefix:
-            # someone documenting the method of an attribute of the current
-            # object? shouldn't happen but who knows...
-            fullname = objectname + '.' + nameprefix + name
+        if nameprefix:
+            if objectname:
+                # someone documenting the method of an attribute of the current
+                # object? shouldn't happen but who knows...
+                nameprefix = objectname + '.' + nameprefix
+            fullname = nameprefix + name
         elif objectname:
             fullname = objectname + '.' + name
-        elif nameprefix:
-            fullname = nameprefix + '.' + name
         else:
             # just a function or constructor
             objectname = ''
         signode['object'] = objectname
         signode['fullname'] = fullname
 
+        signode += addnodes.desc_addname(nameprefix, nameprefix)
         signode += addnodes.desc_name(name, name)
         if self.has_arguments:
             signode += addnodes.desc_parameterlist()
             raise ValueError()
         return fullname, nameprefix
 
+    def add_target_and_index(self, name_obj, sig, signode):
+        objectname = self.options.get(
+            'object', self.env.temp_data.get('js:object'))
+        fullname = name_obj[0]
+        if fullname not in self.state.document.ids:
+            signode['names'].append(fullname)
+            signode['ids'].append(fullname)
+            signode['first'] = not self.names
+            self.state.document.note_explicit_target(signode)
+            objects = self.env.domaindata['js']['objects']
+            if fullname in objects:
+                self.env.warn(
+                    self.env.docname,
+                    'duplicate object description of %s, ' % fullname +
+                    'other instance in ' +
+                    self.env.doc2path(objects[fullname][0]),
+                    self.lineno)
+            objects[fullname] = self.env.docname, self.objtype
+
+        indextext = self.get_index_text(objectname, name_obj)
+        if indextext:
+            self.indexnode['entries'].append(('single', indextext,
+                                              fullname, fullname))
+
+    def get_index_text(self, objectname, name_obj):
+        name, obj = name_obj
+        if self.objtype == 'function':
+            if not obj:
+                return _('%s() (built-in function)') % name
+            return _('%s() (%s method)') % (name, obj)
+        elif self.objtype == 'data':
+            return _('%s (global variable or constant)') % name
+        elif self.objtype == 'attribute':
+            return _('%s (%s attribute)') % (name, obj)
+        return ''
+
 class JSCallable(JSObject):
     """Description of a JavaScript function, method or constructor."""
     has_arguments = True
     roles = {
         'func': JSXRefRole(fix_parens=True),
         'data': JSXRefRole(),
-        'attr': JSXRefRole()
+        'attr': JSXRefRole(),
     }
+    initial_data = {
+        'objects': {}, # fullname -> docname, objtype
+    }
+
+    def clear_doc(self, docname):
+        for fullname, (fn, _) in self.data['objects'].items():
+            if fn == docname:
+                del self.data['objects'][fullname]
+
+    def find_obj(self, env, obj, name, typ, searchorder=0):
+        if name[-2:] == '()':
+            name = name[:-2]
+        objects = self.data['objects']
+        newname = None
+        if searchorder == 1:
+            if obj and obj + '.' + name in objects:
+                newname = obj + '.' + name
+            else:
+                newname = name
+        else:
+            if name in objects:
+                newname = name
+            elif obj and obj + '.' + name in objects:
+                newname = obj + '.' + name
+        return newname, objects.get(newname)
+
+    def resolve_xref(self, env, fromdocname, builder, typ, target, node,
+                     contnode):
+        objectname = node.get('js:object')
+        searchorder = node.hasattr('refspecific') and 1 or 0
+        name, obj = self.find_obj(env, objectname, target, typ, searchorder)
+        if not obj:
+            return None
+        return make_refnode(builder, fromdocname, obj[0], name, contnode, name)
+
+    def get_objects(self):
+        for refname, (docname, type) in self.data['objects'].iteritems():
+            yield refname, type, docname, refname, 1