diff --git a/sphinx/domains/javascript.py b/sphinx/domains/javascript.py index 8f618a70c..d9312eee5 100644 --- a/sphinx/domains/javascript.py +++ b/sphinx/domains/javascript.py @@ -16,17 +16,20 @@ from sphinx.locale import l_, _ 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): @@ -36,14 +39,14 @@ class JSObject(ObjectDescription): 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 = '' @@ -52,6 +55,7 @@ class JSObject(ObjectDescription): 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() @@ -78,6 +82,42 @@ class JSObject(ObjectDescription): 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 @@ -116,5 +156,43 @@ class JavaScriptDomain(Domain): 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