[FIX] doc: handle unknown browser globals better

Before this, if a new global was added to JS code (module toplevel,
function bodies are not considered) it would blow up when attempting
to resolve variable refs & uses.

Make the toplevel scope a defaultdict such that if e.g. a "foo" is
looked up in a module but not a local variable of that module it's
assumed to be an UnknownNS object (from which further UnknownNS can be
deref'd).
This commit is contained in:
Xavier Morel
2017-10-30 16:16:41 +01:00
parent 9417afa4f6
commit e8dc72fd69
+28 -12
View File
@@ -156,13 +156,23 @@ window = jsdoc.UnknownNS({
'doc': '<window>',
'name': 'window',
})
BASE_SCOPE = {
class BaseScope(collections.defaultdict):
""" The base scope assumes anything it's asked for is just an unknown
(global) namespace of some sort. Can hold a bunch of predefined params but
avoids the variables inference system blowing up when new (browser)
globals get used in module bodies.
"""
def __missing__(self, key):
it = jsdoc.UnknownNS({
'name': key,
'doc': u'<%s>' % key,
})
self[key] = it
return it
BASE_SCOPE = BaseScope(None, {
'_': jsdoc.UnknownNS({'doc': u'<underscore.js>', 'name': u'_'}),
'$': jq, 'jQuery': jq,
'nv': jsdoc.UnknownNS({
'doc': u'<nvd3>',
'name': u'nv',
}),
'window': window,
'document': window.get_property('document'),
'Date': jsdoc.ClassDoc({
@@ -188,8 +198,8 @@ BASE_SCOPE = {
('name', jsdoc.PropertyDoc({'name': u'csrf_token', 'type': u'{String}'})),
]
}),
'undefined': jsdoc.LiteralDoc({'name': u'undefined', 'value': None})
}
'undefined': jsdoc.LiteralDoc({'name': u'undefined', 'value': None}),
})
class Scope(object):
"""
@@ -198,20 +208,26 @@ class Scope(object):
have the final Foo extending itself...
"""
def __init__(self, mapping):
self._namemap = {}
self._namemap = self._empty(mapping)
self._targets = []
for k, v in mapping.items():
self[k] = v
@staticmethod
def _empty(mapping):
m = mapping.copy()
m.clear()
return m
def __setitem__(self, k, v):
self._namemap[k] = len(self._targets)
self._targets.append(v)
def freeze(self):
return {
k: self._targets[v]
for k, v in self._namemap.items()
}
d = self._empty(self._namemap)
for k, v in self._namemap.items():
d[k] = self._targets[v]
return d
class ModuleExtractor(Visitor):
def __init__(self, module, requirefunc):