mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
216 lines
7.5 KiB
Python
216 lines
7.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
sphinx.domains.javascript
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The JavaScript domain.
|
|
|
|
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
|
:license: BSD, see LICENSE for details.
|
|
"""
|
|
|
|
from sphinx import addnodes
|
|
from sphinx.domains import Domain, ObjType
|
|
from sphinx.locale import l_, _
|
|
from sphinx.directives import ObjectDescription
|
|
from sphinx.roles import XRefRole
|
|
from sphinx.domains.python import _pseudo_parse_arglist
|
|
from sphinx.util.nodes import make_refnode
|
|
from sphinx.util.docfields import Field, GroupedField, TypedField
|
|
|
|
|
|
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
|
|
|
|
#: what is displayed right before the documentation entry
|
|
display_prefix = None
|
|
|
|
def handle_signature(self, sig, signode):
|
|
sig = sig.strip()
|
|
if '(' in sig and sig[-1:] == ')':
|
|
prefix, arglist = sig.split('(', 1)
|
|
arglist = arglist[:-1].strip()
|
|
else:
|
|
prefix = sig
|
|
arglist = None
|
|
if '.' in prefix:
|
|
nameprefix, name = prefix.rsplit('.', 1)
|
|
else:
|
|
nameprefix = None
|
|
name = prefix
|
|
|
|
objectname = self.env.temp_data.get('js:object')
|
|
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
|
|
else:
|
|
# just a function or constructor
|
|
objectname = ''
|
|
fullname = name
|
|
|
|
signode['object'] = objectname
|
|
signode['fullname'] = fullname
|
|
|
|
if self.display_prefix:
|
|
signode += addnodes.desc_annotation(self.display_prefix,
|
|
self.display_prefix)
|
|
if nameprefix:
|
|
signode += addnodes.desc_addname(nameprefix + '.', nameprefix + '.')
|
|
signode += addnodes.desc_name(name, name)
|
|
if self.has_arguments:
|
|
if not arglist:
|
|
signode += addnodes.desc_parameterlist()
|
|
else:
|
|
_pseudo_parse_arglist(signode, arglist)
|
|
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.replace('$', '_S_'))
|
|
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 == 'class':
|
|
return _('%s() (class)') % name
|
|
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
|
|
|
|
doc_field_types = [
|
|
TypedField('arguments', label=l_('Arguments'),
|
|
names=('argument', 'arg', 'parameter', 'param'),
|
|
typerolename='func', typenames=('paramtype', 'type')),
|
|
GroupedField('errors', label=l_('Throws'), rolename='err',
|
|
names=('throws', ),
|
|
can_collapse=True),
|
|
Field('returnvalue', label=l_('Returns'), has_arg=False,
|
|
names=('returns', 'return')),
|
|
]
|
|
|
|
|
|
class JSConstructor(JSCallable):
|
|
"""Like a callable but with a different prefix"""
|
|
display_prefix = 'class '
|
|
|
|
|
|
class JSXRefRole(XRefRole):
|
|
def process_link(self, env, refnode, has_explicit_title, title, target):
|
|
# basically what sphinx.domains.python.PyXRefRole does
|
|
refnode['js:object'] = env.temp_data.get('js:object')
|
|
if not has_explicit_title:
|
|
title = title.lstrip('.')
|
|
target = target.lstrip('~')
|
|
if title[0:1] == '~':
|
|
title = title[1:]
|
|
dot = title.rfind('.')
|
|
if dot != -1:
|
|
title = title[dot+1:]
|
|
if target[0:1] == '.':
|
|
target = target[1:]
|
|
refnode['refspecific'] = True
|
|
return title, target
|
|
|
|
|
|
class JavaScriptDomain(Domain):
|
|
"""JavaScript language domain."""
|
|
name = 'js'
|
|
label = 'JavaScript'
|
|
# if you add a new object type make sure to edit JSObject.get_index_string
|
|
object_types = {
|
|
'function': ObjType(l_('function'), 'func'),
|
|
'class': ObjType(l_('class'), 'class'),
|
|
'data': ObjType(l_('data'), 'data'),
|
|
'attribute': ObjType(l_('attribute'), 'attr'),
|
|
}
|
|
directives = {
|
|
'function': JSCallable,
|
|
'class': JSConstructor,
|
|
'data': JSObject,
|
|
'attribute': JSObject,
|
|
}
|
|
roles = {
|
|
'func': JSXRefRole(fix_parens=True),
|
|
'class': JSXRefRole(fix_parens=True),
|
|
'data': 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, refname, type, docname, refname, 1
|